Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
onos> create-network test2
Created network test2    
onos> add-host test2 00:00:00:00:00:01/-1
Added host 00:00:00:00:00:01/-1 to testtest2   
onos> add-host test2 00:00:00:00:00:02/-1
Added host 00:00:00:00:00:02/-1 to testtest2
onos> list-networks 
test2
	00:00:00:00:00:01/-1
	00:00:00:00:00:02/-1
onos> intents
id=0x0, state=INSTALLED, type=HostToHostIntent, appId=org.onos.byon
    constraints=[LinkTypeConstraint{inclusive=false, types=[OPTICAL]}]

...

Next, let's recompile your application and push it to the ONOS cluster. You should now be able to create, update, and delete networks from any node, and your distributed store will the application running on all instances in sync. Open a few terminals and test this on the different instances. 

Lab 6: Network Events

 

In order to be able to communicate between ONOS instances we are going to make use of events. Components in ONOS can use events to asynchronously notify other components when their state has changed. We will demonstrate how this can be done by creating a new event type, NetworkEvent, to notify listeners when a virtual network has been updated. These events will be fired by the distributed store and caught forwarded by the manager to listeners in the peer ONOS instance. At this point the peer manager will notify any local listeners of the network event. 

Ok so letLet's start by adding a NetworkEvent class.:

Code Block
languagejava
public class NetworkEvent extends AbstractEvent<NetworkEvent.Type, String> {

    enum Type {
        NETWORK_ADDED,
        NETWORK_REMOVED,
        NETWORK_UPDATED
    }

    public NetworkEvent(Type type, String subject) {
        super(type, subject);
    }

}

...

And since we changed the interface of the Store we will have to add something to the implementationsimplementation, namely SimpleNetworkStoreDistributedNetworkStore. This abstract class is used to define the methods for posting event to its delegates.

Code Block
public class SimpleNetworkStoreDistributedNetworkStore extends AbstractStore<NetworkEvent, NetworkStoreDelegate>

...

Code Block
languagejava
    /**
     * Register a listener for network events.
     *
     * @param listener listener
     */
    void addListener(NetworkListener listener);

    /**
     * Unregister a listener for network events.
     *
     * @param listener listener
     */
    void removeListener(NetworkListener listener);

Now since the store is making use of the delegates, we need to make the stores' implementation delegate-aware by notifying the delegates when network elements are added or removed. For example, the putNetwork method no notifies the delegate that a new network has been added.

The ConsistentMap will already generate notifications when updates are made locally and remotely, so we can mostly leverage that feature to regenerate our events.

To do this, we will need to create a MapEventListener<String, Set<HostId>> class in the DistributedNetworkStore.

