This tutorial will show you how to create a CLI command to print the endpoints found by the reactive forwarding application from the Application tutorial. After completing this tutorial, you will understand:

Offering services to other modules

If you want your module to be able to provide services to other modules, you should define a service interface and have your module class implement it.

1. Define a service interface.

We start by defining a new interface for the service in the same location as our application (~/onos-next/apps/ifwd/src/main/java/org/onlab/onos/ifwd/):

package org.onlab.onos.ifwd;

import java.util.Map;
import org.onlab.onos.net.HostId;

/**
 * A demonstrative service for the intent reactive forwarding application to
 * export
 */
public interface ForwardingMapService {

    /**
     * Get the endpoints of the host-to-host intents that were installed
     *
     * @return maps of source to destination
     */
    public Map<HostId, HostId> getEndPoints();

}

2. Import the service interface.

Next, we implement our service in IntentReactiveForwarding. We also indicate to Karaf that the application exports a service, using the the Felix SCR annotation @Service:

@Component(immediate = true)
@Service
public class IntentReactiveForwarding implements ForwardingMapService {

	private final Logger log = getLogger(getClass());

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected CoreService coreService;

    // ...<snip>...
 
    // Install a rule forwarding the packet to the specified port.
    private void setUpConnectivity(PacketContext context, HostId srcId, HostId dstId) {
        TrafficSelector selector = DefaultTrafficSelector.builder().build();
        TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
        HostToHostIntent intent = new HostToHostIntent(appId, srcId, dstId,
                                                       selector, treatment);
        intentService.submit(intent);
    }
 
    // the new service method, to be filled out
    @Override
    public Map<HostId, HostId> getEndPoints() {
        return null;
    }
}


Although we won't be using it here in this manner, the @Service annotation enables another class to reference the service through the @Reference annotation:

@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ForwardingMapService fwdMapService;

3. Implement the service.

We can now define the new method. We add a new Map, endPoints, to IntentReactiveForwardingThe map is populated when the ReactivePacketProcessor's process() method finds endpoints known by the HostService.

@Component(immediate = true)
@Service
public class IntentReactiveForwarding implements ForwardingMapService {

    // ...<snip>...
    private ApplicationId appId;

    // Map for storing found endpoints, for our service. It is protected
    // so that process() can access it.
    protected final HashMap<HostId, HostId> endPoints = new HashMap<>();

    // ...<snip>...
    /**
     * Packet processor responsible for forwarding packets along their paths.
     */
    private class ReactivePacketProcessor implements PacketProcessor {

        @Override
        public void process(PacketContext context) {
            // Stop processing if the packet has been handled, since we
            // can't do any more to it.
            if (context.isHandled()) {
                return;
            }

            InboundPacket pkt = context.inPacket();
            Ethernet ethPkt = pkt.parsed();

            HostId srcId = HostId.hostId(ethPkt.getSourceMAC());
            HostId dstId = HostId.hostId(ethPkt.getDestinationMAC());
            
            // Do we know who this is for? If not, flood and bail.
            Host dst = hostService.getHost(dstId);
            if (dst == null) {
                flood(context);
                return;
            }
            // Add found endpoints to map.
            endPoints.put(srcId, dstId);

            // Otherwise forward and be done with it.
            setUpConnectivity(context, srcId, dstId);
            forwardPacketToDst(context, dst);
        }
    }

    // ...<snip>...

    @Override
    public Map<HostId, HostId> getEndPoints() {
        // Return our map as a read-only structure.
        return Collections.unmodifiableMap(endPoints);
    }
}

Creating a command 

Next, we create a CLI command to use this new service.