Versions Compared

Key

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

...

We are also going to need a couple interfaces that will be needed by the listeners and the and the delegates. The listeners are components which have registered to obtain events from this service, these are usually local. A delegate is a neighbouring manager which is receiving events from a neighbouring store for the purpose of either taking action on the store event or notifying listeners. So we are going to add NetworkListener.

...

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

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

...

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
language

 

java
	@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
	protected EventDeliveryService eventDispatcher;

    private ApplicationId appId;
    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) {
        listenerRegistry.addListener(listener);
    }

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

    private class InternalStoreDelegate implements NetworkStoreDelegate {
        @Override
        public void notify(NetworkEvent event) {
            eventDispatcher.post(event);
        }
    }

To test this you 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.

 

 

Code Block
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
   protected NetworkService service;

   private final Listener listener = new Listener();

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

   @Deactivate
   protected void deactivate() {
       service.removeListener(listener);
       log.info("Stopped");
   }

   private class Listener implements NetworkListener {
       @Override
       public void event(NetworkEvent event) {
           log.info("{}", event);
       }
   }

 

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.

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

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