Table of Contents
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 <feature name="ima-controller" description="IMA :: OpenDaylight :: Controller" version='${project.version}'>
21 <feature version="${controller.base.version}">odl-base-all</feature>
22 <!--
23 <feature version="${features.adsal-compat.version}">odl-adsal-compatibility</feature>
24 -->
25 <feature version="${controller.adsal.version}">odl-adsal-all</feature>
26 <feature version="${controller.nsf.version}">odl-nsf-all</feature>
27 <feature version="${controller.restconf.version}">odl-restconf</feature>
28 <feature version="${controller.mdsal.version}">odl-mdsal-broker</feature>
29 <feature version="${openflowplugin.version}">odl-openflowplugin-southbound</feature>
30 <feature version="${openflowplugin.version}">odl-openflow----plugin-nxm-extensions</feature>
31 <feature version="${openflowplugin.version}">odl-openflowplugin-flow-services</feature>
32 <feature version="${ovsdb.plugin.version}">odl-ovsdb-plugin</feature>
33 <bundle>mvn:de.dailab.nemo.ima.controller/ima-controller/${project.version}</bundle> <---------- copy 1.0.0-SNAPSHOT
34 </feature>
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.
<plugin> 217 <groupId>org.apache.maven.plugins</groupId> 218 <artifactId>maven-dependency-plugin</artifactId> 219 <!-- 220 <version>2.6</version> 221 --> 222 <executions> 223 <execution> 224 <id>copy</id>
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 <del>odl-adsal-compatibility</del>
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
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
ima-controller project
Dev Resources
- Creating router, Add flow with ovs-ctl: http://dtucker.co.uk/hack/building-a-router-with-openvswitch.html
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
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<Topology> getAllTopologies() { InstanceIdentifier topoIdentifier = InstanceIdentifier.builder(NetworkTopology.class).toInstance(); System.out.println("topoIdentifier " + topoIdentifier); List<Topology> 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<Link> 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<Topology> 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<Link> 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
- writing flow rules: http://www.frank-durr.de/?p=126