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:
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.
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(); } |
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; |
We can now define the new method. We add a new Map, endPoints
, to IntentReactiveForwarding
. The 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); } } |
Next, we create a CLI command to use this new service.