====== ODL dev ima-controller ====== Copy SDN-TUT plugin-exercise. * parent-pom: * all features and bundles version * all bundles dependencies (already managed by odlparent). * feature-pom: * all dependent features used in src/features.xml. Versions are declared in parent pom. * all dependent bundles * plugin bundle-pom: ====== Karaf - Maven ====== ===== Updating features-repo snapshot in karaf 3.0 ===== his is an example of a features.xml file that points to jar files in the local file system: 20 21 odl-base-all 22 25 odl-adsal-all 26 odl-nsf-all 27 odl-restconf 28 odl-mdsal-broker 29 odl-openflowplugin-southbound 30 odl-openflow----plugin-nxm-extensions 31 odl-openflowplugin-flow-services 32 odl-ovsdb-plugin 33 mvn:de.dailab.nemo.ima.controller/ima-controller/${project.version} <---------- copy 1.0.0-SNAPSHOT 34 Karaf Distribution: **Exclude** features-xml-bundle from dependency list. Install feature-repo manually from karaf: feature:repo-add mvn:de.dailab.nemo.ima.controller/features-ima/1.0.0-SNAPSHOT/xml/features Watch the repo-bundle (is this needed?): bundle:watch --start mvn:de.dailab.nemo.ima.controller/features-ima/1.0.0-SNAPSHOT/xml/features bundle:watch --start de.dailab.nemo.ima.controller/ima-controller/1.0.0-SNAPSHOT bundle:watch --list Make changes to the feature-xml project: cd features/ima vim src/.../features.xml mvn clean install Refresh ima feature repo: feature:repo-refresh mvn:de.dailab.nemo.ima.controller/features-ima/1.0.0-SNAPSHOT/xml/features feature:info ima-controller # the new feature dependencies should be shown ===== Updating Bundle snapshot in karaf 3.0 ===== Install feature: feature:install ima-controller ====== Troubleshooting ====== * Could not find artifacts: https://wiki.opendaylight.org/view/Karaf:Step_by_Step_Guide#Could_not_find_artifact * dependency not declared in bundle, features, etc. Add the to **scope compile** * Bad artifact coordinates mvn:org.opendaylight.controller/features-nsf/${controller.nsf.version}/xml/features, * Delete the ${..} from .m2 then recompile * feature:install karaf-base-all look for tomcat-security in wrong location: * feature-list | grep base * feature:repo-list | grep base --> remove duplicate version. * cd feature-abc; mvn clean install * rm -rf $KARAF/data/* ===== Karaf: Update Karaf maven version requirement ===== The generated karaf distribution archetype use maven 3.0.0. This mvn version can not resolve com.google.common.collect. Use maven > 3.1.1 Could not start bundle mvn:de.dailab.nemo.ima.controller/ima-controller-main/1.0.0-SNAPSHOT in feature(s) ima-controller-1.0.0- SNAPSHOT: The bundle "de.dailab.nemo.ima.controller.ima-controller-main_1.0.0.SNAPSHOT [61]" could not be resolved. Reason: Missing Constraint: Import-Package: com.google.common.collect; version="[18.0.0,19.0.0)" Do a mvn dependecy:tree +- org.opendaylight.controller:sal-binding-api:jar:1.2.0-SNAPSHOT:compile +- com.google.guava:guava:jar:18.0:compile com.google.common.collect is packaged in guava.jar so check if sal-binding-api is in dependencies list. ===== Karaf: mvn dependency:tree ===== Comment out the version of maven-dependency-plugin in the autogenerated karaf-distribution pom. Newer version will be used. 217 org.apache.maven.plugins 218 maven-dependency-plugin 219 222 223 224 copy ===== Bundle could not be resolved ===== feature:install ima-controller Refreshing bundles org.apache.aries.util (13) Error executing command: Could not start bundle mvn:org.opendaylight.controller/dummy-console/1.3.0-SNAPSHOT in feature(s) odl-base-dummy-console-1.3.0-SNAPSHOT: The bundle "org.opendaylight.controller.dummy-console_1.3.0.SNAPSHOT [101]" could not be resolved. Reason: Missing Constraint: Require-Capability: osgi.ee; filter="(&(osgi.ee=JavaSE)(version=1.7))" Solution: dummy-console is in features-adsal. So add it to the features.xml repo and in feature-pom dependencies. ==== Missing Constraint ==== https://issues.apache.org/jira/browse/KARAF-3069 Solution: use karaf 3.0.2 In parent.pom: karaf.version 3.0.2 karaf> version The new maven bundle plugin 2.5.0 creates a new standard OSGi header: Require-Capability: osgi.ee; filter="(&(osgi.ee=JavaSE)(version=1.6))" So such bundles can only be resolved if the capability is present. Because of this bug such bundles can not be resolved in karaf by default. How to reproduce: Load and unpack karaf 3.0.1 Set "framework=equinox" in etc/config.properties Start bin/karaf In the console type "capabilities 0 | grep osgi.ee" It will show no matching capability. Problem: The problem is that we use a variable ${services-${karaf.framework}} which does not exist if the framework is equinox. Workaround: Remove the line ${services-${karaf.framework}} and the ", \" in the line above. ==== Could not find features-base xx in apache (http://repository.apache.org/content/groups/snapshots-group/) ==== Doing mvn dependency:tree, dependency:lis Add all feature xml dependencies from features-artifacts to karaf-distribution dependencies.??? not solving problem ====== Testing ====== Features: ima-controller depends on: feature-base, feature-nsf, feature-mdsal, feature-restconf, feature-adsal odl-nsf-all and odl-adsal-compatibility Install features in karaf: feature:install ima-controller odl-restconf odl-l2switch-switch odl-mdsal-apidocs odl-dlux-all ====== Wireshark ====== 2. on local machine: # ssh -X root@remotemachine # wireshark 3. Go to Capture > Options > Interface > Pseudo-Device ====== Working ====== * http://www.brocade.com/downloads/documents/html_product_manuals/Brocade_Vyatta_Controller/bvc_1.x/bvc_111_user_guide/GUID-ECEC4E6B-70B4-461A-93F6-C6DE959A8C2A.html feature:repo-add mvn:de.dailab.nemo.ima.controller/features-ima/1.0.0-SNAPSHOT/xml/features feature:repo-add mvn:de.dailab.nemo.dmm/features-dmm/1.0.0-SNAPSHOT/xml/features feature:install dmm-switch feature:install ima-controller odl-mdsal-apidocs odl-dlux-all bundle:watch de.dailab.nemo.ima.controller/ima-controller/1.0.0-SNAPSHOT mn --custom topo-2sw-2host.py --topo mytopo --switch ovsk,protocol=OpenFlow13 --controller remote,ip=10.10.11.44,port=6633 sudo mn --switch ovsk,protocol=OpenFlow13 --controller remote,ip=10.10.11.44,port=6633 ovs-ofctl -O OpenFlow13 dump-flows s4 log:set TRACE de.dailab.nemo.ima.controller If code changes relating to Service loading (SAL) it's better to reinstall bundle: feature:uninstall ima-controller feature:install ima-controller ===== See if flow rule applied ===== ovs-ofctl -O OpenFlow13 dump-flows s1 show something like this: n_packets show number of packets, for which rule is applied. Here all are dropped!! [root@mininet fedora]# ovs-ofctl -O OpenFlow13 dump-flows s1 OFPST_FLOW reply (OF1.3) (xid=0x2): cookie=0x0, duration=188.304s, table=0, n_packets=14, n_bytes=644, priority=0 actions=drop cookie=0x0, duration=188.141s, table=0, n_packets=0, n_bytes=0, priority=65535,dl_type=0x88cc actions=CONTROLLER:65535 ==== ovs-dpctl dump-flows ==== ovs-dpctl show Show data path in the last 5 second. So start after doing a ping: ovs-dpctl dump-flows -m sudo ovs-dpctl dump-flows -m skb_priority(0),in_port(s1-eth1),skb_mark(0/0),eth(src=8a:03:93:82:15:2a/00:00:00:00:00:00,dst=ff:ff:ff:ff:ff:ff /00:00:00:00:00:00),eth_type(0x0806),arp(sip=10.0.0.1/0.0.0.0,tip=10.0.0.3/0.0.0.0,op=1/0,sha=8a:03:93:82:15:2a /00:00:00:00:00:00,tha=00:00:00:00:00:00/00:00:00:00:00:00), packets:2, bytes:84, used:0.181s, actions:userspace(pid=4294962801,slow_path(controller)) ===== . ===== **Restart karaf after installing bundle for the first time. So they are autostarted in good sequence** **Empty karaf/data then restart, repo-add, feature:install etc.** ===== ODL Controller Modules ===== * https://wiki.opendaylight.org/view/Controller_Projects%27_Modules/Bundles_and_Interfaces * Tutorial http://thenewstack.io/writing-opendaylight-applications/ * ODL interfaces: https://sdnforall.wordpress.com/2014/09/04/important-interfaces-in-opendaylight/ ====== ima-controller project ====== ===== Dev Resources ===== * Creating router, Add flow with ovs-ctl: http://dtucker.co.uk/hack/building-a-router-with-openvswitch.html * Openflow: http://archive.openflow.org/wk/?title=OpenDayLight_Tutorial * gui https://sdngeeks.wordpress.com/2014/08/01/network-statistics-sample-sdn-application-with-opendaylight-code-walk-thru/ ===== Scaffolding ===== * generate simple mdsal archetype project * cp provider to controller-main * generate distribution archetype project * move main pom content to commons/parent/pom * fix featuers, dependencies... ===== Feature Dependency ===== Feature depends on: odl-yangtools-common 0.7.0-SNAPSHOT odl-yangtools-binding 0.7.0-SNAPSHOT odl-l2switch-hosttracker 0.2.0-SNAPSHOT Feature contains followed bundles: mvn:de.dailab.nemo.ima.controller/ima-controller-model/1.0.0-SNAPSHOT mvn:de.dailab.nemo.ima.controller/ima-controller-main/1.0.0-SNAPSHOT Hosttracker depends on AddressTracker depends on Arphandler depends on Loopremover. https://wiki.opendaylight.org/view/L2_Switch:Helium:Developer_Guide Arphandler install default flooding rules. Main controller will remove these flows. ===== How l2switch works ===== Using mobility.py, disable deleting flows. Disable flooding: vim $karaf/etc/opendaylight/54-arphandler.xml Disable drop rule: vim $karaf/etc/opendaylight/58-l2switchmain.xml ==== Observation ==== h1 moves from s1 to s2 port 14 * h1 keeps IP * s2 port 2:2 still fwd packets destined to h1 to s1. **Flow not updated** * additional host-tracker for h1 is created on port 14. Timestamp updated. h1 moves from s2 to s3 * s2 prot 2:3 fwd to s3 with h1,h3 host-tracker entry. * port 2:2 still fwd to s1, old host-tracker entry. Conclusion: * Host-tracker add new nodes, not delete old ones. * Flows are not updated. ==== Arp handler ==== Listen to arp packet and flood or direct forward arp to ports. ==== Address Tracker ==== listen to arp and insert srcMac, ip to the nodeConnectorRef where the arp came from. ==== Host Tracker ==== Listen to **Topology** changes: HostNode.class and Link.class Listen to **Inventory** changes: Adresses.class Remove oldHost, oldLinsk and add newHost, newLinks. Observation: * Topology is updated fast. ==== MD-SAL database, iid, read, write ==== * http://sdntutorials.com/how-to-look-up-topology-and-links-in-md-sal/ Example query for topology model: "topology": [ { "topology-id": "flow:1", "link": [ { "link-id": "openflow:3:2", "destination": { "dest-tp": "openflow:2:3", "dest-node": "openflow:2" }, "source": { "source-node": "openflow:3", "source-tp": "openflow:3:2" } }, { // Get all topologies in MD-SAL private List getAllTopologies() { InstanceIdentifier topoIdentifier = InstanceIdentifier.builder(NetworkTopology.class).toInstance(); System.out.println("topoIdentifier " + topoIdentifier); List topos = ((NetworkTopology) this.dataProviderService .readOperationalData(topoIdentifier)).getTopology(); return topos; } // Get a particular toplogy in MD-SAL private Topology getFlowTopology() { TopologyId topoId = new TopologyId("flow:1"); InstanceIdentifier topoIdentifier = InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class, new TopologyKey(topoId)).toInstance(); System.out.println("topoIdentifier " + topoIdentifier); Topology topology = (Topology) dataProviderService.readOperationalData(topoIdentifier); return topology; } // Get all links in MD-SAL private List getAllLinks() { Topology flowTopology = getFlowTopology(); return flowTopology.getLink(); } === Get all topologies === Create Instance Id form Topology Object to query all data: InstanceIdentifier topoIdentifier = InstanceIdentifier.builder(NetworkTopology.class).toInstance(); Query Database using the Identifier: List topos = ((NetworkTopology) this.dataProviderService .readOperationalData(topoIdentifier)).getTopology(); === Get a particular toplogy in MD-SAL === We need an ID object: TopologyId topoId = new TopologyId("flow:1"); Create InstanceId for the specific flow, using child method: InstanceIdentifier topoIdentifier = InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class, new TopologyKey(topoId)).toInstance(); Get Topology object from the query: Topology topology = (Topology) dataProviderService.readOperationalData(topoIdentifier); Access Data in the Topology object: List allLinks = topology.getLink(); ====== dmm-switch / ima-controller ====== ===== Understand startup process ===== TutorialFlowProgrammer register for OpendaylightInventory (implement OpendaylightInventoryListener). Start mininet triggers onNodeUpdate callback. This write 2 LLDP rules to the OVS. 2015-05-07 04:43:07,168 | INFO | pool-63-thread-1 | TutorialFlowProgrammer | 407 - de.dailab.nemo.ima.controller.ima-controller - 1.0.0.SNAPSHOT | MD-SAL Node Update: NodeUpdated [_id=Uri [_value=openflow:1], _nodeRef=NodeRef [_value=KeyedInstanceIdentifier{targetType=interface org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, path=[org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes, org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node[key=NodeKey [_id=Uri [_value=openflow:1]]]]}], augmentation=[FlowCapableNodeUpdated [_ipAddress=IpAddress [_ipv4Address=Ipv4Address [_value=10.10.11.237], _value=[1, 0, ., 1, 0, ., 1, 1, ., 2, 3, 7]], _switchFeatures=SwitchFeatures [_capabilities=[class org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityFlowStats, class org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityPortStats, class org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityQueueStats, class org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityTableStats], _maxBuffers=256, _maxTables=254, augmentation=[]]]]] ===== WakeupOnNode ===== 2015-05-12 09:41:05,683 | TRACE | lt-dispatcher-17 | WakeupOnNode | 389 - de.dailab.nemo.ima.controller.ima-controller - 1.0.0.SNAPSHOT | Data chaged - table: Table{getId=0, augmentations={interface org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData=FlowTableStatisticsData{getFlowTableStatistics=FlowTableStatistics{getActiveFlows=Counter32 [_value=0], getPacketsLookedUp=Counter64 [_value=7106], getPacketsMatched=Counter64 [_value=7058], augmentations={}}}, interface org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData=AggregateFlowStatisticsData{getAggregateFlowStatistics=AggregateFlowStatistics{getByteCount=Counter64 [_value=0], getFlowCount=Counter32 [_value=0], getPacketCount=Counter64 [_value=0], augmentations={}}}}} 2015-05-12 09:41:05,683 | DEBUG | lt-dispatcher-17 | SwitchHandlerFacadeImpl | 389 - de.dailab.nemo.ima.controller.ima-controller - 1.0.0.SNAPSHOT | expected table acquired, learning .. 2015-05-12 09:41:05,685 | DEBUG | lt-dispatcher-17 | SwitchHandler | 389 - de.dailab.nemo.ima.controller.ima-controller - 1.0.0.SNAPSHOT | expected table acquired, learning .. 2015-05-12 09:41:05,686 | TRACE | lt-dispatcher-14 | WakeupOnNode | 389 - de.dailab.nemo.ima.controller.ima-controller - 1.0.0.SNAPSHOT | Data chaged - table: Table{getId=0, augmentations={interface org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData=FlowTableStatisticsData{getFlowTableStatistics=FlowTableStatistics{getActiveFlows=Counter32 [_value=0], getPacketsLookedUp=Counter64 [_value=7106], getPacketsMatched=Counter64 [_value=7058], augmentations={}}}, interface org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData=AggregateFlowStatisticsData{getAggregateFlowStatistics=AggregateFlowStatistics{getByteCount=Counter64 [_value=0], getFlowCount=Counter32 [_value=0], getPacketCount=Counter64 [_value=0], augmentations={}}}}} 2015-05-12 09:41:05,694 | DEBUG | lt-dispatcher-14 | SwitchHandlerFacadeImpl | 389 - de.dailab.nemo.ima.controller.ima-controller - 1.0.0.SNAPSHOT | expected table acquired, learning .. 2015-05-12 09:41:05,696 | DEBUG | lt-dispatcher-17 | SwitchHandler | 389 - de.dailab.nemo.ima.controller.ima-controller - 1.0.0.SNAPSHOT | writing packetForwardToController flow. Flow Path: KeyedInstanceIdentifier{targetType=interface org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table, path=[org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes, org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node[key=NodeKey [_id=Uri [_value=openflow:4]]], org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode, org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table[key=TableKey [_id=0]]]} 2015-05-12 09:41:05,999 | TRACE | ult-dispatcher-3 | WakeupOnNode | 389 - de.dailab.nemo.ima.controller.ima-controller - 1.0.0.SNAPSHOT | Data chaged - table: Table{getId=0, augmentations={interface org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData=FlowTableStatisticsData{getFlowTableStatistics=FlowTableStatistics{getActiveFlows=Counter32 [_value=0], getPacketsLookedUp=Counter64 [_value=7106], getPacketsMatched=Counter64 [_value=7059], augmentations={}}}, interface org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData=AggregateFlowStatisticsData{getAggregateFlowStatistics=AggregateFlowStatistics{getByteCount=Counter64 [_value=0], getFlowCount=Counter32 [_value=0], getPacketCount=Counter64 [_value=0], augmentations={}}}}} 2015-05-12 09:41:06,008 | DEBUG | ult-dispatcher-3 | SwitchHandlerFacadeImpl | 389 - de.dailab.nemo.ima.controller.ima-controller - 1.0.0.SNAPSHOT | expected table acquired, learning .. 2015-05-12 09:41:06,008 | DEBUG | ult-dispatcher-3 | SwitchHandler | 389 - de.dailab.nemo.ima.controller.ima-controller - 1.0.0.SNAPSHOT | expected table acquired, learning .. 2015-05-12 09:41:06,008 | DEBUG | ult-dispatcher-3 | SwitchHandler | 389 - de.dailab.nemo.ima.controller.ima-controller - 1.0.0.SNAPSHOT | writing packetForwardToController flow. Flow Path: KeyedInstanceIdentifier{targetType=interface org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table, path=[org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes, org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node[key=NodeKey [_id=Uri [_value=openflow:3]]], org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode, org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table[key=TableKey [_id=0]]]} 2015-05-12 09:41:06,009 | TRACE | ult-dispatcher-3 | WakeupOnNode | 389 - de.dailab.nemo.ima.controller.ima-controller - 1.0.0.SNAPSHOT | Data chaged - table: Table{getId=0, augmentations={interface org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData=FlowTableStatisticsData{getFlowTableStatistics=FlowTableStatistics{getActiveFlows=Counter32 [_value=0], getPacketsLookedUp=Counter64 [_value=7106], getPacketsMatched=Counter64 [_value=7059], augmentations={}}}, interface org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData=AggregateFlowStatisticsData{getAggregateFlowStatistics=AggregateFlowStatistics{getByteCount=Counter64 [_value=0], getFlowCount=Counter32 [_value=0], getPacketCount=Counter64 [_value=0], augmentations={}}}}} 2015-05-12 09:41:06,009 | DEBUG | ult-dispatcher-3 | SwitchHandlerFacadeImpl | 389 - de.dailab.nemo.ima.controller.ima-controller - 1.0.0.SNAPSHOT | expected table acquired, learning .. 2015-05-12 09:41:11,722 | TRACE | lt-dispatcher-18 | WakeupOnNode ===== Write Flow ===== * https://wiki.opendaylight.org/view/OpenDaylight_OpenFlow_Plugin:End_to_End_Flows#Check_inventory * https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL:CliffNotes * http://sdntutorials.com/creating-instanceidentifier-for-binding-aware-binding-independent-components/ * http://sdntutorials.com/how-to-publish-node-to-md-sal/ * http://sdntutorials.com/how-to-publish-nodeconnector-to-md-sal/ * writing flow rules: http://www.frank-durr.de/?p=126 * http://h17007.www1.hp.com/docs/networking/solutions/sdn/devcenter/03_-_HP_OpenFlow_Technical_Overview_TSG_v1_2013-10-01.pdf * http://etherealmind.com/defining-flow-forwarding-instead-switching-routing/ * sample code: https://github.com/sdnhub/SDNHub_Opendaylight_Tutorial/blob/master/plugin_exercise/src/main/java/org/opendaylight/tutorial/plugin_exercise/utils/openflow13/MatchUtils.java * https://wiki.opendaylight.org/view/Editing_OpenDaylight_OpenFlow_Plugin:End_to_End_Flows:Example_Flows#Ethernet_Src_.26_Dest_Addresses.2C_Ethernet_Type