Code Block
private class InternalListener implements MapEventListener<String, Set<HostId>> {
    
Code Block
languagejava
    @Override
    public void putNetwork(String networkevent(MapEvent<String, Set<HostId>> mapEvent) {
        final intentsPerNet.putIfAbsent(network, Sets.<Intent>newHashSet())NetworkEvent.Type type;
        ifswitch (networks.putIfAbsent(network, Sets.<HostId>newHashSetmapEvent.type()) == null) { {
            case INSERT:
            notifyDelegate(new NetworkEvent(    type = NETWORK_ADDED, network));
        }
       }

Try to change the implementation of the remaining methods to notify the delegates as well.

Alright so now that the stores emit events the managers should be made to receive them. For this we are going to have to add a reference on the EventDeliveryService an AbstractListenerRegistry to keep track of listeners and NetworkStoreDelegate as shown in the code snippet below.

Code Block
languagejava
	@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
	protected EventDeliveryService eventDispatcher;

 break;
      private   ApplicationId appId;
  case UPDATE:
 private final AbstractListenerRegistry<NetworkEvent, NetworkListener>
            listenerRegistrytype = new AbstractListenerRegistry<>()NETWORK_UPDATED;

        private final NetworkStoreDelegate delegate = new InternalStoreDelegate();

Then we need to add a couple lines in the activate in order to register our Event type for our listeners and set our delegate.

Code Block
 eventDispatcher.addSink(NetworkEvent.class, listenerRegistry) break;
 store.setDelegate(delegate);
       

and vice versa deactivate

Code Block
eventDispatcher.removeSink(NetworkEvent.class);
store.unsetDelegate(delegate);

Finally add the methods to add listeners and dispatch events coming from the store:

Code Block
languagejava
    case @OverrideREMOVE:
     public void addListener(NetworkListener listener) {
   default:
     listenerRegistry.addListener(listener);
    }

    @Override
   type public void removeListener(NetworkListener listener) {
= NETWORK_REMOVED;
           listenerRegistry.removeListener(listener);
    }

    private class InternalStoreDelegate implements NetworkStoreDelegate { break;
        @Override}
        public void notify(NetworkEvent event) {
            eventDispatcher.post(event);
    notifyDelegate(new NetworkEvent(type, mapEvent.key()));
    }
    }

To test this you We will need to complete the extra credit section (big grin).

Part 5: Distributed Store

So we can finally start implementing DistributedStore. To this start by disabling your SimpleNetworkStore:

Code Block
@Component(immediate = false, enabled = false)
@Service
public class SimpleNetworkStore

 

Then copy the contents of the SimpleNetworkStore to a new file called DistributedNetworkStore (surprise!). First start by striping all the events that you generate in the methods of the store. These will be generated by the Remote Listener. Start by adding the Remote Listener to the distributed store class as an internal class.

Code Block
languagejava
 private class RemoteListener extends EntryAdapter<String, Set<HostId>> {
        @Override
        public void entryAdded(EntryEvent<String, Set<HostId>> event) {
            notifyDelegate(new NetworkEvent(NETWORK_ADDED, event.getKey()));
        }

        @Override
        public void entryUpdated(EntryEvent<String, Set<HostId>> event) {
            notifyDelegate(new NetworkEvent(NETWORK_UPDATED, event.getKey()));
        }

        @Override
        public void entryRemoved(EntryEvent<String, Set<HostId>> event) {
            notifyDelegate(new NetworkEvent(NETWORK_REMOVED, event.getKey()));
        }
    }

Replace your maps, activate and deactivate methods by the following code snippet:

Code Block
languagejava
    private SMap<String, Set<HostId>> networks;
    private SMap<String, Set<Intent>> intentsPerNet;

    private String listenerId;

    @Activate
    public void activate() {
        super.activate();

        networks = new SMap<>(theInstance.<byte[], byte[]>getMap("byon-networks"), this.serializer);
        intentsPerNet = new SMap<>(theInstance.<byte[], byte[]>getMap("byon-network-intents"), this.serializer);
        EntryListener<String, Set<HostId>> listener = new RemoteListener();
        listenerId = networks.addEntryListener(listener, true);
        log.info("Started");
    }

    @Deactivate
    public void deactivate() {
        networks.removeEntryListener(listenerId);
        log.info("Stopped");
    }


 

Verify your implementation

You can do this by recompiling, deploying, and launching another console to a second onos instance:

Code Block
distributed@mininet-vm:~/ $ onos $OC2

When you add and remove networks and/or hosts you should see this being reflected on the other ONOS instances.

 

Part 6: Event Listener

 

We can create the byon application using a Maven archetype:

 

 

 

Code Block
distributed@mininet-vm:~/onos-byon/ $ mvn archetype:generate -DarchetypeGroupId=org.onosproject  -DarchetypeArtifactId=onos-bundle-archetype -DarchetypeVersion=1.0.0p1

 

Make sure you are in the onos-byon directory

When prompted for the groupId, enter org.onos.byon. When prompted for the artifactId, enter byon-monitor. The remaining fields can the default values that maven suggests.

This will create a directory called byon-monitor that contains a pom.xml file as well as some starter Java files. Let's delete the "test" subtree for now.<w

Info

IntelliJ should detect the new module and ask you to import the changes but if it does not then right click on the top-level project, select Maven followed by re-import.

Open the pom.xml in the byon-monitor module and add the following snippet to the bottom of the dependencies block: (can either be done in IntelliJ or by hand)

Code Block
<dependency>
   <groupId>org.onos.byon</groupId>
   <artifactId>byon-app</artifactId>
   <version>1.0-SNAPSHOT</version>
</dependency>

The archetype comes with a file called AppComponent.java. Refactor this class and call it NetworkEventMonitor. And add the following code to it.

 

 

construct an instance of the InternalListener.

Code Block
private final InternalListener listener = new InternalListener();

This listener will need to be added and removed to the networks map during activation and deactivation respectively.

Alright, so now that the stores emit events the managers should be made to receive them. For this we are going to have to add a reference on the EventDeliveryService an AbstractListenerRegistry to keep track of listeners and NetworkStoreDelegate as shown in the code snippet below.

Code Block
languagejava
	@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
	protected EventDeliveryService eventDispatcher;

    private final AbstractListenerRegistry<NetworkEvent, NetworkListener>
            listenerRegistry = new AbstractListenerRegistry<>();

    private final NetworkStoreDelegate delegate = new InternalStoreDelegate();

Then we need to add a couple lines in the activate in order to register our Event type for our listeners and set our delegate.

Code Block
 eventDispatcher.addSink(NetworkEvent.class, listenerRegistry);
 store.setDelegate(delegate);
       

and vice versa deactivate

Code Block
eventDispatcher.removeSink(NetworkEvent.class);
store.unsetDelegate(delegate);

Finally add the methods to add listeners and dispatch events coming from the store:

Code Block
languagejava
    @Override
    public void addListener(NetworkListener listener
Code Block
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
   protected NetworkService service;

   private final Listener listener = new Listener();

   @Activate
   protected void activate() {
       service listenerRegistry.addListener(listener);
       log.info("Started");
   }

    @Deactivate@Override
    protectedpublic void deactivateremoveListener(NetworkListener listener) {
       service listenerRegistry.removeListener(listener);
       log.info("Stopped");
   }

    private class ListenerInternalStoreDelegate implements NetworkListenerNetworkStoreDelegate {
        @Override
        public void eventnotify(NetworkEvent event) {
            logeventDispatcher.info("{}", post(event);
        }
    }

To test this, you will need to create a new component that registers to the NetworkEvents with the NetworkService. We will leave this as an extra credit exercise. 

Then update the bundles line in byon-push-bits:     

Code Block
bundles="byon-app byon-cli byon-monitor"

Verify what you built

So once again recompile and redeploy byon by using the byon-push-bits command.

Info

Make sure to use the @Component annotation to start an instance of the class automatically.You will also want to register and deregister with the NetworkService in the activate and deactivate methods of your component.

Finally, build and push the app to the ONOS cluster. You should try to test your implementation. When you add and remove networks and/or hosts you should see this being reflected on the other ONOS instances.

Furthermore, you add, remove, or update When you add a network you should see the following line in the ONOS log. You can get the ONOS log by running:

Code Block
distributed@mininet-vm:~/ $ ol

 

And you should see a line that look like:

Code Block
INFO  | event-dispatch-0 | NetworkEventMonitor    | 187 - org.onos.byon.monitor - 1.0.0.SNAPSHOT | NetworkEvent{time=<time&date>, type=NETWORK_ADDED, subject=test}

 

Conclusion

Congratulations! You have learned how to develop an ONOS distributed application on ONOS.