====== 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