├── .gitignore ├── LICENSE ├── README.md ├── acl ├── config │ ├── pom.xml │ └── src │ │ └── main │ │ └── resources │ │ └── initial │ │ └── 51-acl-config.xml ├── implementation │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── org │ │ │ └── sdnhub │ │ │ └── odl │ │ │ └── tutorial │ │ │ └── acl │ │ │ └── impl │ │ │ ├── TutorialACL.java │ │ │ ├── TutorialACLModule.java │ │ │ └── TutorialACLModuleFactory.java │ │ └── yang │ │ └── acl-impl.yang ├── model │ ├── pom.xml │ └── src │ │ └── main │ │ └── yang │ │ └── acl.yang └── pom.xml ├── commons ├── parent │ └── pom.xml └── utils │ ├── pom.xml │ └── src │ └── main │ └── java │ └── org │ └── sdnhub │ └── odl │ └── tutorial │ └── utils │ ├── GenericTransactionUtils.java │ ├── PacketParsingUtils.java │ ├── inventory │ └── InventoryUtils.java │ └── openflow13 │ ├── ActionUtils.java │ ├── InstructionUtils.java │ └── MatchUtils.java ├── distribution ├── karaf-branding │ ├── pom.xml │ └── src │ │ └── main │ │ └── resources │ │ └── org │ │ └── apache │ │ └── karaf │ │ └── branding │ │ └── branding.properties ├── opendaylight-karaf │ └── pom.xml └── pom.xml ├── features ├── pom.xml └── src │ └── main │ └── resources │ └── features.xml ├── learning-switch ├── config │ ├── pom.xml │ └── src │ │ └── main │ │ └── resources │ │ └── initial │ │ └── 49-learning-switch-config.xml ├── implementation │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── org │ │ │ └── sdnhub │ │ │ └── odl │ │ │ └── tutorial │ │ │ └── learningswitch │ │ │ └── impl │ │ │ ├── TutorialL2Forwarding.java │ │ │ ├── TutorialL2Forwarding.single_switch.solution │ │ │ ├── TutorialLearningSwitchModule.java │ │ │ └── TutorialLearningSwitchModuleFactory.java │ │ └── yang │ │ └── learning-switch-impl.yang └── pom.xml ├── netconf-exercise ├── base_datastore.xml ├── config │ ├── pom.xml │ └── src │ │ └── main │ │ └── resources │ │ └── initial │ │ └── 51-netconf-exercise-config.xml ├── implementation │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── org │ │ │ └── sdnhub │ │ │ └── odl │ │ │ └── tutorial │ │ │ └── netconf │ │ │ └── exercise │ │ │ └── impl │ │ │ ├── MyRouterOrchestrator.java │ │ │ ├── TutorialNetconfExerciseModule.java │ │ │ └── TutorialNetconfExerciseModuleFactory.java │ │ └── yang │ │ └── netconf-exercise.yang ├── model │ ├── pom.xml │ └── src │ │ └── main │ │ └── yang │ │ └── router.yang ├── netconf-postman.json ├── pom.xml ├── register_netconf_device.sh ├── router.yang ├── spawn_router.sh └── unregister_netconf_device.sh ├── pom.xml └── tapapp ├── config ├── pom.xml └── src │ └── main │ └── resources │ └── initial │ └── 50-tapapp-config.xml ├── implementation ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── sdnhub │ │ └── odl │ │ └── tutorial │ │ └── tapapp │ │ └── impl │ │ ├── TutorialTapAppModule.java │ │ ├── TutorialTapAppModuleFactory.java │ │ ├── TutorialTapProvider.bidirectional.solution │ │ ├── TutorialTapProvider.java │ │ └── TutorialTapProvider.unidirectional.solution │ └── yang │ └── tapapp-impl.yang ├── model ├── pom.xml └── src │ └── main │ └── yang │ └── tap.yang ├── pom.xml └── postman-resources └── tapapp-postman.json /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | target/ 3 | *.class 4 | *.iml 5 | **/target 6 | **/bin 7 | dist 8 | **/logs 9 | products 10 | repository 11 | workspace 12 | *~ 13 | target 14 | .classpath 15 | .project 16 | .settings 17 | MANIFEST.MF 18 | 19 | # Package Files # 20 | *.jar 21 | *.war 22 | *.ear 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SDNHub Opendaylight Tutorial 2 | ============================ 3 | This is the OpenDaylight project source code used by the [our tutorial](http://sdnhub.org/tutorials/opendaylight/). 4 | 5 | # Directory Organization 6 | * pom.xml: The POM in the main directory specifies all the sub-POMs to build 7 | * commons/parent: contains the parent pom.xml with all properties defined for the subprojects. 8 | * commons/utils: contains custom utilities built for OpenFlow programming 9 | * learning-switch: contains the tutorial L2 hub / switch 10 | * tapapp: contains the traffic monitoring tap application 11 | * features: defines the two features "sdnhub-tutorial-learning-switch", * "sdnhub-tutorial-tapapp" that can be loaded in Karaf 12 | * distribution/karaf-branding: contains karaf branner for SDN Hub 13 | * distribution/opendaylight-karaf: contains packaging relevant pom to * generate a running directory 14 | 15 | # HOW TO BUILD 16 | In order to build it's required to have JDK 1.8+ and Maven 3.2+. 17 | The following commands are used to build and run. 18 | ``` 19 | $ mvn clean install 20 | $ cd distribution/opendaylight-karaf/target/assembly 21 | $ ./bin/karaf 22 | karaf>feature:install sdnhub-XYZ 23 | ``` 24 | -------------------------------------------------------------------------------- /acl/config/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.sdnhub.odl.tutorial 7 | commons 8 | 1.2.0-SNAPSHOT 9 | ../../commons/parent/pom.xml 10 | 11 | 12 | org.sdnhub.odl.tutorial.acl 13 | acl-config 14 | 1.0.0-SNAPSHOT 15 | SDN Hub tutorial Project ACL application Config 16 | 17 | jar 18 | 19 | 20 | 21 | org.codehaus.mojo 22 | build-helper-maven-plugin 23 | ${build.plugins.plugin.version} 24 | 25 | 26 | attach-artifacts 27 | 28 | attach-artifact 29 | 30 | package 31 | 32 | 33 | 34 | ${project.build.directory}/classes/initial/${acl.configfile} 35 | xml 36 | config 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /acl/config/src/main/resources/initial/51-acl-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | prefix:acl-impl 9 | acl-impl 10 | 11 | 12 | binding:binding-notification-service 13 | binding-notification-broker 14 | 15 | 16 | binding:binding-async-data-broker 17 | binding-data-broker 18 | 19 | 20 | binding:binding-rpc-registry 21 | binding-rpc-broker 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | urn:sdnhub:odl:tutorial:acl:acl-impl?module=acl-impl&revision=2015-07-22 30 | urn:opendaylight:params:xml:ns:yang:openflow:common:config:impl?module=openflow-provider-impl&revision=2014-03-26 31 | 32 | 33 | -------------------------------------------------------------------------------- /acl/implementation/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.sdnhub.odl.tutorial.acl 6 | acl-parent 7 | 0.1.0-SNAPSHOT 8 | 9 | 10 | acl-impl 11 | SDN Hub tutorial project ACL application Impl 12 | 1.0.0-SNAPSHOT 13 | bundle 14 | 15 | 16 | 17 | org.sdnhub.odl.tutorial 18 | utils 19 | ${utils.version} 20 | 21 | 22 | org.sdnhub.odl.tutorial.acl 23 | acl-model 24 | ${acl.version} 25 | 26 | 27 | org.opendaylight.openflowplugin.model 28 | model-flow-service 29 | ${openflowplugin.version} 30 | 31 | 32 | 33 | 34 | 35 | org.opendaylight.yangtools 36 | yang-maven-plugin 37 | ${yangtools.version} 38 | 39 | 40 | 41 | generate-sources 42 | 43 | 44 | src/main/yang 45 | 46 | 47 | org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl 48 | ${codeGeneratorPath} 49 | 50 | 51 | org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator 52 | ${configCodeGeneratorPath} 53 | 54 | urn:sdnhub:odl:tutorial:acl:acl-impl==org.sdnhub.odl.tutorial.acl.impl 55 | urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang 56 | 57 | 58 | 59 | org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl 60 | ${project.build.directory}/site/models 61 | 62 | 63 | true 64 | 65 | 66 | 67 | 68 | 69 | org.opendaylight.mdsal 70 | maven-sal-api-gen-plugin 71 | ${maven-sal-api-gen-plugin.version} 72 | jar 73 | 74 | 75 | org.opendaylight.controller 76 | yang-jmx-generator-plugin 77 | ${yang.jmx.version} 78 | 79 | 80 | 81 | 82 | org.apache.felix 83 | maven-bundle-plugin 84 | 2.4.0 85 | true 86 | 87 | 88 | * 89 | utils 90 | 91 | ${project.basedir}/META-INF 92 | 93 | 94 | 96 | 97 | org.codehaus.mojo 98 | build-helper-maven-plugin 99 | 1.8 100 | 101 | 102 | add-source 103 | 104 | add-source 105 | 106 | generate-sources 107 | 108 | 109 | src/main/yang 110 | ${codeGeneratorPath} 111 | ${configCodeGeneratorPath} 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | maven-clean-plugin 120 | 121 | 122 | 123 | ${codeGeneratorPath} 124 | 125 | ** 126 | 127 | 128 | 129 | ${configCodeGeneratorPath} 130 | 131 | ** 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /acl/implementation/src/main/java/org/sdnhub/odl/tutorial/acl/impl/TutorialACL.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 SDN Hub 3 | 4 | Licensed under the GNU GENERAL PUBLIC LICENSE, Version 3. 5 | You may not use this file except in compliance with this License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.gnu.org/licenses/gpl-3.0.txt 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 13 | implied. 14 | 15 | * 16 | */ 17 | 18 | package org.sdnhub.odl.tutorial.acl.impl; 19 | 20 | import java.nio.ByteBuffer; 21 | import java.util.List; 22 | import java.util.Map; 23 | 24 | import org.opendaylight.controller.md.sal.binding.api.DataBroker; 25 | import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; 26 | import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; 27 | import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; 28 | import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; 29 | import org.opendaylight.controller.sal.binding.api.NotificationProviderService; 30 | import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; 31 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; 32 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; 33 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; 34 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; 35 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; 36 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder; 37 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey; 38 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; 39 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; 40 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; 41 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; 42 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; 43 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; 44 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; 45 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; 46 | import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener; 47 | import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService; 48 | import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived; 49 | import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput; 50 | import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder; 51 | import org.opendaylight.yang.gen.v1.urn.sdnhub.odl.tutorial.acl.rev150722.AclSpec; 52 | import org.opendaylight.yang.gen.v1.urn.sdnhub.odl.tutorial.acl.rev150722.acl.spec.Acl; 53 | import org.opendaylight.yangtools.concepts.ListenerRegistration; 54 | import org.opendaylight.yangtools.concepts.Registration; 55 | import org.opendaylight.yangtools.yang.binding.DataObject; 56 | import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; 57 | import org.sdnhub.odl.tutorial.utils.GenericTransactionUtils; 58 | import org.sdnhub.odl.tutorial.utils.PacketParsingUtils; 59 | import org.sdnhub.odl.tutorial.utils.inventory.InventoryUtils; 60 | import org.sdnhub.odl.tutorial.utils.openflow13.MatchUtils; 61 | import org.slf4j.Logger; 62 | import org.slf4j.LoggerFactory; 63 | 64 | import com.google.common.base.Preconditions; 65 | import com.google.common.collect.Lists; 66 | 67 | public class TutorialACL implements AutoCloseable, DataChangeListener, PacketProcessingListener { 68 | private final Logger LOG = LoggerFactory.getLogger(this.getClass()); 69 | private final static long FLOOD_PORT_NUMBER = 0xfffffffbL; 70 | 71 | //Members related to MD-SAL operations 72 | private List registrations; 73 | private DataBroker dataBroker; 74 | private PacketProcessingService packetProcessingService; 75 | 76 | public TutorialACL(DataBroker dataBroker, NotificationProviderService notificationService, RpcProviderRegistry rpcProviderRegistry) { 77 | //Store the data broker for reading/writing from inventory store 78 | this.dataBroker = dataBroker; 79 | 80 | //Get access to the packet processing service for making RPC calls later 81 | this.packetProcessingService = rpcProviderRegistry.getRpcService(PacketProcessingService.class); 82 | 83 | //List used to track notification (both data change and YANG-defined) listener registrations 84 | this.registrations = registerDataChangeListeners(); 85 | 86 | //Register this object for receiving notifications when there are PACKET_INs 87 | registrations.add(notificationService.registerNotificationListener(this)); 88 | } 89 | 90 | @Override 91 | public void close() throws Exception { 92 | for (Registration registration : registrations) { 93 | registration.close(); 94 | } 95 | registrations.clear(); 96 | } 97 | 98 | private List registerDataChangeListeners() { 99 | Preconditions.checkNotNull(dataBroker); 100 | List registrations = Lists.newArrayList(); 101 | try { 102 | //Register listener for config updates and topology 103 | InstanceIdentifier aclSpecIID = InstanceIdentifier.builder(AclSpec.class) 104 | .build(); 105 | ListenerRegistration registration = dataBroker.registerDataChangeListener( 106 | LogicalDatastoreType.CONFIGURATION, 107 | aclSpecIID, this, AsyncDataBroker.DataChangeScope.SUBTREE); 108 | LOG.debug("DataChangeListener registered with MD-SAL for path {}", aclSpecIID); 109 | registrations.add(registration); 110 | 111 | } catch (Exception e) { 112 | LOG.error("Exception reached {}", e); 113 | } 114 | return registrations; 115 | } 116 | 117 | @Override 118 | public void onDataChanged(AsyncDataChangeEvent, DataObject> change) { 119 | LOG.debug("Data changed: {} created, {} updated, {} removed", 120 | change.getCreatedData().size(), change.getUpdatedData().size(), change.getRemovedPaths().size()); 121 | 122 | DataObject dataObject; 123 | 124 | // Iterate over any created nodes or interfaces 125 | for (Map.Entry, DataObject> entry : change.getCreatedData().entrySet()) { 126 | dataObject = entry.getValue(); 127 | if (dataObject instanceof Acl) { 128 | programACL((Acl)dataObject); 129 | } 130 | } 131 | } 132 | 133 | @Override 134 | public void onPacketReceived(PacketReceived notification) { 135 | NodeConnectorRef ingressNodeConnectorRef = notification.getIngress(); 136 | NodeRef ingressNodeRef = InventoryUtils.getNodeRef(ingressNodeConnectorRef); 137 | // NodeConnectorId ingressNodeConnectorId = InventoryUtils.getNodeConnectorId(ingressNodeConnectorRef); 138 | NodeId ingressNodeId = InventoryUtils.getNodeId(ingressNodeConnectorRef); 139 | 140 | // Useful to create it beforehand 141 | NodeConnectorId floodNodeConnectorId = InventoryUtils.getNodeConnectorId(ingressNodeId, FLOOD_PORT_NUMBER); 142 | NodeConnectorRef floodNodeConnectorRef = InventoryUtils.getNodeConnectorRef(floodNodeConnectorId); 143 | 144 | //Ignore LLDP packets, or you will be in big trouble 145 | byte[] etherTypeRaw = PacketParsingUtils.extractEtherType(notification.getPayload()); 146 | int etherType = (0x0000ffff & ByteBuffer.wrap(etherTypeRaw).getShort()); 147 | if (etherType == 0x88cc) { 148 | return; 149 | } 150 | 151 | // Flood packet 152 | packetOut(ingressNodeRef, floodNodeConnectorRef, notification.getPayload()); 153 | } 154 | 155 | private void packetOut(NodeRef egressNodeRef, NodeConnectorRef egressNodeConnectorRef, byte[] payload) { 156 | Preconditions.checkNotNull(packetProcessingService); 157 | LOG.debug("Flooding packet of size {} out of port {}", payload.length, egressNodeConnectorRef); 158 | 159 | //Construct input for RPC call to packet processing service 160 | TransmitPacketInput input = new TransmitPacketInputBuilder() 161 | .setPayload(payload) 162 | .setNode(egressNodeRef) 163 | .setEgress(egressNodeConnectorRef) 164 | .build(); 165 | packetProcessingService.transmitPacket(input); 166 | } 167 | 168 | private void programACL(Acl acl) { 169 | /* Programming a flow involves: 170 | * 1. Creating a Flow object that has a match and drop packets to destination address, 171 | * 2. Adding Flow object as an augmentation to the Node object in the inventory. 172 | * 3. FlowProgrammer module of OpenFlowPlugin will pick up this data change and eventually program the switch. 173 | */ 174 | 175 | NodeId nodeId = acl.getNode(); 176 | 177 | //Creating match object 178 | MatchBuilder matchBuilder = new MatchBuilder(); 179 | MatchUtils.createDstL3IPv4Match(matchBuilder, acl.getIpAddr()); 180 | 181 | /* 182 | * Create Flow 183 | */ 184 | String flowId = "L3_ACL_Rule_" + acl.getDestination(); 185 | FlowBuilder flowBuilder = new FlowBuilder(); 186 | flowBuilder.setMatch(matchBuilder.build()); 187 | flowBuilder.setId(new FlowId(flowId)); 188 | FlowKey key = new FlowKey(new FlowId(flowId)); 189 | flowBuilder.setBarrier(true); 190 | flowBuilder.setTableId((short)0); 191 | flowBuilder.setKey(key); 192 | flowBuilder.setPriority(32768); 193 | flowBuilder.setFlowName(flowId); 194 | flowBuilder.setHardTimeout(0); 195 | flowBuilder.setIdleTimeout(0); 196 | 197 | /* Perform transaction to store rule 198 | * 199 | */ 200 | InstanceIdentifier flowIID = InstanceIdentifier.builder(Nodes.class) 201 | .child(Node.class, new NodeKey(nodeId)) 202 | .augmentation(FlowCapableNode.class) 203 | .child(Table.class, new TableKey(flowBuilder.getTableId())) 204 | .child(Flow.class, flowBuilder.getKey()) 205 | .build(); 206 | GenericTransactionUtils.writeData(dataBroker, LogicalDatastoreType.CONFIGURATION, flowIID, flowBuilder.build(), true); 207 | LOG.debug("Programming ACL rule to block destination: {}",acl.getIpAddr()); 208 | 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /acl/implementation/src/main/java/org/sdnhub/odl/tutorial/acl/impl/TutorialACLModule.java: -------------------------------------------------------------------------------- 1 | package org.sdnhub.odl.tutorial.acl.impl; 2 | 3 | import org.opendaylight.controller.md.sal.binding.api.DataBroker; 4 | import org.opendaylight.controller.sal.binding.api.NotificationProviderService; 5 | import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | public class TutorialACLModule extends org.sdnhub.odl.tutorial.acl.impl.AbstractTutorialACLModule { 10 | private final Logger LOG = LoggerFactory.getLogger(this.getClass()); 11 | public TutorialACLModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { 12 | super(identifier, dependencyResolver); 13 | } 14 | 15 | public TutorialACLModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.sdnhub.odl.tutorial.acl.impl.TutorialACLModule oldModule, java.lang.AutoCloseable oldInstance) { 16 | super(identifier, dependencyResolver, oldModule, oldInstance); 17 | } 18 | 19 | @Override 20 | public void customValidation() { 21 | // add custom validation form module attributes here. 22 | } 23 | 24 | @Override 25 | public java.lang.AutoCloseable createInstance() { 26 | //Get all MD-SAL provider objects 27 | DataBroker dataBroker = getDataBrokerDependency(); 28 | RpcProviderRegistry rpcRegistry = getRpcRegistryDependency(); 29 | NotificationProviderService notificationService = getNotificationServiceDependency(); 30 | 31 | TutorialACL tutorialACL = new TutorialACL(dataBroker, notificationService, rpcRegistry); 32 | LOG.info("Tutorial Access Control List (instance {}) initialized.", tutorialACL); 33 | return tutorialACL; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /acl/implementation/src/main/java/org/sdnhub/odl/tutorial/acl/impl/TutorialACLModuleFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Generated file 3 | * 4 | * Generated from: yang module name: acl-impl yang module local name: acl-impl 5 | * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator 6 | * Generated at: Sun Jul 26 00:55:52 PDT 2015 7 | * 8 | * Do not modify this file unless it is present under src/main directory 9 | */ 10 | package org.sdnhub.odl.tutorial.acl.impl; 11 | public class TutorialACLModuleFactory extends org.sdnhub.odl.tutorial.acl.impl.AbstractTutorialACLModuleFactory { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /acl/implementation/src/main/yang/acl-impl.yang: -------------------------------------------------------------------------------- 1 | module acl-impl { 2 | yang-version 1; 3 | namespace "urn:sdnhub:odl:tutorial:acl:acl-impl"; 4 | prefix "acl-impl"; 5 | 6 | import config { prefix config; revision-date 2013-04-05; } 7 | import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; } 8 | 9 | description 10 | "This module contains the base YANG definitions for acl-impl."; 11 | 12 | revision "2015-07-22" { 13 | description 14 | "Initial revision."; 15 | } 16 | 17 | // This is the definition of the service implementation as a module identity 18 | identity acl-impl { 19 | base config:module-type; 20 | 21 | // Specifies the prefix for generated java classes. 22 | config:java-name-prefix TutorialACL; 23 | } 24 | 25 | // Augments the 'configuration' choice node under modules/module 26 | augment "/config:modules/config:module/config:configuration" { 27 | case acl-impl { 28 | when "/config:modules/config:module/config:type = 'acl-impl'"; 29 | 30 | //wires in the data-broker service 31 | container data-broker { 32 | uses config:service-ref { 33 | refine type { 34 | mandatory true; 35 | config:required-identity mdsal:binding-async-data-broker; 36 | } 37 | } 38 | } 39 | container notification-service { 40 | uses config:service-ref { 41 | refine type { 42 | mandatory false; 43 | config:required-identity mdsal:binding-notification-service; 44 | } 45 | } 46 | } 47 | container rpc-registry { 48 | uses config:service-ref { 49 | refine type { 50 | mandatory true; 51 | config:required-identity mdsal:binding-rpc-registry; 52 | } 53 | } 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /acl/model/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.sdnhub.odl.tutorial 6 | commons 7 | 1.2.0-SNAPSHOT 8 | ../../commons/parent/ 9 | 10 | 11 | org.sdnhub.odl.tutorial.acl 12 | acl-model 13 | 1.0.0-SNAPSHOT 14 | bundle 15 | SDN Hub tutorial project ACL application Model 16 | 17 | 18 | 19 | org.opendaylight.controller.model 20 | model-inventory 21 | ${controller-model.version} 22 | 23 | 24 | 25 | 26 | 27 | 28 | org.apache.felix 29 | maven-bundle-plugin 30 | true 31 | 32 | 33 | ${project.groupId}.${project.artifactId} 34 | org.opendaylight.yangtools.yang.binding.annotations, * 35 | ${project.basedir}/META-INF 36 | 37 | 38 | 39 | 40 | org.opendaylight.yangtools 41 | yang-maven-plugin 42 | ${yangtools.version} 43 | 44 | 45 | org.opendaylight.mdsal 46 | maven-sal-api-gen-plugin 47 | ${maven-sal-api-gen-plugin.version} 48 | jar 49 | 50 | 51 | org.opendaylight.mdsal 52 | yang-binding 53 | ${yang-binding.version} 54 | jar 55 | 56 | 57 | 58 | 59 | 60 | generate-sources 61 | 62 | 63 | src/main/yang 64 | 65 | 66 | org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl 67 | ${codeGeneratorPath} 68 | 69 | 70 | org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl 71 | target/site/models 72 | 73 | 74 | org.opendaylight.yangtools.yang.wadl.generator.maven.WadlGenerator 75 | target/site/models 76 | 77 | 78 | true 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | maven-clean-plugin 87 | 88 | 89 | 90 | ${codeGeneratorPath} 91 | 92 | ** 93 | 94 | 95 | 96 | ${codeGeneratorPath} 97 | 98 | ** 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /acl/model/src/main/yang/acl.yang: -------------------------------------------------------------------------------- 1 | module acl { 2 | yang-version 1; 3 | namespace "urn:sdnhub:odl:tutorial:acl"; 4 | prefix acl; 5 | 6 | import opendaylight-inventory {prefix inv; revision-date 2013-08-19;} 7 | import yang-ext {prefix ext; revision-date "2013-07-09";} 8 | import ietf-yang-types { prefix yang; revision-date 2010-09-24; } 9 | import ietf-inet-types { prefix inet; } 10 | description "ACL configuration"; 11 | 12 | revision "2015-07-22" { 13 | description "Initial version."; 14 | } 15 | 16 | typedef port-number { 17 | type uint32; 18 | } 19 | 20 | container acl-spec { 21 | list acl { 22 | key "destination"; 23 | leaf destination { 24 | type string; 25 | } 26 | leaf node { 27 | mandatory true; 28 | type leafref { 29 | path "/inv:nodes/inv:node/inv:id"; 30 | } 31 | } 32 | leaf ip-addr { 33 | type inet:ipv4-prefix; 34 | } 35 | leaf port { 36 | type port-number; 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /acl/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | org.sdnhub.odl.tutorial 9 | commons 10 | 1.2.0-SNAPSHOT 11 | ../commons/parent/ 12 | 13 | 14 | org.sdnhub.odl.tutorial.acl 15 | acl-parent 16 | 0.1.0-SNAPSHOT 17 | pom 18 | 19 | 20 | model 21 | implementation 22 | config 23 | 24 | 25 | -------------------------------------------------------------------------------- /commons/parent/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 3.0 7 | 8 | 9 | org.opendaylight.odlparent 10 | odlparent 11 | 1.6.1-Beryllium-SR1 12 | 13 | 14 | 15 | org.sdnhub.odl.tutorial 16 | commons 17 | SDN Hub Tutorial project common properties 18 | 1.2.0-SNAPSHOT 19 | pom 20 | http://sdnhub.org/tutorials/opendaylight 21 | 22 | 23 | 24 | http://nexus.opendaylight.org/content 25 | UTF-8 26 | 1.7 27 | 1.7 28 | true 29 | true 30 | src/main/yang-gen-code 31 | src/main/yang-gen-config 32 | 33 | 34 | 1.0.0-SNAPSHOT 35 | 1.0.0-SNAPSHOT 36 | 1.0.0-SNAPSHOT 37 | 1.0.0-SNAPSHOT 38 | 1.0.0-SNAPSHOT 39 | 1.0.0-SNAPSHOT 40 | 1.0.0-SNAPSHOT 41 | 1.0.0-SNAPSHOT 42 | 43 | 44 | 49-learning-switch-config.xml 45 | 50-tapapp-config.xml 46 | 51-acl-config.xml 47 | 51-netconf-exercise-config.xml 48 | 49 | 50 | 0.8.1-Beryllium-SR1 51 | 0.8.1-Beryllium-SR1 52 | 0.8.1-Beryllium-SR1 53 | 0.4.1-Beryllium-SR1 54 | 0.4.1-Beryllium-SR1 55 | 1.3.1-Beryllium-SR1 56 | 2013.10.21.8.1-Beryllium-SR1 57 | 2010.09.24.8.1-Beryllium-SR1 58 | 2010.09.24.8.1-Beryllium-SR1 59 | 2013.09.07.8.1-Beryllium-SR1 60 | 1.3.1-Beryllium-SR1 61 | 62 | 63 | 0.2.1-Beryllium-SR1 64 | 1.3.1-Beryllium-SR1 65 | 66 | 67 | 3.0.3 68 | 1.9.1 69 | 1.6.1-Beryllium-SR1 70 | 71 | 72 | 0.3.1-Beryllium-SR1 73 | 0.3.1-Beryllium-SR1 74 | 0.3.1-Beryllium-SR1 75 | 1.0.1-Beryllium-SR1 76 | 1.3.1-Beryllium-SR1 77 | 1.3.1-Beryllium-SR1 78 | 0.2.1-Beryllium-SR1 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | org.apache.maven.plugins 87 | maven-compiler-plugin 88 | 89 | ${java.version.source} 90 | ${java.version.target} 91 | ${java.version.source} 92 | ${java.version.target} 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | opendaylight-release 103 | opendaylight-release 104 | http://nexus.opendaylight.org/content/repositories/opendaylight.release/ 105 | 106 | true 107 | 108 | 109 | false 110 | 111 | 112 | 113 | 114 | opendaylight-snapshot 115 | opendaylight-snapshot 116 | http://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/ 117 | 118 | false 119 | 120 | 121 | true 122 | 123 | 124 | 125 | 126 | 127 | 128 | opendaylight-release 129 | opendaylight-release 130 | http://nexus.opendaylight.org/content/repositories/opendaylight.release/ 131 | 132 | false 133 | 134 | 135 | true 136 | 137 | 138 | 139 | opendaylight-snapshot 140 | opendaylight-snapshot 141 | http://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/ 142 | 143 | true 144 | 145 | 146 | false 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | org.opendaylight.mdsal.model 155 | ietf-yang-types 156 | ${ietf-yang-types.version} 157 | 158 | 159 | org.opendaylight.mdsal.model 160 | ietf-inet-types 161 | ${ietf-inet-types.version} 162 | 163 | 164 | org.opendaylight.mdsal.model 165 | yang-ext 166 | ${yang-ext.version} 167 | 168 | 169 | org.opendaylight.yangtools 170 | yang-common 171 | ${yangtools.version} 172 | 173 | 174 | org.opendaylight.mdsal 175 | yang-binding 176 | ${yang-binding.version} 177 | 178 | 179 | org.opendaylight.controller 180 | config-api 181 | ${config-api.version} 182 | 183 | 184 | org.opendaylight.controller 185 | sal-binding-config 186 | ${sal-binding.version} 187 | 188 | 189 | org.opendaylight.controller 190 | sal-binding-api 191 | ${sal-binding.version} 192 | 193 | 194 | 195 | -------------------------------------------------------------------------------- /commons/utils/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.sdnhub.odl.tutorial 6 | commons 7 | 1.2.0-SNAPSHOT 8 | ../../commons/parent/ 9 | 10 | 11 | org.sdnhub.odl.tutorial 12 | utils 13 | SDN Hub tutorial project common utils 14 | 1.0.0-SNAPSHOT 15 | bundle 16 | 17 | 18 | 19 | 20 | org.opendaylight.openflowplugin 21 | openflowplugin-api 22 | ${openflowplugin.version} 23 | 24 | 25 | 26 | 27 | 28 | 29 | org.apache.felix 30 | maven-bundle-plugin 31 | 2.4.0 32 | true 33 | 34 | 35 | 36 | false 37 | 38 | 39 | org.sdnhub.odl.tutorial.utils 40 | 41 | 42 | ${project.basedir}/META-INF 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /commons/utils/src/main/java/org/sdnhub/odl/tutorial/utils/GenericTransactionUtils.java: -------------------------------------------------------------------------------- 1 | package org.sdnhub.odl.tutorial.utils; 2 | 3 | import java.util.concurrent.ExecutionException; 4 | 5 | import org.opendaylight.controller.md.sal.binding.api.DataBroker; 6 | import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; 7 | import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; 8 | import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; 9 | import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; 10 | import org.opendaylight.yangtools.yang.binding.DataObject; 11 | import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | import com.google.common.base.Optional; 16 | import com.google.common.base.Preconditions; 17 | import com.google.common.util.concurrent.CheckedFuture; 18 | 19 | public final class GenericTransactionUtils { 20 | static final Logger logger = LoggerFactory.getLogger(GenericTransactionUtils.class); 21 | 22 | public static boolean writeData(DataBroker dataBroker, LogicalDatastoreType logicalDatastoreType, 23 | InstanceIdentifier iid, T dataObject, boolean isAdd) { 24 | Preconditions.checkNotNull(dataBroker); 25 | WriteTransaction modification = dataBroker.newWriteOnlyTransaction(); 26 | if (isAdd) { 27 | if (dataObject == null) { 28 | logger.warn("Invalid attempt to add a non-existent object to path {}", iid); 29 | return false; 30 | } 31 | modification.merge(logicalDatastoreType, iid, dataObject, true /*createMissingParents*/); 32 | } 33 | else { 34 | modification.delete(LogicalDatastoreType.CONFIGURATION, iid); 35 | } 36 | CheckedFuture commitFuture = modification.submit(); 37 | try { 38 | commitFuture.checkedGet(); 39 | logger.debug("Transaction success for {} of object {}", (isAdd) ? "add" : "delete", dataObject); 40 | return true; 41 | } catch (Exception e) { 42 | logger.error("Transaction failed with error {} for {} of object {}", e.getMessage(), (isAdd) ? "add" : "delete", dataObject); 43 | modification.cancel(); 44 | return false; 45 | } 46 | } 47 | 48 | public static T readData(DataBroker dataBroker, LogicalDatastoreType dataStoreType, InstanceIdentifier iid) { 49 | Preconditions.checkNotNull(dataBroker); 50 | ReadOnlyTransaction readTransaction = dataBroker.newReadOnlyTransaction(); 51 | try { 52 | Optional optionalData = readTransaction.read(dataStoreType, iid).get(); 53 | if (optionalData.isPresent()) { 54 | return (T)optionalData.get(); 55 | } 56 | } catch (ExecutionException | InterruptedException e) { 57 | logger.error("Read transaction for identifier {} failed with error {}", iid, e.getMessage()); 58 | readTransaction.close(); 59 | } 60 | return null; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /commons/utils/src/main/java/org/sdnhub/odl/tutorial/utils/PacketParsingUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at http://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | 9 | package org.sdnhub.odl.tutorial.utils; 10 | 11 | import java.util.Arrays; 12 | 13 | import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; 14 | 15 | /** 16 | * 17 | */ 18 | public abstract class PacketParsingUtils { 19 | 20 | /** 21 | * size of MAC address in octets (6*8 = 48 bits) 22 | */ 23 | private static final int MAC_ADDRESS_SIZE = 6; 24 | 25 | /** 26 | * start position of destination MAC address in array 27 | */ 28 | private static final int DST_MAC_START_POSITION = 0; 29 | 30 | /** 31 | * end position of destination MAC address in array 32 | */ 33 | private static final int DST_MAC_END_POSITION = 6; 34 | 35 | /** 36 | * start position of source MAC address in array 37 | */ 38 | private static final int SRC_MAC_START_POSITION = 6; 39 | 40 | /** 41 | * end position of source MAC address in array 42 | */ 43 | private static final int SRC_MAC_END_POSITION = 12; 44 | 45 | /** 46 | * start position of ethernet type in array 47 | */ 48 | private static final int ETHER_TYPE_START_POSITION = 12; 49 | 50 | /** 51 | * end position of ethernet type in array 52 | */ 53 | private static final int ETHER_TYPE_END_POSITION = 14; 54 | 55 | private PacketParsingUtils() { 56 | //prohibite to instantiate this class 57 | } 58 | 59 | /** 60 | * @param payload 61 | * @return destination MAC address 62 | */ 63 | public static byte[] extractDstMac(final byte[] payload) { 64 | return Arrays.copyOfRange(payload, DST_MAC_START_POSITION, DST_MAC_END_POSITION); 65 | } 66 | 67 | /** 68 | * @param payload 69 | * @return source MAC address 70 | */ 71 | public static byte[] extractSrcMac(final byte[] payload) { 72 | return Arrays.copyOfRange(payload, SRC_MAC_START_POSITION, SRC_MAC_END_POSITION); 73 | } 74 | 75 | /** 76 | * @param payload 77 | * @return source MAC address 78 | */ 79 | public static byte[] extractEtherType(final byte[] payload) { 80 | return Arrays.copyOfRange(payload, ETHER_TYPE_START_POSITION, ETHER_TYPE_END_POSITION); 81 | } 82 | 83 | /** 84 | * @param rawMac 85 | * @return {@link MacAddress} wrapping string value, baked upon binary MAC 86 | * address 87 | */ 88 | public static MacAddress rawMacToMac(final byte[] rawMac) { 89 | MacAddress mac = null; 90 | if (rawMac != null && rawMac.length == MAC_ADDRESS_SIZE) { 91 | StringBuilder sb = new StringBuilder(); 92 | for (byte octet : rawMac) { 93 | sb.append(String.format(":%02X", octet)); 94 | } 95 | mac = new MacAddress(sb.substring(1)); 96 | } 97 | return mac; 98 | } 99 | 100 | public static String rawMacToString(byte[] rawMac) { 101 | if (rawMac != null && rawMac.length == 6) { 102 | StringBuffer sb = new StringBuffer(); 103 | for (byte octet : rawMac) { 104 | sb.append(String.format(":%02X", octet)); 105 | } 106 | return sb.substring(1); 107 | } 108 | return null; 109 | } 110 | 111 | public static byte[] stringMacToRawMac(String address) { 112 | String[] elements = address.split(":"); 113 | if (elements.length != MAC_ADDRESS_SIZE) { 114 | throw new IllegalArgumentException( 115 | "Specified MAC Address must contain 12 hex digits" + 116 | " separated pairwise by :'s."); 117 | } 118 | 119 | byte[] addressInBytes = new byte[MAC_ADDRESS_SIZE]; 120 | for (int i = 0; i < MAC_ADDRESS_SIZE; i++) { 121 | String element = elements[i]; 122 | addressInBytes[i] = (byte)Integer.parseInt(element, 16); 123 | } 124 | return addressInBytes; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /commons/utils/src/main/java/org/sdnhub/odl/tutorial/utils/inventory/InventoryUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 SDN Hub 3 | 4 | Licensed under the GNU GENERAL PUBLIC LICENSE, Version 3. 5 | You may not use this file except in compliance with this License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.gnu.org/licenses/gpl-3.0.txt 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 13 | implied. 14 | 15 | * 16 | */ 17 | package org.sdnhub.odl.tutorial.utils.inventory; 18 | 19 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; 20 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; 21 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; 22 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; 23 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; 24 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder; 25 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; 26 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; 27 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; 28 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; 29 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; 30 | import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; 31 | 32 | public final class InventoryUtils { 33 | public static final String OPENFLOW_NODE_PREFIX = "openflow:"; 34 | 35 | public static NodeRef getNodeRef(NodeId nodeId) { 36 | return new NodeRef(InstanceIdentifier.builder(Nodes.class) 37 | .child(Node.class, new NodeKey(nodeId)) 38 | .build()); 39 | } 40 | 41 | public static NodeRef getNodeRef(NodeConnectorRef nodeConnectorRef) { 42 | InstanceIdentifier nodeIID = nodeConnectorRef.getValue() 43 | .firstIdentifierOf(Node.class); 44 | return new NodeRef(nodeIID); 45 | } 46 | 47 | public static NodeBuilder getNodeBuilder(NodeId nodeId) { 48 | NodeBuilder builder = new NodeBuilder() 49 | .setId(nodeId) 50 | .setKey(new NodeKey(nodeId)); 51 | return builder; 52 | } 53 | 54 | public static NodeBuilder getNodeBuilder(String dpid) { 55 | String nodeName = OPENFLOW_NODE_PREFIX + dpid; 56 | NodeBuilder builder = new NodeBuilder(); 57 | builder.setId(new NodeId(nodeName)); 58 | builder.setKey(new NodeKey(builder.getId())); 59 | return builder; 60 | } 61 | 62 | public static NodeId getNodeId(NodeConnectorRef nodeConnectorRef) { 63 | return nodeConnectorRef.getValue() 64 | .firstKeyOf(Node.class, NodeKey.class) 65 | .getId(); 66 | } 67 | 68 | public static NodeId getNodeId(NodeConnectorId nodeConnectorId) { 69 | if (nodeConnectorId == null) 70 | return null; 71 | String[] tokens = nodeConnectorId.getValue().split(":"); 72 | if (tokens.length == 3) 73 | return new NodeId(OPENFLOW_NODE_PREFIX + Long.parseLong(tokens[1])); 74 | else 75 | return null; 76 | } 77 | 78 | public static NodeConnectorId getNodeConnectorId(NodeId nodeId, long portNumber) { 79 | if (nodeId == null) 80 | return null; 81 | String nodeConnectorIdStr = nodeId.getValue() + ":" + portNumber; 82 | return new NodeConnectorId(nodeConnectorIdStr); 83 | } 84 | 85 | public static NodeConnectorRef getNodeConnectorRef(NodeConnectorId nodeConnectorId) { 86 | NodeId nodeId = getNodeId(nodeConnectorId); 87 | return new NodeConnectorRef(InstanceIdentifier.builder(Nodes.class) 88 | .child(Node.class, new NodeKey(nodeId)) 89 | .child(NodeConnector.class, new NodeConnectorKey(nodeConnectorId)) 90 | .build()); 91 | } 92 | 93 | public static NodeConnectorBuilder getNodeConnectorBuilder(NodeConnectorId nodeConnectorId) { 94 | NodeConnectorBuilder builder = new NodeConnectorBuilder() 95 | .setId(nodeConnectorId) 96 | .setKey(new NodeConnectorKey(nodeConnectorId)); 97 | return builder; 98 | } 99 | 100 | public static NodeConnectorId getNodeConnectorId(NodeConnectorRef nodeConnectorRef) { 101 | return nodeConnectorRef.getValue() 102 | .firstKeyOf(NodeConnector.class, NodeConnectorKey.class) 103 | .getId(); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /commons/utils/src/main/java/org/sdnhub/odl/tutorial/utils/openflow13/ActionUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Red Hat, Inc. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | */ 9 | package org.sdnhub.odl.tutorial.utils.openflow13; 10 | 11 | import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri; 12 | import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; 13 | import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId; 14 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action; 15 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DecMplsTtlCaseBuilder; 16 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DecNwTtlCaseBuilder; 17 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DropActionCaseBuilder; 18 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCaseBuilder; 19 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder; 20 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopMplsActionCaseBuilder; 21 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushMplsActionCaseBuilder; 22 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCaseBuilder; 23 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopVlanActionCaseBuilder; 24 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlDstActionCaseBuilder; 25 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlSrcActionCaseBuilder; 26 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetFieldCaseBuilder; 27 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetMplsTtlActionCaseBuilder; 28 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwDstActionCaseBuilder; 29 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwSrcActionCaseBuilder; 30 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwTtlActionCaseBuilder; 31 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.dec.mpls.ttl._case.DecMplsTtlBuilder; 32 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.dec.nw.ttl._case.DecNwTtlBuilder; 33 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.drop.action._case.DropActionBuilder; 34 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.group.action._case.GroupActionBuilder; 35 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder; 36 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.push.mpls.action._case.PushMplsActionBuilder; 37 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.push.vlan.action._case.PushVlanActionBuilder; 38 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.pop.mpls.action._case.PopMplsActionBuilder; 39 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.pop.vlan.action._case.PopVlanActionBuilder; 40 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.dl.dst.action._case.SetDlDstActionBuilder; 41 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.dl.src.action._case.SetDlSrcActionBuilder; 42 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.field._case.SetFieldBuilder; 43 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.mpls.ttl.action._case.SetMplsTtlActionBuilder; 44 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.dst.action._case.SetNwDstActionBuilder; 45 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.src.action._case.SetNwSrcActionBuilder; 46 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.ttl.action._case.SetNwTtlActionBuilder; 47 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.Address; 48 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; 49 | import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.ProtocolMatchFieldsBuilder; 50 | import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.TunnelBuilder; 51 | import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder; 52 | import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder; 53 | 54 | import com.google.common.net.InetAddresses; 55 | 56 | import java.math.BigInteger; 57 | 58 | public final class ActionUtils { 59 | public static Action dropAction() { 60 | return new DropActionCaseBuilder() 61 | .setDropAction(new DropActionBuilder() 62 | .build()) 63 | .build(); 64 | } 65 | 66 | public static Action outputAction(NodeConnectorId id) { 67 | return new OutputActionCaseBuilder() 68 | .setOutputAction(new OutputActionBuilder() 69 | .setOutputNodeConnector(new Uri(id.getValue())) 70 | .build()) 71 | .build(); 72 | } 73 | 74 | public static Action groupAction(Long id) { 75 | return new GroupActionCaseBuilder() 76 | .setGroupAction(new GroupActionBuilder() 77 | .setGroupId(id) 78 | .build()) 79 | .build(); 80 | } 81 | 82 | public static Action pushVlanAction(Integer ethernetType) { 83 | return new PushVlanActionCaseBuilder() 84 | .setPushVlanAction(new PushVlanActionBuilder() 85 | .setEthernetType(ethernetType) 86 | .build()) 87 | .build(); 88 | } 89 | 90 | public static Action popVlanAction() { 91 | return new PopVlanActionCaseBuilder() 92 | .setPopVlanAction(new PopVlanActionBuilder() 93 | .build()) 94 | .build(); 95 | } 96 | 97 | public static Action setVlanVidAction(Integer vlanId) { 98 | VlanMatchBuilder vlanMatchBuilder = new VlanMatchBuilder(); 99 | VlanIdBuilder vlanIdBuilder = new VlanIdBuilder(); 100 | vlanIdBuilder.setVlanId(new VlanId(vlanId)); 101 | vlanIdBuilder.setVlanIdPresent(true); 102 | vlanMatchBuilder.setVlanId(vlanIdBuilder.build()); 103 | SetFieldBuilder setFieldBuilder = new SetFieldBuilder() 104 | .setVlanMatch((vlanMatchBuilder.build())); 105 | 106 | return new SetFieldCaseBuilder() 107 | .setSetField(setFieldBuilder.build()) 108 | .build(); 109 | } 110 | 111 | public static Action pushMplsAction(Integer ethernetType) { 112 | return new PushMplsActionCaseBuilder() 113 | .setPushMplsAction(new PushMplsActionBuilder() 114 | .setEthernetType(ethernetType) 115 | .build()) 116 | .build(); 117 | } 118 | 119 | public static Action popMplsAction(Integer payloadEthernetType) { 120 | return new PopMplsActionCaseBuilder() 121 | .setPopMplsAction(new PopMplsActionBuilder() 122 | .setEthernetType(payloadEthernetType) 123 | .build()) 124 | .build(); 125 | } 126 | 127 | public static Action setMplsLabelBosAction(Long label, boolean bos) { 128 | ProtocolMatchFieldsBuilder matchFieldsBuilder = new ProtocolMatchFieldsBuilder() 129 | .setMplsLabel(label) 130 | .setMplsBos((short) (bos?1:0)); 131 | SetFieldBuilder setFieldBuilder = new SetFieldBuilder() 132 | .setProtocolMatchFields(matchFieldsBuilder.build()); 133 | return new SetFieldCaseBuilder() 134 | .setSetField(setFieldBuilder.build()) 135 | .build(); 136 | } 137 | 138 | public static Action setDlSrcAction(MacAddress mac) { 139 | return new SetDlSrcActionCaseBuilder() 140 | .setSetDlSrcAction(new SetDlSrcActionBuilder() 141 | .setAddress(mac) 142 | .build()) 143 | .build(); 144 | } 145 | 146 | public static Action setDlDstAction(MacAddress mac) { 147 | return new SetDlDstActionCaseBuilder() 148 | .setSetDlDstAction(new SetDlDstActionBuilder() 149 | .setAddress(mac) 150 | .build()) 151 | .build(); 152 | } 153 | 154 | public static Action setNwSrcAction(Address ip) { 155 | return new SetNwSrcActionCaseBuilder() 156 | .setSetNwSrcAction(new SetNwSrcActionBuilder() 157 | .setAddress(ip) 158 | .build()) 159 | .build(); 160 | } 161 | 162 | public static Action setNwDstAction(Address ip) { 163 | return new SetNwDstActionCaseBuilder() 164 | .setSetNwDstAction(new SetNwDstActionBuilder() 165 | .setAddress(ip) 166 | .build()) 167 | .build(); 168 | } 169 | 170 | public static Action SetNwTtlAction(Short ttlValue) { 171 | return new SetNwTtlActionCaseBuilder() 172 | .setSetNwTtlAction(new SetNwTtlActionBuilder() 173 | .setNwTtl(ttlValue) 174 | .build()) 175 | .build(); 176 | } 177 | 178 | public static Action decNwTtlAction() { 179 | return new DecNwTtlCaseBuilder() 180 | .setDecNwTtl(new DecNwTtlBuilder() 181 | .build()) 182 | .build(); 183 | } 184 | 185 | public static Action decMplsTtlAction() { 186 | return new DecMplsTtlCaseBuilder() 187 | .setDecMplsTtl(new DecMplsTtlBuilder() 188 | .build()) 189 | .build(); 190 | } 191 | 192 | public static Action SetMplsTtlAction(Short ttlValue) { 193 | return new SetMplsTtlActionCaseBuilder() 194 | .setSetMplsTtlAction(new SetMplsTtlActionBuilder() 195 | .setMplsTtl(ttlValue) 196 | .build()) 197 | .build(); 198 | } 199 | 200 | public static Action setTunnelIdAction(BigInteger tunnelId) { 201 | 202 | SetFieldBuilder setFieldBuilder = new SetFieldBuilder(); 203 | 204 | // Build the Set Tunnel Field Action 205 | TunnelBuilder tunnel = new TunnelBuilder(); 206 | tunnel.setTunnelId(tunnelId); 207 | setFieldBuilder.setTunnel(tunnel.build()); 208 | 209 | return new SetFieldCaseBuilder() 210 | .setSetField(setFieldBuilder.build()) 211 | .build(); 212 | } 213 | 214 | /** 215 | * Accepts a MAC address and returns the corresponding long, where the 216 | * MAC bytes are set on the lower order bytes of the long. 217 | * @param macAddress 218 | * @return a long containing the mac address bytes 219 | */ 220 | public static long toLong(byte[] macAddress) { 221 | long mac = 0; 222 | for (int i = 0; i < 6; i++) { 223 | long t = (macAddress[i] & 0xffL) << ((5-i)*8); 224 | mac |= t; 225 | } 226 | return mac; 227 | } 228 | 229 | /** 230 | * Accepts a MAC address of the form 00:aa:11:bb:22:cc, case does not 231 | * matter, and returns the corresponding long, where the MAC bytes are set 232 | * on the lower order bytes of the long. 233 | * 234 | * @param macAddress 235 | * in String format 236 | * @return a long containing the mac address bytes 237 | */ 238 | public static long toLong(MacAddress macAddress) { 239 | return toLong(toMACAddress(macAddress.getValue())); 240 | } 241 | 242 | /** 243 | * Accepts a MAC address of the form 00:aa:11:bb:22:cc, case does not 244 | * matter, and returns a corresponding byte[]. 245 | * @param macAddress 246 | * @return 247 | */ 248 | public static byte[] toMACAddress(String macAddress) { 249 | final String HEXES = "0123456789ABCDEF"; 250 | byte[] address = new byte[6]; 251 | String[] macBytes = macAddress.split(":"); 252 | if (macBytes.length != 6) 253 | throw new IllegalArgumentException( 254 | "Specified MAC Address must contain 12 hex digits" + 255 | " separated pairwise by :'s."); 256 | for (int i = 0; i < 6; ++i) { 257 | address[i] = (byte) ((HEXES.indexOf(macBytes[i].toUpperCase() 258 | .charAt(0)) << 4) | HEXES.indexOf(macBytes[i].toUpperCase() 259 | .charAt(1))); 260 | } 261 | return address; 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /distribution/karaf-branding/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | org.sdnhub.odl.tutorial.distribution 5 | distribution-parent 6 | 0.1.0-SNAPSHOT 7 | 8 | 4.0.0 9 | karaf-branding 10 | 1.0.0-SNAPSHOT 11 | bundle 12 | SDN Hub tutorial project Karaf branding 13 | 14 | 15 | 16 | org.apache.felix 17 | maven-bundle-plugin 18 | 2.4.0 19 | true 20 | 21 | 22 | ${project.artifactId} 23 | * 24 | !* 25 | org.apache.karaf.branding 26 | *;public-context:=false 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /distribution/karaf-branding/src/main/resources/org/apache/karaf/branding/branding.properties: -------------------------------------------------------------------------------- 1 | welcome = \ 2 | \u001B[36m _____ _____ _ _ _ _ _ \u001B[0m\r\n\ 3 | \u001B[36m / ____| __ \\| \\ | | | | | | | | \u001B[0m\r\n\ 4 | \u001B[36m | (___ | | | | \\| | | |__| |_ _| |__ \u001B[0m\r\n\ 5 | \u001B[36m \\___ \\| | | | . ` | | __ | | | | '_ \\ \u001B[0m\r\n\ 6 | \u001B[36m ____) | |__| | |\\ | | | | | |_| | |_) |\u001B[0m\r\n\ 7 | \u001B[36m |_____/|_____/|_| \\_| |_| |_|\\__,_|_.__/ \u001B[0m\r\n\ 8 | \r\n\ 9 | Hit '\u001B[1m\u001B[0m' for a list of available commands\r\n\ 10 | and '\u001B[1m[cmd] --help\u001B[0m' for help on a specific command.\r\n\ 11 | Hit '\u001B[1m\u001B[0m' or type '\u001B[1msystem:shutdown\u001B[0m' or '\u001B[1mlogout\u001B[0m' to shutdown OpenDaylight.\r\n 12 | prompt = \u001B[36mopendaylight-user\u001B[0m\u001B[1m@\u001B[0m\u001B[34m${APPLICATION}\u001B[0m> 13 | -------------------------------------------------------------------------------- /distribution/opendaylight-karaf/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.sdnhub.odl.tutorial.distribution 6 | distribution-parent 7 | 0.1.0-SNAPSHOT 8 | 9 | packaging 10 | 1.0.0-SNAPSHOT 11 | pom 12 | SDN Hub tutorial project distribution packaging 13 | 14 | 3.2 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | org.apache.karaf.features 23 | framework 24 | ${karaf.version} 25 | kar 26 | 27 | 28 | org.apache.karaf.features 29 | standard 30 | ${karaf.version} 31 | features 32 | xml 33 | runtime 34 | 35 | 36 | 37 | 38 | org.opendaylight.controller 39 | opendaylight-karaf-resources 40 | ${opendaylight-karaf-resources.version} 41 | 42 | 43 | org.sdnhub.odl.tutorial.distribution 44 | karaf-branding 45 | ${karaf-branding.version} 46 | 47 | 48 | 49 | 50 | org.sdnhub.odl.tutorial 51 | features 52 | ${feature.odl.tutorial.version} 53 | features 54 | xml 55 | runtime 56 | 57 | 58 | 59 | 60 | org.opendaylight.l2switch 61 | features-l2switch 62 | ${feature.l2switch.version} 63 | features 64 | xml 65 | runtime 66 | 67 | 68 | 69 | org.opendaylight.dlux 70 | features-dlux 71 | ${feature.dlux.version} 72 | features 73 | xml 74 | runtime 75 | 76 | 77 | 78 | org.opendaylight.aaa 79 | features-aaa 80 | ${feature.aaa.version} 81 | features 82 | xml 83 | runtime 84 | 85 | 86 | 87 | org.opendaylight.aaa 88 | features-aaa-authz 89 | ${feature.aaa.version} 90 | features 91 | xml 92 | runtime 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | org.eclipse.m2e 101 | lifecycle-mapping 102 | 1.0.0 103 | 104 | 105 | 106 | 107 | 108 | org.apache.felix 109 | maven-bundle-plugin 110 | [0,) 111 | 112 | cleanVersions 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | org.apache.maven.plugins 122 | maven-dependency-plugin 123 | [0,) 124 | 125 | copy 126 | unpack 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | org.apache.karaf.tooling 136 | karaf-maven-plugin 137 | [0,) 138 | 139 | commands-generate-help 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | org.fusesource.scalate 149 | maven-scalate-plugin 150 | [0,) 151 | 152 | sitegen 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | org.apache.servicemix.tooling 162 | depends-maven-plugin 163 | [0,) 164 | 165 | generate-depends-file 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | maven-resources-plugin 181 | 2.6 182 | 183 | 184 | copy-resources 185 | 186 | prepare-package 187 | 188 | copy-resources 189 | 190 | 191 | ${basedir}/target/assembly 192 | 193 | 194 | src/main/assembly 195 | 196 | 197 | true 198 | 199 | 200 | 201 | 202 | 203 | org.apache.karaf.tooling 204 | karaf-maven-plugin 205 | true 206 | 207 | 208 | 209 | standard 210 | sdnhub-tutorial-tapapp 211 | 212 | 213 | 214 | 215 | 216 | populate-system 217 | generate-resources 218 | 219 | features-add-to-repository 220 | 221 | 222 | 223 | mvn:org.apache.karaf.features/standard/${karaf.version}/xml/features 224 | 225 | 226 | standard 227 | config 228 | package 229 | kar 230 | ssh 231 | management 232 | war 233 | 234 | target/assembly/system 235 | 236 | 237 | 238 | process-resources 239 | 240 | install-kars 241 | 242 | process-resources 243 | 244 | 245 | package 246 | 247 | instance-create-archive 248 | 249 | 250 | 251 | 252 | 253 | org.apache.maven.plugins 254 | maven-checkstyle-plugin 255 | ${checkstyle.version} 256 | 257 | **\/target\/,**\/bin\/,**\/target-ide\/,**\/configuration\/initial\/ 258 | 259 | 260 | 261 | org.apache.maven.plugins 262 | maven-dependency-plugin 263 | 2.8 264 | 265 | 266 | copy 267 | 268 | copy 269 | 270 | 271 | generate-resources 272 | 273 | 274 | 275 | org.sdnhub.odl.tutorial.distribution 276 | karaf-branding 277 | ${karaf.branding.version} 278 | target/assembly/lib 279 | karaf-branding-${karaf.branding.version}.jar 280 | 281 | 282 | 283 | 284 | 285 | unpack-karaf-resources 286 | 287 | unpack-dependencies 288 | 289 | prepare-package 290 | 291 | ${project.build.directory}/assembly 292 | org.opendaylight.controller 293 | opendaylight-karaf-resources 294 | META-INF\/** 295 | true 296 | false 297 | 298 | 299 | 300 | copy-dependencies 301 | prepare-package 302 | 303 | copy-dependencies 304 | 305 | 306 | ${project.build.directory}/assembly/system 307 | distribution.vtn-coordinator 308 | false 309 | true 310 | true 311 | true 312 | true 313 | true 314 | 315 | 316 | 317 | copy-externalapps 318 | prepare-package 319 | 320 | copy-dependencies 321 | 322 | 323 | ${project.build.directory}/assembly/externalapps 324 | distribution.vtn-coordinator 325 | false 326 | true 327 | true 328 | true 329 | 330 | 331 | 332 | 333 | 334 | org.apache.maven.plugins 335 | maven-antrun-plugin 336 | 337 | 338 | prepare-package 339 | 340 | run 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | -------------------------------------------------------------------------------- /distribution/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | org.sdnhub.odl.tutorial 9 | commons 10 | 1.2.0-SNAPSHOT 11 | ../commons/parent/ 12 | 13 | 14 | org.sdnhub.odl.tutorial.distribution 15 | distribution-parent 16 | 0.1.0-SNAPSHOT 17 | pom 18 | 19 | 20 | karaf-branding 21 | opendaylight-karaf 22 | 23 | 24 | -------------------------------------------------------------------------------- /features/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.sdnhub.odl.tutorial 6 | commons 7 | 1.2.0-SNAPSHOT 8 | ../commons/parent 9 | 10 | features 11 | SDN Hub tutorial project features 12 | 1.0.0-SNAPSHOT 13 | jar 14 | 15 | features.xml 16 | 17 | 18 | 19 | 20 | org.opendaylight.netconf 21 | features-restconf 22 | ${feature.restconf.version} 23 | features 24 | xml 25 | 26 | 27 | org.opendaylight.controller 28 | features-mdsal 29 | ${feature.mdsal.version} 30 | features 31 | xml 32 | 33 | 34 | org.opendaylight.openflowplugin 35 | features-openflowplugin 36 | ${feature.openflowplugin.version} 37 | features 38 | xml 39 | 40 | 41 | org.opendaylight.netconf 42 | features-netconf-connector 43 | ${feature.netconf.connector.version} 44 | features 45 | xml 46 | 47 | 48 | 49 | 50 | org.sdnhub.odl.tutorial.tapapp 51 | tapapp-config 52 | ${tapapp.version} 53 | xml 54 | config 55 | 56 | 57 | org.sdnhub.odl.tutorial.tapapp 58 | tapapp-model 59 | ${tapapp.version} 60 | 61 | 62 | org.sdnhub.odl.tutorial.tapapp 63 | tapapp-impl 64 | ${tapapp.version} 65 | 66 | 67 | 68 | org.sdnhub.odl.tutorial.learning-switch 69 | learning-switch-config 70 | ${learning-switch.version} 71 | xml 72 | config 73 | 74 | 75 | org.sdnhub.odl.tutorial.learning-switch 76 | learning-switch-impl 77 | ${learning-switch.version} 78 | 79 | 80 | 81 | org.sdnhub.odl.tutorial.acl 82 | acl-config 83 | ${acl.version} 84 | xml 85 | config 86 | 87 | 88 | org.sdnhub.odl.tutorial.acl 89 | acl-impl 90 | ${acl.version} 91 | 92 | 93 | org.sdnhub.odl.tutorial.acl 94 | acl-model 95 | ${acl.version} 96 | 97 | 98 | 99 | org.sdnhub.odl.tutorial.netconf-exercise 100 | netconf-exercise-config 101 | ${netconf-exercise.version} 102 | xml 103 | config 104 | 105 | 106 | org.sdnhub.odl.tutorial.netconf-exercise 107 | netconf-exercise-model 108 | ${netconf-exercise.version} 109 | 110 | 111 | org.sdnhub.odl.tutorial.netconf-exercise 112 | netconf-exercise-impl 113 | ${netconf-exercise.version} 114 | 115 | 116 | 117 | 118 | 119 | true 120 | src/main/resources 121 | 122 | 123 | 124 | 125 | org.apache.maven.plugins 126 | maven-resources-plugin 127 | 128 | 129 | filter 130 | 131 | resources 132 | 133 | generate-resources 134 | 135 | 136 | 137 | 138 | org.codehaus.mojo 139 | build-helper-maven-plugin 140 | 141 | 142 | attach-artifacts 143 | 144 | attach-artifact 145 | 146 | package 147 | 148 | 149 | 150 | ${project.build.directory}/classes/${features.file} 151 | xml 152 | features 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | org.apache.maven.plugins 161 | maven-surefire-plugin 162 | 163 | ${skip.karaf} 164 | 165 | org.opendaylight.controller 166 | opendaylight-karaf-empty 167 | ${opendaylight-karaf-empty.version} 168 | 169 | 172 | 173 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /features/src/main/resources/features.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | mvn:org.opendaylight.controller/features-mdsal/${feature.mdsal.version}/xml/features 4 | mvn:org.opendaylight.netconf/features-restconf/${feature.restconf.version}/xml/features 5 | mvn:org.opendaylight.netconf/features-netconf-connector/${feature.netconf.connector.version}/xml/features 6 | mvn:org.opendaylight.openflowplugin/features-openflowplugin/${feature.openflowplugin.version}/xml/features 7 | 8 | 9 | odl-mdsal-broker 10 | odl-netconf-connector-all 11 | mvn:org.sdnhub.odl.tutorial.netconf-exercise/netconf-exercise-impl/${netconf-exercise.version} 12 | mvn:org.sdnhub.odl.tutorial.netconf-exercise/netconf-exercise-model/${netconf-exercise.version} 13 | mvn:org.sdnhub.odl.tutorial.netconf-exercise/netconf-exercise-config/${netconf-exercise.version}/xml/config 14 | 15 | 16 | 17 | odl-openflowplugin-southbound 18 | odl-openflowplugin-flow-services 19 | odl-mdsal-broker 20 | mvn:org.sdnhub.odl.tutorial.tapapp/tapapp-impl/${tapapp.version} 21 | mvn:org.sdnhub.odl.tutorial.tapapp/tapapp-model/${tapapp.version} 22 | mvn:org.sdnhub.odl.tutorial.tapapp/tapapp-config/${tapapp.version}/xml/config 23 | 24 | 25 | 26 | odl-openflowplugin-southbound 27 | odl-openflowplugin-flow-services 28 | odl-mdsal-broker 29 | mvn:org.sdnhub.odl.tutorial.learning-switch/learning-switch-impl/${learning-switch.version} 30 | mvn:org.sdnhub.odl.tutorial.learning-switch/learning-switch-config/${learning-switch.version}/xml/config 31 | 32 | 33 | 34 | odl-openflowplugin-southbound 35 | odl-openflowplugin-flow-services 36 | odl-mdsal-broker 37 | mvn:org.sdnhub.odl.tutorial.acl/acl-impl/${acl.version} 38 | mvn:org.sdnhub.odl.tutorial.acl/acl-model/${acl.version} 39 | mvn:org.sdnhub.odl.tutorial.acl/acl-config/${acl.version}/xml/config 40 | 41 | 42 | -------------------------------------------------------------------------------- /learning-switch/config/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.sdnhub.odl.tutorial 7 | commons 8 | 1.2.0-SNAPSHOT 9 | ../../commons/parent/pom.xml 10 | 11 | 12 | org.sdnhub.odl.tutorial.learning-switch 13 | learning-switch-config 14 | 1.0.0-SNAPSHOT 15 | SDN Hub tutorial project Learning Switch Config 16 | 17 | jar 18 | 19 | 20 | 21 | org.codehaus.mojo 22 | build-helper-maven-plugin 23 | ${build.plugins.plugin.version} 24 | 25 | 26 | attach-artifacts 27 | 28 | attach-artifact 29 | 30 | package 31 | 32 | 33 | 34 | ${project.build.directory}/classes/initial/${learning-switch.configfile} 35 | xml 36 | config 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /learning-switch/config/src/main/resources/initial/49-learning-switch-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | prefix:learning-switch-impl 9 | learning-switch-impl 10 | 11 | 12 | binding:binding-notification-service 13 | binding-notification-broker 14 | 15 | 16 | binding:binding-async-data-broker 17 | binding-data-broker 18 | 19 | 20 | binding:binding-rpc-registry 21 | binding-rpc-broker 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | urn:sdnhub:odl:tutorial:learning-switch:learning-switch-impl?module=learning-switch-impl&revision=2015-06-05 30 | urn:opendaylight:params:xml:ns:yang:openflow:common:config:impl?module=openflow-provider-impl&revision=2014-03-26 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /learning-switch/implementation/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.sdnhub.odl.tutorial.learning-switch 6 | learning-switch-parent 7 | 0.1.0-SNAPSHOT 8 | 9 | 10 | learning-switch-impl 11 | SDN Hub tutorial project learning switch Impl 12 | 1.0.0-SNAPSHOT 13 | bundle 14 | 15 | 16 | 17 | org.sdnhub.odl.tutorial 18 | utils 19 | ${utils.version} 20 | 21 | 22 | org.opendaylight.openflowplugin.model 23 | model-flow-service 24 | ${openflowplugin.version} 25 | 26 | 27 | 28 | 29 | 30 | org.opendaylight.yangtools 31 | yang-maven-plugin 32 | ${yangtools.version} 33 | 34 | 35 | 36 | generate-sources 37 | 38 | 39 | src/main/yang 40 | 41 | 42 | org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl 43 | ${codeGeneratorPath} 44 | 45 | 46 | org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator 47 | ${configCodeGeneratorPath} 48 | 49 | urn:sdnhub:odl:tutorial:learning-switch:learning-switch-impl==org.sdnhub.odl.tutorial.learningswitch.impl 50 | urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang 51 | 52 | 53 | 54 | org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl 55 | ${project.build.directory}/site/models 56 | 57 | 58 | true 59 | 60 | 61 | 62 | 63 | 64 | org.opendaylight.mdsal 65 | maven-sal-api-gen-plugin 66 | ${maven-sal-api-gen-plugin.version} 67 | jar 68 | 69 | 70 | org.opendaylight.controller 71 | yang-jmx-generator-plugin 72 | ${yang.jmx.version} 73 | 74 | 75 | 76 | 77 | org.apache.felix 78 | maven-bundle-plugin 79 | 2.4.0 80 | true 81 | 82 | 83 | * 84 | utils 85 | 86 | ${project.basedir}/META-INF 87 | 88 | 89 | 91 | 92 | org.codehaus.mojo 93 | build-helper-maven-plugin 94 | 1.8 95 | 96 | 97 | add-source 98 | 99 | add-source 100 | 101 | generate-sources 102 | 103 | 104 | src/main/yang 105 | ${codeGeneratorPath} 106 | ${configCodeGeneratorPath} 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | maven-clean-plugin 115 | 116 | 117 | 118 | ${codeGeneratorPath} 119 | 120 | ** 121 | 122 | 123 | 124 | ${configCodeGeneratorPath} 125 | 126 | ** 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /learning-switch/implementation/src/main/java/org/sdnhub/odl/tutorial/learningswitch/impl/TutorialL2Forwarding.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 SDN Hub 3 | 4 | Licensed under the GNU GENERAL PUBLIC LICENSE, Version 3. 5 | You may not use this file except in compliance with this License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.gnu.org/licenses/gpl-3.0.txt 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 13 | implied. 14 | 15 | * 16 | */ 17 | 18 | package org.sdnhub.odl.tutorial.learningswitch.impl; 19 | 20 | import java.nio.ByteBuffer; 21 | import java.util.HashMap; 22 | import java.util.List; 23 | import java.util.Map; 24 | 25 | import org.opendaylight.controller.md.sal.binding.api.DataBroker; 26 | import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; 27 | import org.opendaylight.controller.sal.binding.api.NotificationProviderService; 28 | import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; 29 | import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; 30 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action; 31 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder; 32 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder; 33 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder; 34 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey; 35 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; 36 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; 37 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; 38 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; 39 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; 40 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder; 41 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey; 42 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder; 43 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; 44 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder; 45 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder; 46 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; 47 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder; 48 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey; 49 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; 50 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; 51 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; 52 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; 53 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; 54 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; 55 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; 56 | import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener; 57 | import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService; 58 | import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived; 59 | import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput; 60 | import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder; 61 | import org.opendaylight.yangtools.concepts.Registration; 62 | import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; 63 | import org.sdnhub.odl.tutorial.utils.GenericTransactionUtils; 64 | import org.sdnhub.odl.tutorial.utils.PacketParsingUtils; 65 | import org.sdnhub.odl.tutorial.utils.inventory.InventoryUtils; 66 | import org.sdnhub.odl.tutorial.utils.openflow13.MatchUtils; 67 | import org.slf4j.Logger; 68 | import org.slf4j.LoggerFactory; 69 | 70 | import com.google.common.base.Preconditions; 71 | import com.google.common.collect.Lists; 72 | 73 | public class TutorialL2Forwarding implements AutoCloseable, PacketProcessingListener { 74 | private final Logger LOG = LoggerFactory.getLogger(this.getClass()); 75 | private final static long FLOOD_PORT_NUMBER = 0xfffffffbL; 76 | 77 | //Members specific to this class 78 | private Map macTable = new HashMap (); 79 | private String function = "hub"; 80 | 81 | //Members related to MD-SAL operations 82 | private List registrations; 83 | private DataBroker dataBroker; 84 | private PacketProcessingService packetProcessingService; 85 | 86 | public TutorialL2Forwarding(DataBroker dataBroker, NotificationProviderService notificationService, RpcProviderRegistry rpcProviderRegistry) { 87 | //Store the data broker for reading/writing from inventory store 88 | this.dataBroker = dataBroker; 89 | 90 | //Get access to the packet processing service for making RPC calls later 91 | this.packetProcessingService = rpcProviderRegistry.getRpcService(PacketProcessingService.class); 92 | 93 | //List used to track notification (both data change and YANG-defined) listener registrations 94 | this.registrations = Lists.newArrayList(); 95 | 96 | //Register this object for receiving notifications when there are PACKET_INs 97 | registrations.add(notificationService.registerNotificationListener(this)); 98 | } 99 | 100 | @Override 101 | public void close() throws Exception { 102 | for (Registration registration : registrations) { 103 | registration.close(); 104 | } 105 | registrations.clear(); 106 | } 107 | 108 | @Override 109 | public void onPacketReceived(PacketReceived notification) { 110 | LOG.trace("Received packet notification {}", notification.getMatch()); 111 | 112 | NodeConnectorRef ingressNodeConnectorRef = notification.getIngress(); 113 | NodeRef ingressNodeRef = InventoryUtils.getNodeRef(ingressNodeConnectorRef); 114 | NodeConnectorId ingressNodeConnectorId = InventoryUtils.getNodeConnectorId(ingressNodeConnectorRef); 115 | NodeId ingressNodeId = InventoryUtils.getNodeId(ingressNodeConnectorRef); 116 | 117 | // Useful to create it beforehand 118 | NodeConnectorId floodNodeConnectorId = InventoryUtils.getNodeConnectorId(ingressNodeId, FLOOD_PORT_NUMBER); 119 | NodeConnectorRef floodNodeConnectorRef = InventoryUtils.getNodeConnectorRef(floodNodeConnectorId); 120 | 121 | /* 122 | * Logic: 123 | * 0. Ignore LLDP packets 124 | * 1. If behaving as "hub", perform a PACKET_OUT with FLOOD action 125 | * 2. Else if behaving as "learning switch", 126 | * 2.1. Extract MAC addresses 127 | * 2.2. Update MAC table with source MAC address 128 | * 2.3. Lookup in MAC table for the target node connector of dst_mac 129 | * 2.3.1 If found, 130 | * 2.3.1.1 perform FLOW_MOD for that dst_mac through the target node connector 131 | * 2.3.1.2 perform PACKET_OUT of this packet to target node connector 132 | * 2.3.2 If not found, perform a PACKET_OUT with FLOOD action 133 | */ 134 | 135 | //Ignore LLDP packets, or you will be in big trouble 136 | byte[] etherTypeRaw = PacketParsingUtils.extractEtherType(notification.getPayload()); 137 | int etherType = (0x0000ffff & ByteBuffer.wrap(etherTypeRaw).getShort()); 138 | if (etherType == 0x88cc) { 139 | return; 140 | } 141 | 142 | // Hub implementation 143 | if (function.equals("hub")) { 144 | 145 | //flood packet (1) 146 | packetOut(ingressNodeRef, floodNodeConnectorRef, notification.getPayload()); 147 | } else { 148 | //TODO: Extract payload 149 | 150 | //TODO: Extract MAC address (2.1) 151 | byte[] payload = notification.getPayload(); 152 | byte[] dstMacRaw = PacketParsingUtils.extractDstMac(payload); 153 | byte[] srcMacRaw = PacketParsingUtils.extractSrcMac(payload); 154 | 155 | String srcMac = PacketParsingUtils.rawMacToString(srcMacRaw); 156 | String dstMac = PacketParsingUtils.rawMacToString(dstMacRaw); 157 | 158 | //TODO: Learn source MAC address (2.2) 159 | 160 | //TODO: Lookup destination MAC address in table (2.3) 161 | NodeConnectorId egressNodeConnectorId = null; 162 | 163 | //TODO: If found (2.3.1) 164 | if (egressNodeConnectorId != null) { 165 | //TODO: 2.3.1.1 perform FLOW_MOD for that dst_mac through the target node connector 166 | //TODO: 2.3.1.2 perform PACKET_OUT of this packet to target node connector 167 | } else { 168 | //2.3.2 Flood packet 169 | packetOut(ingressNodeRef, floodNodeConnectorRef, payload); 170 | } 171 | } 172 | } 173 | 174 | private void packetOut(NodeRef egressNodeRef, NodeConnectorRef egressNodeConnectorRef, byte[] payload) { 175 | Preconditions.checkNotNull(packetProcessingService); 176 | LOG.debug("Flooding packet of size {} out of port {}", payload.length, egressNodeConnectorRef); 177 | 178 | //Construct input for RPC call to packet processing service 179 | TransmitPacketInput input = new TransmitPacketInputBuilder() 180 | .setPayload(payload) 181 | .setNode(egressNodeRef) 182 | .setEgress(egressNodeConnectorRef) 183 | .build(); 184 | packetProcessingService.transmitPacket(input); 185 | } 186 | 187 | private void programL2Flow(NodeId nodeId, String dstMac, NodeConnectorId ingressNodeConnectorId, NodeConnectorId egressNodeConnectorId) { 188 | 189 | /* Programming a flow involves: 190 | * 1. Creating a Flow object that has a match and a list of instructions, 191 | * 2. Adding Flow object as an augmentation to the Node object in the inventory. 192 | * 3. FlowProgrammer module of OpenFlowPlugin will pick up this data change and eventually program the switch. 193 | */ 194 | 195 | //Creating match object 196 | MatchBuilder matchBuilder = new MatchBuilder(); 197 | //MatchUtils.createEthDstMatch(matchBuilder, ..., null); 198 | //MatchUtils.createInPortMatch(matchBuilder, ...); 199 | 200 | /* 201 | * Instructions List Stores Individual Instructions 202 | InstructionsBuilder isb = new InstructionsBuilder(); 203 | List instructions = Lists.newArrayList(); 204 | InstructionBuilder ib = new InstructionBuilder(); 205 | ApplyActionsBuilder aab = new ApplyActionsBuilder(); 206 | ActionBuilder ab = new ActionBuilder(); 207 | List actionList = Lists.newArrayList(); 208 | */ 209 | 210 | /* 211 | * Set output action 212 | OutputActionBuilder output = new OutputActionBuilder(); 213 | output.setOutputNodeConnector(egressNodeConnectorId); 214 | output.setMaxLength(65535); //Send full packet and No buffer 215 | ab.setAction(new OutputActionCaseBuilder().setOutputAction(output.build()).build()); 216 | ab.setOrder(0); 217 | ab.setKey(new ActionKey(0)); 218 | actionList.add(ab.build()); 219 | */ 220 | 221 | /* 222 | * Create Apply Actions Instruction 223 | aab.setAction(actionList); 224 | ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build()); 225 | ib.setOrder(0); 226 | ib.setKey(new InstructionKey(0)); 227 | instructions.add(ib.build()); 228 | */ 229 | 230 | /* 231 | * Create Flow 232 | String flowId = "L2_Rule_" + dstMac; 233 | FlowBuilder flowBuilder = new FlowBuilder(); 234 | flowBuilder.setMatch(matchBuilder.build()); 235 | flowBuilder.setId(new FlowId(flowId)); 236 | FlowKey key = new FlowKey(new FlowId(flowId)); 237 | flowBuilder.setBarrier(true); 238 | flowBuilder.setTableId((short)0); 239 | flowBuilder.setKey(key); 240 | flowBuilder.setPriority(32768); 241 | flowBuilder.setFlowName(flowId); 242 | flowBuilder.setHardTimeout(0); 243 | flowBuilder.setIdleTimeout(0); 244 | flowBuilder.setInstructions(isb.setInstruction(instructions).build()); 245 | */ 246 | 247 | /* Perform transaction to store rule 248 | * 249 | InstanceIdentifier flowIID = InstanceIdentifier.builder(Nodes.class) 250 | .child(Node.class, new NodeKey(nodeId)) 251 | .augmentation(FlowCapableNode.class) 252 | .child(Table.class, new TableKey(flowBuilder.getTableId())) 253 | .child(Flow.class, flowBuilder.getKey()) 254 | .build(); 255 | GenericTransactionUtils.writeData(dataBroker, LogicalDatastoreType.CONFIGURATION, flowIID, flowBuilder.build(), true); 256 | */ 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /learning-switch/implementation/src/main/java/org/sdnhub/odl/tutorial/learningswitch/impl/TutorialL2Forwarding.single_switch.solution: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 SDN Hub 3 | 4 | Licensed under the GNU GENERAL PUBLIC LICENSE, Version 3. 5 | You may not use this file except in compliance with this License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.gnu.org/licenses/gpl-3.0.txt 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 13 | implied. 14 | 15 | * 16 | */ 17 | 18 | package org.sdnhub.odl.tutorial.learningswitch.impl; 19 | 20 | import java.nio.ByteBuffer; 21 | import java.util.HashMap; 22 | import java.util.List; 23 | import java.util.Map; 24 | 25 | import org.opendaylight.controller.md.sal.binding.api.DataBroker; 26 | import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; 27 | import org.opendaylight.controller.sal.binding.api.NotificationProviderService; 28 | import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; 29 | import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; 30 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action; 31 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder; 32 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder; 33 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder; 34 | import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey; 35 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; 36 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; 37 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; 38 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; 39 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; 40 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder; 41 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey; 42 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder; 43 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; 44 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder; 45 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder; 46 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; 47 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder; 48 | import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey; 49 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; 50 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; 51 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; 52 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; 53 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; 54 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; 55 | import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; 56 | import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener; 57 | import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService; 58 | import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived; 59 | import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput; 60 | import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder; 61 | import org.opendaylight.yangtools.concepts.Registration; 62 | import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; 63 | import org.sdnhub.odl.tutorial.utils.GenericTransactionUtils; 64 | import org.sdnhub.odl.tutorial.utils.PacketParsingUtils; 65 | import org.sdnhub.odl.tutorial.utils.inventory.InventoryUtils; 66 | import org.sdnhub.odl.tutorial.utils.openflow13.MatchUtils; 67 | import org.slf4j.Logger; 68 | import org.slf4j.LoggerFactory; 69 | 70 | import com.google.common.base.Preconditions; 71 | import com.google.common.collect.Lists; 72 | 73 | public class TutorialL2Forwarding implements AutoCloseable, PacketProcessingListener { 74 | private final Logger LOG = LoggerFactory.getLogger(this.getClass()); 75 | private final static long FLOOD_PORT_NUMBER = 0xfffffffbL; 76 | 77 | //Members specific to this class 78 | private Map macTable = new HashMap (); 79 | private String function = "hub"; 80 | 81 | //Members related to MD-SAL operations 82 | private List registrations; 83 | private DataBroker dataBroker; 84 | private PacketProcessingService packetProcessingService; 85 | 86 | public TutorialL2Forwarding(DataBroker dataBroker, NotificationProviderService notificationService, RpcProviderRegistry rpcProviderRegistry) { 87 | //Store the data broker for reading/writing from inventory store 88 | this.dataBroker = dataBroker; 89 | 90 | //Get access to the packet processing service for making RPC calls later 91 | this.packetProcessingService = rpcProviderRegistry.getRpcService(PacketProcessingService.class); 92 | 93 | //List used to track notification (both data change and YANG-defined) listener registrations 94 | this.registrations = Lists.newArrayList(); 95 | 96 | //Register this object for receiving notifications when there are PACKET_INs 97 | registrations.add(notificationService.registerNotificationListener(this)); 98 | } 99 | 100 | @Override 101 | public void close() throws Exception { 102 | for (Registration registration : registrations) { 103 | registration.close(); 104 | } 105 | registrations.clear(); 106 | } 107 | 108 | @Override 109 | public void onPacketReceived(PacketReceived notification) { 110 | LOG.trace("Received packet notification {}", notification.getMatch()); 111 | 112 | NodeConnectorRef ingressNodeConnectorRef = notification.getIngress(); 113 | NodeRef ingressNodeRef = InventoryUtils.getNodeRef(ingressNodeConnectorRef); 114 | NodeConnectorId ingressNodeConnectorId = InventoryUtils.getNodeConnectorId(ingressNodeConnectorRef); 115 | NodeId ingressNodeId = InventoryUtils.getNodeId(ingressNodeConnectorRef); 116 | 117 | // Useful to create it beforehand 118 | NodeConnectorId floodNodeConnectorId = InventoryUtils.getNodeConnectorId(ingressNodeId, FLOOD_PORT_NUMBER); 119 | NodeConnectorRef floodNodeConnectorRef = InventoryUtils.getNodeConnectorRef(floodNodeConnectorId); 120 | 121 | /* 122 | * Logic: 123 | * 0. Ignore LLDP packets 124 | * 1. If behaving as "hub", perform a PACKET_OUT with FLOOD action 125 | * 2. Else if behaving as "learning switch", 126 | * 2.1. Extract MAC addresses 127 | * 2.2. Update MAC table with source MAC address 128 | * 2.3. Lookup in MAC table for the target node connector of dst_mac 129 | * 2.3.1 If found, 130 | * 2.3.1.1 perform FLOW_MOD for that dst_mac through the target node connector 131 | * 2.3.1.2 perform PACKET_OUT of this packet to target node connector 132 | * 2.3.2 If not found, perform a PACKET_OUT with FLOOD action 133 | */ 134 | 135 | //Ignore LLDP packets, or you will be in big trouble 136 | byte[] etherTypeRaw = PacketParsingUtils.extractEtherType(notification.getPayload()); 137 | int etherType = (0x0000ffff & ByteBuffer.wrap(etherTypeRaw).getShort()); 138 | if (etherType == 0x88cc) { 139 | return; 140 | } 141 | 142 | // Hub implementation 143 | if (function.equals("hub")) { 144 | 145 | //flood packet (1) 146 | packetOut(ingressNodeRef, floodNodeConnectorRef, notification.getPayload()); 147 | } else { 148 | byte[] payload = notification.getPayload(); 149 | byte[] dstMacRaw = PacketParsingUtils.extractDstMac(payload); 150 | byte[] srcMacRaw = PacketParsingUtils.extractSrcMac(payload); 151 | 152 | //Extract MAC addresses (2.1) 153 | String srcMac = PacketParsingUtils.rawMacToString(srcMacRaw); 154 | String dstMac = PacketParsingUtils.rawMacToString(dstMacRaw); 155 | 156 | //Learn source MAC address (2.2) 157 | this.macTable.put(srcMac, ingressNodeConnectorId); 158 | 159 | //Lookup destination MAC address in table (2.3) 160 | NodeConnectorId egressNodeConnectorId = this.macTable.get(dstMac) ; 161 | 162 | //If found (2.3.1) 163 | if (egressNodeConnectorId != null) { 164 | programL2Flow(ingressNodeId, dstMac, ingressNodeConnectorId, egressNodeConnectorId); 165 | NodeConnectorRef egressNodeConnectorRef = InventoryUtils.getNodeConnectorRef(egressNodeConnectorId); 166 | packetOut(ingressNodeRef, egressNodeConnectorRef, payload); 167 | } else { 168 | //2.3.2 Flood packet 169 | packetOut(ingressNodeRef, floodNodeConnectorRef, payload); 170 | } 171 | } 172 | } 173 | 174 | private void packetOut(NodeRef egressNodeRef, NodeConnectorRef egressNodeConnectorRef, byte[] payload) { 175 | Preconditions.checkNotNull(packetProcessingService); 176 | LOG.debug("Flooding packet of size {} out of port {}", payload.length, egressNodeConnectorRef); 177 | 178 | //Construct input for RPC call to packet processing service 179 | TransmitPacketInput input = new TransmitPacketInputBuilder() 180 | .setPayload(payload) 181 | .setNode(egressNodeRef) 182 | .setEgress(egressNodeConnectorRef) 183 | .build(); 184 | packetProcessingService.transmitPacket(input); 185 | } 186 | 187 | private void programL2Flow(NodeId nodeId, String dstMac, NodeConnectorId ingressNodeConnectorId, NodeConnectorId egressNodeConnectorId) { 188 | 189 | /* Programming a flow involves: 190 | * 1. Creating a Flow object that has a match and a list of instructions, 191 | * 2. Adding Flow object as an augmentation to the Node object in the inventory. 192 | * 3. FlowProgrammer module of OpenFlowPlugin will pick up this data change and eventually program the switch. 193 | */ 194 | 195 | //Creating match object 196 | MatchBuilder matchBuilder = new MatchBuilder(); 197 | MatchUtils.createEthDstMatch(matchBuilder, new MacAddress(dstMac), null); 198 | MatchUtils.createInPortMatch(matchBuilder, ingressNodeConnectorId); 199 | 200 | // Instructions List Stores Individual Instructions 201 | InstructionsBuilder isb = new InstructionsBuilder(); 202 | List instructions = Lists.newArrayList(); 203 | InstructionBuilder ib = new InstructionBuilder(); 204 | ApplyActionsBuilder aab = new ApplyActionsBuilder(); 205 | ActionBuilder ab = new ActionBuilder(); 206 | List actionList = Lists.newArrayList(); 207 | 208 | // Set output action 209 | OutputActionBuilder output = new OutputActionBuilder(); 210 | output.setOutputNodeConnector(egressNodeConnectorId); 211 | output.setMaxLength(65535); //Send full packet and No buffer 212 | ab.setAction(new OutputActionCaseBuilder().setOutputAction(output.build()).build()); 213 | ab.setOrder(0); 214 | ab.setKey(new ActionKey(0)); 215 | actionList.add(ab.build()); 216 | 217 | // Create Apply Actions Instruction 218 | aab.setAction(actionList); 219 | ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build()); 220 | ib.setOrder(0); 221 | ib.setKey(new InstructionKey(0)); 222 | instructions.add(ib.build()); 223 | 224 | // Create Flow 225 | FlowBuilder flowBuilder = new FlowBuilder(); 226 | flowBuilder.setMatch(matchBuilder.build()); 227 | 228 | String flowId = "L2_Rule_" + dstMac; 229 | flowBuilder.setId(new FlowId(flowId)); 230 | FlowKey key = new FlowKey(new FlowId(flowId)); 231 | flowBuilder.setBarrier(true); 232 | flowBuilder.setTableId((short)0); 233 | flowBuilder.setKey(key); 234 | flowBuilder.setPriority(32768); 235 | flowBuilder.setFlowName(flowId); 236 | flowBuilder.setHardTimeout(0); 237 | flowBuilder.setIdleTimeout(0); 238 | flowBuilder.setInstructions(isb.setInstruction(instructions).build()); 239 | 240 | InstanceIdentifier flowIID = InstanceIdentifier.builder(Nodes.class) 241 | .child(Node.class, new NodeKey(nodeId)) 242 | .augmentation(FlowCapableNode.class) 243 | .child(Table.class, new TableKey(flowBuilder.getTableId())) 244 | .child(Flow.class, flowBuilder.getKey()) 245 | .build(); 246 | GenericTransactionUtils.writeData(dataBroker, LogicalDatastoreType.CONFIGURATION, flowIID, flowBuilder.build(), true); 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /learning-switch/implementation/src/main/java/org/sdnhub/odl/tutorial/learningswitch/impl/TutorialLearningSwitchModule.java: -------------------------------------------------------------------------------- 1 | package org.sdnhub.odl.tutorial.learningswitch.impl; 2 | 3 | import org.opendaylight.controller.md.sal.binding.api.DataBroker; 4 | import org.opendaylight.controller.sal.binding.api.NotificationProviderService; 5 | import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | public class TutorialLearningSwitchModule extends org.sdnhub.odl.tutorial.learningswitch.impl.AbstractTutorialLearningSwitchModule { 10 | private final Logger LOG = LoggerFactory.getLogger(this.getClass()); 11 | 12 | public TutorialLearningSwitchModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { 13 | super(identifier, dependencyResolver); 14 | } 15 | 16 | public TutorialLearningSwitchModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.sdnhub.odl.tutorial.learningswitch.impl.TutorialLearningSwitchModule oldModule, java.lang.AutoCloseable oldInstance) { 17 | super(identifier, dependencyResolver, oldModule, oldInstance); 18 | } 19 | 20 | @Override 21 | public void customValidation() { 22 | // add custom validation form module attributes here. 23 | } 24 | 25 | @Override 26 | public java.lang.AutoCloseable createInstance() { 27 | //Get all MD-SAL provider objects 28 | DataBroker dataBroker = getDataBrokerDependency(); 29 | RpcProviderRegistry rpcRegistry = getRpcRegistryDependency(); 30 | NotificationProviderService notificationService = getNotificationServiceDependency(); 31 | 32 | TutorialL2Forwarding tutorialL2Forwarding = new TutorialL2Forwarding(dataBroker, notificationService, rpcRegistry); 33 | LOG.info("Tutorial Learning Switch (instance {}) initialized.", tutorialL2Forwarding); 34 | return tutorialL2Forwarding; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /learning-switch/implementation/src/main/java/org/sdnhub/odl/tutorial/learningswitch/impl/TutorialLearningSwitchModuleFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Generated file 3 | * 4 | * Generated from: yang module name: learning-switch-impl yang module local name: learning-switch-impl 5 | * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator 6 | * Generated at: Fri Jun 05 11:08:20 PDT 2015 7 | * 8 | * Do not modify this file unless it is present under src/main directory 9 | */ 10 | package org.sdnhub.odl.tutorial.learningswitch.impl; 11 | public class TutorialLearningSwitchModuleFactory extends org.sdnhub.odl.tutorial.learningswitch.impl.AbstractTutorialLearningSwitchModuleFactory { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /learning-switch/implementation/src/main/yang/learning-switch-impl.yang: -------------------------------------------------------------------------------- 1 | module learning-switch-impl { 2 | yang-version 1; 3 | namespace "urn:sdnhub:odl:tutorial:learning-switch:learning-switch-impl"; 4 | prefix "learning-switch-impl"; 5 | 6 | import config { prefix config; revision-date 2013-04-05; } 7 | import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; } 8 | 9 | description 10 | "This module contains the base YANG definitions for learning-switch-impl."; 11 | 12 | revision "2015-06-05" { 13 | description 14 | "Initial revision."; 15 | } 16 | 17 | // This is the definition of the service implementation as a module identity 18 | identity learning-switch-impl { 19 | base config:module-type; 20 | 21 | // Specifies the prefix for generated java classes. 22 | config:java-name-prefix TutorialLearningSwitch; 23 | } 24 | 25 | // Augments the 'configuration' choice node under modules/module. 26 | augment "/config:modules/config:module/config:configuration" { 27 | case learning-switch-impl { 28 | when "/config:modules/config:module/config:type = 'learning-switch-impl'"; 29 | 30 | //wires in the data-broker service 31 | container data-broker { 32 | uses config:service-ref { 33 | refine type { 34 | mandatory true; 35 | config:required-identity mdsal:binding-async-data-broker; 36 | } 37 | } 38 | } 39 | container notification-service { 40 | uses config:service-ref { 41 | refine type { 42 | mandatory false; 43 | config:required-identity mdsal:binding-notification-service; 44 | } 45 | } 46 | } 47 | container rpc-registry { 48 | uses config:service-ref { 49 | refine type { 50 | mandatory true; 51 | config:required-identity mdsal:binding-rpc-registry; 52 | } 53 | } 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /learning-switch/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | org.sdnhub.odl.tutorial 9 | commons 10 | 1.2.0-SNAPSHOT 11 | ../commons/parent/ 12 | 13 | 14 | org.sdnhub.odl.tutorial.learning-switch 15 | learning-switch-parent 16 | 0.1.0-SNAPSHOT 17 | pom 18 | 19 | 20 | implementation 21 | config 22 | 23 | 24 | -------------------------------------------------------------------------------- /netconf-exercise/base_datastore.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /netconf-exercise/config/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.sdnhub.odl.tutorial 7 | commons 8 | 1.2.0-SNAPSHOT 9 | ../../commons/parent/pom.xml 10 | 11 | 12 | org.sdnhub.odl.tutorial.netconf-exercise 13 | netconf-exercise-config 14 | 1.0.0-SNAPSHOT 15 | SDN Hub tutorial Project Netconf exercise Config 16 | 17 | jar 18 | 19 | 20 | 21 | org.codehaus.mojo 22 | build-helper-maven-plugin 23 | ${build.plugins.plugin.version} 24 | 25 | 26 | attach-artifacts 27 | 28 | attach-artifact 29 | 30 | package 31 | 32 | 33 | 34 | ${project.build.directory}/classes/initial/${netconf-exercise.configfile} 35 | xml 36 | config 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /netconf-exercise/config/src/main/resources/initial/51-netconf-exercise-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | prefix:netconf-exercise-impl 9 | netconf-exercise-impl 10 | 11 | 12 | binding:binding-broker-osgi-registry 13 | binding-osgi-broker 14 | 15 | 16 | 17 | binding:binding-notification-service 18 | binding-notification-broker 19 | 20 | 21 | binding:binding-async-data-broker 22 | binding-data-broker 23 | 24 | 25 | binding:binding-rpc-registry 26 | binding-rpc-broker 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | urn:sdnhub:odl:tutorial:netconf-exercise:netconf-exercise-impl?module=netconf-exercise-impl&revision=2015-08-31 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /netconf-exercise/implementation/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.sdnhub.odl.tutorial.netconf-exercise 6 | netconf-exercise-parent 7 | 0.1.0-SNAPSHOT 8 | 9 | 10 | netconf-exercise-impl 11 | SDN Hub tutorial project Netconf exercise Impl 12 | 1.0.0-SNAPSHOT 13 | bundle 14 | 15 | 16 | 17 | org.opendaylight.netconf 18 | sal-netconf-connector 19 | ${sal-netconf-connector.version} 20 | 21 | 22 | org.opendaylight.controller.model 23 | model-topology 24 | ${controller-model.version} 25 | 26 | 27 | org.sdnhub.odl.tutorial 28 | utils 29 | ${utils.version} 30 | 31 | 32 | org.sdnhub.odl.tutorial.netconf-exercise 33 | netconf-exercise-model 34 | ${netconf-exercise.version} 35 | 36 | 37 | 38 | 39 | 40 | org.opendaylight.yangtools 41 | yang-maven-plugin 42 | ${yangtools.version} 43 | 44 | 45 | 46 | generate-sources 47 | 48 | 49 | src/main/yang 50 | 51 | 52 | org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl 53 | ${codeGeneratorPath} 54 | 55 | 56 | org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator 57 | ${configCodeGeneratorPath} 58 | 59 | urn:sdnhub:odl:tutorial:netconf-exercise:netconf-exercise-impl==org.sdnhub.odl.tutorial.netconf.exercise.impl 60 | urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang 61 | 62 | 63 | 64 | org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl 65 | ${project.build.directory}/site/models 66 | 67 | 68 | true 69 | 70 | 71 | 72 | 73 | 74 | org.opendaylight.mdsal 75 | maven-sal-api-gen-plugin 76 | ${maven-sal-api-gen-plugin.version} 77 | jar 78 | 79 | 80 | org.opendaylight.controller 81 | yang-jmx-generator-plugin 82 | ${yang.jmx.version} 83 | 84 | 85 | 86 | 87 | org.apache.felix 88 | maven-bundle-plugin 89 | 2.4.0 90 | true 91 | 92 | 93 | * 94 | utils 95 | 96 | ${project.basedir}/META-INF 97 | 98 | 99 | 101 | 102 | org.codehaus.mojo 103 | build-helper-maven-plugin 104 | 1.8 105 | 106 | 107 | add-source 108 | 109 | add-source 110 | 111 | generate-sources 112 | 113 | 114 | src/main/yang 115 | ${codeGeneratorPath} 116 | ${configCodeGeneratorPath} 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | maven-clean-plugin 125 | 126 | 127 | 128 | ${codeGeneratorPath} 129 | 130 | ** 131 | 132 | 133 | 134 | ${configCodeGeneratorPath} 135 | 136 | ** 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /netconf-exercise/implementation/src/main/java/org/sdnhub/odl/tutorial/netconf/exercise/impl/MyRouterOrchestrator.java: -------------------------------------------------------------------------------- 1 | package org.sdnhub.odl.tutorial.netconf.exercise.impl; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.concurrent.Executors; 6 | import java.util.concurrent.ScheduledExecutorService; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | import org.opendaylight.controller.md.sal.binding.api.DataBroker; 10 | import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; 11 | import org.opendaylight.controller.md.sal.binding.api.MountPoint; 12 | import org.opendaylight.controller.md.sal.binding.api.MountPointService; 13 | import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; 14 | import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; 15 | import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; 16 | import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; 17 | import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; 18 | import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; 19 | import org.opendaylight.controller.sal.binding.api.NotificationProviderService; 20 | import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; 21 | import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.network.topology.topology.topology.types.TopologyNetconf; 22 | import org.opendaylight.yang.gen.v1.urn.sdnhub.odl.tutorial.router.rev150728.Interfaces; 23 | import org.opendaylight.yang.gen.v1.urn.sdnhub.odl.tutorial.router.rev150728.InterfacesBuilder; 24 | import org.opendaylight.yang.gen.v1.urn.sdnhub.odl.tutorial.router.rev150728.InterfacesKey; 25 | import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; 26 | import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; 27 | import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; 28 | import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; 29 | import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; 30 | import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; 31 | import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; 32 | import org.opendaylight.yangtools.concepts.Registration; 33 | import org.opendaylight.yangtools.yang.binding.DataObject; 34 | import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; 35 | import org.sdnhub.odl.tutorial.utils.GenericTransactionUtils; 36 | import org.slf4j.Logger; 37 | import org.slf4j.LoggerFactory; 38 | 39 | import com.google.common.base.Optional; 40 | import com.google.common.collect.Lists; 41 | 42 | public class MyRouterOrchestrator implements BindingAwareProvider, AutoCloseable, DataChangeListener { 43 | private final Logger LOG = LoggerFactory.getLogger(this.getClass()); 44 | 45 | //Members related to MD-SAL operations 46 | private List registrations = Lists.newArrayList(); 47 | private MountPointService mountService; 48 | 49 | public MyRouterOrchestrator(BindingAwareBroker bindingAwareBroker, DataBroker dataBroker, NotificationProviderService notificationService, RpcProviderRegistry rpcProviderRegistry) { 50 | //Register this object as a provider for receiving session context 51 | bindingAwareBroker.registerProvider(this); 52 | 53 | //Register this object as listener for changes in netconf topology 54 | InstanceIdentifier netconfTopoIID = InstanceIdentifier.builder(NetworkTopology.class) 55 | .child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName()))) 56 | .build(); 57 | registrations.add(dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, netconfTopoIID.child(Node.class), this, DataChangeScope.SUBTREE)); 58 | } 59 | 60 | @Override 61 | public void onSessionInitiated(ProviderContext session) { 62 | // Get the mount service provider 63 | this.mountService = session.getSALService(MountPointService.class); 64 | } 65 | 66 | public void close() throws Exception { 67 | for (Registration registration : registrations) { 68 | registration.close(); 69 | } 70 | registrations.clear(); 71 | } 72 | 73 | @Override 74 | public void onDataChanged(AsyncDataChangeEvent, DataObject> change) { 75 | LOG.debug("Data changed: {} created, {} updated, {} removed", 76 | change.getCreatedData().size(), change.getUpdatedData().size(), change.getRemovedPaths().size()); 77 | 78 | DataObject dataObject; 79 | 80 | // Iterate over any created nodes 81 | for (Map.Entry, DataObject> entry : change.getCreatedData().entrySet()) { 82 | dataObject = entry.getValue(); 83 | if (dataObject instanceof Node) { 84 | LOG.debug("ADDED Path {}, Object {}", entry.getKey(), dataObject); 85 | NodeId nodeId = entry.getKey().firstKeyOf(Node.class, NodeKey.class).getNodeId(); 86 | final String routerName = nodeId.getValue(); 87 | 88 | //Add interface configs 2 seconds later to give the mount point time to settle down 89 | final ScheduledExecutorService exec = Executors.newScheduledThreadPool(1); 90 | exec.schedule(new Runnable(){ 91 | @Override 92 | public void run(){ 93 | //Configure interfaces for each router we care about 94 | if (routerName.equals("router1")) { 95 | configureRouterInterface(routerName, "eth0", "10.10.1.1/24"); 96 | configureRouterInterface(routerName, "eth1", "100.100.100.1/24"); 97 | } else if (routerName.equals("router2")) { 98 | configureRouterInterface(routerName, "eth0", "10.10.1.2/24"); 99 | configureRouterInterface(routerName, "eth1", "100.100.100.2/24"); 100 | } 101 | } 102 | }, 2, TimeUnit.SECONDS); 103 | } 104 | } 105 | 106 | // Iterate over any deleted nodes 107 | Map, DataObject> originalData = change.getOriginalData(); 108 | for (InstanceIdentifier path : change.getRemovedPaths()) { 109 | dataObject = originalData.get(path); 110 | if (dataObject instanceof Node) { 111 | LOG.debug("REMOVED Path {}, Object {}", path, dataObject); 112 | } 113 | } 114 | 115 | //FIXME: Handle relevant updates 116 | } 117 | 118 | /* 119 | * In this method, we write data to a data store location referenced by the REST URL 120 | /restconf/config/network-topology:network-topology/topology/topology-netconf 121 | /node//yang-ext:mount 122 | /router:interfaces/ 123 | * 124 | */ 125 | private void configureRouterInterface(String routerName, String interfaceName, String subnetPrefix) { 126 | LOG.debug("Configuring interface {} for {}", interfaceName, routerName); 127 | 128 | //Step 1: Get access to mount point 129 | InstanceIdentifier netconfNodeIID = InstanceIdentifier.builder(NetworkTopology.class) 130 | .child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName()))) 131 | .child(Node.class, new NodeKey(new NodeId(routerName))) 132 | .build(); 133 | final Optional netconfNodeOptional = mountService.getMountPoint(netconfNodeIID); 134 | 135 | //Step 2: Write to the mount point 136 | if (netconfNodeOptional.isPresent()) { 137 | 138 | //Step 2.1: access data broker within this mount point 139 | MountPoint netconfNode = netconfNodeOptional.get(); 140 | DataBroker netconfNodeDataBroker = netconfNode.getService(DataBroker.class).get(); 141 | 142 | //Step 2.2: construct data and the relative iid 143 | InterfacesBuilder builder = new InterfacesBuilder() 144 | .setId(interfaceName) 145 | .setKey(new InterfacesKey(interfaceName)) 146 | .setIpAddress(subnetPrefix); 147 | InstanceIdentifier interfacesIID = InstanceIdentifier 148 | .builder(Interfaces.class, builder.getKey()) 149 | .build(); 150 | 151 | //Step 2.3: write to the config data store 152 | GenericTransactionUtils.writeData(netconfNodeDataBroker, LogicalDatastoreType.CONFIGURATION, interfacesIID, builder.build(), true); 153 | 154 | } else { 155 | LOG.warn("Mount point not ready for {}", routerName); 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /netconf-exercise/implementation/src/main/java/org/sdnhub/odl/tutorial/netconf/exercise/impl/TutorialNetconfExerciseModule.java: -------------------------------------------------------------------------------- 1 | package org.sdnhub.odl.tutorial.netconf.exercise.impl; 2 | 3 | import org.opendaylight.controller.md.sal.binding.api.DataBroker; 4 | import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; 5 | import org.opendaylight.controller.sal.binding.api.NotificationProviderService; 6 | import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import com.google.common.base.Preconditions; 11 | 12 | public class TutorialNetconfExerciseModule extends AbstractTutorialNetconfExerciseModule { 13 | private final Logger LOG = LoggerFactory.getLogger(this.getClass()); 14 | 15 | public TutorialNetconfExerciseModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { 16 | super(identifier, dependencyResolver); 17 | } 18 | 19 | public TutorialNetconfExerciseModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, AbstractTutorialNetconfExerciseModule oldModule, java.lang.AutoCloseable oldInstance) { 20 | super(identifier, dependencyResolver, oldModule, oldInstance); 21 | } 22 | 23 | @Override 24 | public void customValidation() { 25 | // add custom validation form module attributes here. 26 | } 27 | 28 | @Override 29 | public java.lang.AutoCloseable createInstance() { 30 | BindingAwareBroker bindingAwareBroker = getBindingAwareBrokerDependency(); 31 | DataBroker dataBrokerService = getDataBrokerDependency(); 32 | RpcProviderRegistry rpcProviderRegistry = getRpcRegistryDependency(); 33 | NotificationProviderService notificationService = getNotificationServiceDependency(); 34 | 35 | Preconditions.checkNotNull(bindingAwareBroker); 36 | Preconditions.checkNotNull(dataBrokerService); 37 | Preconditions.checkNotNull(rpcProviderRegistry); 38 | Preconditions.checkNotNull(notificationService); 39 | 40 | MyRouterOrchestrator orchestrator = new MyRouterOrchestrator(bindingAwareBroker, dataBrokerService, notificationService, rpcProviderRegistry); 41 | LOG.info("Tutorial NetconfExercise (instance {}) initialized.", orchestrator); 42 | return orchestrator; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /netconf-exercise/implementation/src/main/java/org/sdnhub/odl/tutorial/netconf/exercise/impl/TutorialNetconfExerciseModuleFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Generated file 3 | * 4 | * Generated from: yang module name: netconf-exercise-impl yang module local name: netconf-exercise-impl 5 | * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator 6 | * Generated at: Mon Aug 31 22:01:26 PDT 2015 7 | * 8 | * Do not modify this file unless it is present under src/main directory 9 | */ 10 | package org.sdnhub.odl.tutorial.netconf.exercise.impl; 11 | public class TutorialNetconfExerciseModuleFactory extends org.sdnhub.odl.tutorial.netconf.exercise.impl.AbstractTutorialNetconfExerciseModuleFactory { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /netconf-exercise/implementation/src/main/yang/netconf-exercise.yang: -------------------------------------------------------------------------------- 1 | module netconf-exercise-impl { 2 | yang-version 1; 3 | namespace "urn:sdnhub:odl:tutorial:netconf-exercise:netconf-exercise-impl"; 4 | prefix "netconf-exercise-impl"; 5 | 6 | import config { prefix config; revision-date 2013-04-05; } 7 | import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; } 8 | 9 | description 10 | "This module contains the base YANG definitions for netconf-exercise-impl."; 11 | 12 | revision "2015-08-31" { 13 | description 14 | "Initial revision."; 15 | } 16 | 17 | // This is the definition of the service implementation as a module identity 18 | identity netconf-exercise-impl { 19 | base config:module-type; 20 | 21 | // Specifies the prefix for generated java classes. 22 | config:java-name-prefix TutorialNetconfExercise; 23 | } 24 | 25 | // Augments the 'configuration' choice node under modules/module. 26 | augment "/config:modules/config:module/config:configuration" { 27 | case netconf-exercise-impl { 28 | when "/config:modules/config:module/config:type = 'netconf-exercise-impl'"; 29 | 30 | //wires in the data-broker service 31 | container binding-aware-broker { 32 | uses config:service-ref { 33 | refine type { 34 | mandatory true; 35 | config:required-identity mdsal:binding-broker-osgi-registry; 36 | } 37 | } 38 | } 39 | container data-broker { 40 | uses config:service-ref { 41 | refine type { 42 | mandatory true; 43 | config:required-identity mdsal:binding-async-data-broker; 44 | } 45 | } 46 | } 47 | container notification-service { 48 | uses config:service-ref { 49 | refine type { 50 | mandatory false; 51 | config:required-identity mdsal:binding-notification-service; 52 | } 53 | } 54 | } 55 | container rpc-registry { 56 | uses config:service-ref { 57 | refine type { 58 | mandatory true; 59 | config:required-identity mdsal:binding-rpc-registry; 60 | } 61 | } 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /netconf-exercise/model/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.sdnhub.odl.tutorial 6 | commons 7 | 1.2.0-SNAPSHOT 8 | ../../commons/parent/ 9 | 10 | 11 | org.sdnhub.odl.tutorial.netconf-exercise 12 | netconf-exercise-model 13 | 1.0.0-SNAPSHOT 14 | bundle 15 | SDN Hub tutorial project Netconf exercise Model 16 | 17 | 18 | 19 | org.opendaylight.controller.model 20 | model-inventory 21 | ${controller-model.version} 22 | 23 | 24 | 25 | 26 | 27 | 28 | org.apache.felix 29 | maven-bundle-plugin 30 | true 31 | 32 | 33 | ${project.groupId}.${project.artifactId} 34 | org.opendaylight.yangtools.yang.binding.annotations, * 35 | ${project.basedir}/META-INF 36 | 37 | 38 | 39 | 40 | org.opendaylight.yangtools 41 | yang-maven-plugin 42 | ${yangtools.version} 43 | 44 | 45 | org.opendaylight.mdsal 46 | maven-sal-api-gen-plugin 47 | ${maven-sal-api-gen-plugin.version} 48 | jar 49 | 50 | 51 | org.opendaylight.mdsal 52 | yang-binding 53 | ${yang-binding.version} 54 | jar 55 | 56 | 57 | 58 | 59 | 60 | generate-sources 61 | 62 | 63 | src/main/yang 64 | 65 | 66 | org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl 67 | ${codeGeneratorPath} 68 | 69 | 70 | org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl 71 | target/site/models 72 | 73 | 74 | org.opendaylight.yangtools.yang.wadl.generator.maven.WadlGenerator 75 | target/site/models 76 | 77 | 78 | true 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | maven-clean-plugin 87 | 88 | 89 | 90 | ${codeGeneratorPath} 91 | 92 | ** 93 | 94 | 95 | 96 | ${codeGeneratorPath} 97 | 98 | ** 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /netconf-exercise/model/src/main/yang/router.yang: -------------------------------------------------------------------------------- 1 | module router { 2 | yang-version 1; 3 | namespace "urn:sdnhub:odl:tutorial:router"; 4 | prefix router; 5 | 6 | description "Router configuration"; 7 | 8 | revision "2015-07-28" { 9 | description "Initial version."; 10 | } 11 | 12 | list interfaces { 13 | key id; 14 | leaf id { 15 | type string; 16 | } 17 | leaf ip-address { 18 | type string; 19 | } 20 | } 21 | 22 | container router { 23 | list ospf { 24 | key process-id; 25 | leaf process-id { 26 | type uint32; 27 | } 28 | list networks { 29 | key subnet-ip; 30 | leaf subnet-ip { 31 | type string; 32 | } 33 | leaf area-id { 34 | type uint32; 35 | } 36 | } 37 | } 38 | 39 | list bgp { 40 | key as-number; 41 | leaf as-number { 42 | type uint32; 43 | } 44 | leaf router-id { 45 | type string; 46 | } 47 | list neighbors { 48 | key as-number; 49 | leaf as-number { 50 | type uint32; 51 | } 52 | leaf peer-ip { 53 | type string; 54 | } 55 | } 56 | } 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /netconf-exercise/netconf-postman.json: -------------------------------------------------------------------------------- 1 | {"id":"efe2e7b1-360c-c0e6-d5b2-b38def604ca5","name":"Tutorial-Netconf","timestamp":1433658588597,"order":["4ec1b204-ab62-a115-242c-bf39ca711729","c74dc865-f03a-4c0d-7dad-6342d4eff400","7becffb0-1fb7-f0fa-f025-90319d1f24fd","917e2fc1-72f5-7069-22be-0091eddda31d","f43b3dfb-870b-19c7-a2a9-21b526863ada","496d5f49-fb91-d884-65ed-d567f84cb35d","f1852aea-aefe-b0f2-6420-f66e12cff2be","7c93f30f-acb7-8380-b084-14e5c8f6a373","f0452bd6-9c0e-ee13-a918-79cf1f7730a5"],"requests":[{"collectionId":"efe2e7b1-360c-c0e6-d5b2-b38def604ca5","id":"496d5f49-fb91-d884-65ed-d567f84cb35d","name":"Configure router2 interface eth0","description":"","url":"http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/router2/yang-ext:mount/router:interfaces/eth0","method":"PUT","headers":"Content-Type: application/xml\n","data":"\neth0\n10.10.1.2/24\n\n","dataMode":"raw","timestamp":0,"responses":[],"version":2},{"collectionId":"efe2e7b1-360c-c0e6-d5b2-b38def604ca5","id":"4ec1b204-ab62-a115-242c-bf39ca711729","name":"Get all discovered netconf devices","description":"","url":"http://localhost:8181/restconf/operational/network-topology:network-topology/topology/topology-netconf/","method":"GET","headers":"Content-Type: application/xml\n","data":"","dataMode":"raw","timestamp":0,"responses":[],"version":2},{"collectionId":"efe2e7b1-360c-c0e6-d5b2-b38def604ca5","id":"7becffb0-1fb7-f0fa-f025-90319d1f24fd","name":"Configure router1 interface eth1","description":"","url":"http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/router1/yang-ext:mount/router:interfaces/eth1","method":"PUT","headers":"Content-Type: application/xml\n","data":"\neth1\n100.100.100.1/24\n\n","dataMode":"raw","timestamp":0,"responses":[],"version":2},{"collectionId":"efe2e7b1-360c-c0e6-d5b2-b38def604ca5","id":"7c93f30f-acb7-8380-b084-14e5c8f6a373","name":"Configure router2 OSPF + BGP","description":"","url":"http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/router2/yang-ext:mount/router:router","method":"PUT","headers":"Content-Type: application/xml\n","data":"\n \n 1\n \n 200.200.200.0/24\n 20\n \n \n \n 2000\n 10.10.1.2\n \n 1000\n 10.10.1.1\n \n \n","dataMode":"raw","timestamp":0,"version":2},{"collectionId":"efe2e7b1-360c-c0e6-d5b2-b38def604ca5","id":"917e2fc1-72f5-7069-22be-0091eddda31d","name":"Configure router1 OSPF + BGP","description":"","url":"http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/router1/yang-ext:mount/router:router","method":"PUT","headers":"Content-Type: application/xml\n","data":"\n \n 1\n \n 100.100.100.0/24\n 10\n \n \n \n 1000\n 10.10.1.1\n \n 2000\n 10.10.1.2\n \n \n","dataMode":"raw","timestamp":0,"version":2},{"collectionId":"efe2e7b1-360c-c0e6-d5b2-b38def604ca5","id":"c74dc865-f03a-4c0d-7dad-6342d4eff400","name":"Configure router1 interface eth0","description":"","url":"http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/router1/yang-ext:mount/router:interfaces/eth0","method":"PUT","headers":"Content-Type: application/xml\n","data":"\neth0\n10.10.1.1/24\n\n","dataMode":"raw","timestamp":0,"responses":[],"version":2},{"collectionId":"efe2e7b1-360c-c0e6-d5b2-b38def604ca5","id":"f0452bd6-9c0e-ee13-a918-79cf1f7730a5","name":"Get configurations of router2","description":"","url":"http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/router2/yang-ext:mount/","method":"GET","headers":"Content-Type: application/xml\n","data":"","dataMode":"raw","timestamp":0,"responses":[],"version":2},{"collectionId":"efe2e7b1-360c-c0e6-d5b2-b38def604ca5","id":"f1852aea-aefe-b0f2-6420-f66e12cff2be","name":"Configure router2 interface eth1","description":"","url":"http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/router2/yang-ext:mount/router:interfaces/eth1","method":"PUT","headers":"Content-Type: application/xml\n","data":"\neth1\n200.200.200.1/24\n\n","dataMode":"raw","timestamp":0,"responses":[],"version":2},{"collectionId":"efe2e7b1-360c-c0e6-d5b2-b38def604ca5","id":"f43b3dfb-870b-19c7-a2a9-21b526863ada","name":"Get configurations of router1","description":"","url":"http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/router1/yang-ext:mount/","method":"GET","headers":"Content-Type: application/xml\n","data":"","dataMode":"raw","timestamp":0,"responses":[],"version":2}]} 2 | -------------------------------------------------------------------------------- /netconf-exercise/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | org.sdnhub.odl.tutorial 9 | commons 10 | 1.2.0-SNAPSHOT 11 | ../commons/parent/ 12 | 13 | 14 | org.sdnhub.odl.tutorial.netconf-exercise 15 | netconf-exercise-parent 16 | 0.1.0-SNAPSHOT 17 | pom 18 | 19 | 20 | model 21 | implementation 22 | config 23 | 24 | 25 | -------------------------------------------------------------------------------- /netconf-exercise/register_netconf_device.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ $# -ne 2 ] 3 | then 4 | echo "Usage: register_netconf_device " 5 | exit 0 6 | fi 7 | 8 | DEVICE_NAME=$1 9 | IP_ADDRESS=$2 10 | USERNAME=root 11 | PASSWORD=root 12 | PORT=830 13 | CONTROLLER_IP=localhost 14 | 15 | ######## Perform CURL call to push new device to the ODL netconf connector 16 | 17 | curl -H "Content-Type: application/xml" -u admin:admin -X PUT -d " 18 | 19 | prefix:sal-netconf-connector 20 | $DEVICE_NAME 21 |
$IP_ADDRESS
22 | $PORT 23 | $USERNAME 24 | $PASSWORD 25 | false 26 | 27 | prefix:netty-event-executor 28 | global-event-executor 29 | 30 | 31 | prefix:binding-broker-osgi-registry 32 | binding-osgi-broker 33 | 34 | 35 | prefix:dom-broker-osgi-registry 36 | dom-broker 37 | 38 | 39 | prefix:netconf-client-dispatcher 40 | global-netconf-dispatcher 41 | 42 | 43 | prefix:threadpool 44 | global-netconf-processing-executor 45 | 46 |
" http://${CONTROLLER_IP}:8181/restconf/config/opendaylight-inventory:nodes/node/controller-config/yang-ext:mount/config:modules/module/odl-sal-netconf-connector-cfg:sal-netconf-connector/$DEVICE_NAME 47 | -------------------------------------------------------------------------------- /netconf-exercise/router.yang: -------------------------------------------------------------------------------- 1 | module router { 2 | yang-version 1; 3 | namespace "urn:sdnhub:odl:tutorial:router"; 4 | prefix router; 5 | 6 | description "Router configuration"; 7 | 8 | revision "2015-07-28" { 9 | description "Initial version."; 10 | } 11 | 12 | list interfaces { 13 | key id; 14 | leaf id { 15 | type string; 16 | } 17 | leaf ip-address { 18 | type string; 19 | } 20 | } 21 | 22 | container router { 23 | list ospf { 24 | key process-id; 25 | leaf process-id { 26 | type uint32; 27 | } 28 | list networks { 29 | key subnet-ip; 30 | leaf subnet-ip { 31 | type string; 32 | } 33 | leaf area-id { 34 | type uint32; 35 | } 36 | } 37 | } 38 | 39 | list bgp { 40 | key as-number; 41 | leaf as-number { 42 | type uint32; 43 | } 44 | leaf router-id { 45 | type string; 46 | } 47 | list neighbors { 48 | key as-number; 49 | leaf as-number { 50 | type uint32; 51 | } 52 | leaf peer-ip { 53 | type string; 54 | } 55 | } 56 | } 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /netconf-exercise/spawn_router.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ $# -ne 1 ] 3 | then 4 | echo "Usage: spawn_router " 5 | exit 0 6 | fi 7 | 8 | ######## Spin up containers 9 | DEVICE_NAME=$1 10 | sudo docker rm -f $DEVICE_NAME 11 | DOCKER_ID=`sudo docker run --name $DEVICE_NAME -dit sdnhub/netopeer /bin/bash` 12 | echo $DOCKER_ID 13 | echo "Spawned container with IP `sudo docker inspect --format '{{ .NetworkSettings.IPAddress }}' $DEVICE_NAME`" 14 | 15 | ######## Start netconf server with custom YANG model 16 | sudo cp base_datastore.xml /var/lib/docker/aufs/mnt/${DOCKER_ID}/usr/local/etc/netopeer/cfgnetopeer/datastore.xml 17 | sudo cp router.yang /var/lib/docker/aufs/mnt/${DOCKER_ID}/root/router.yang 18 | sudo docker exec $DEVICE_NAME pyang -f yin /root/router.yang -o /root/router.yin 19 | sudo docker exec $DEVICE_NAME netopeer-manager add --name router --model router.yin --datastore /usr/local/etc/netopeer/cfgnetopeer/router.xml 20 | sudo docker exec $DEVICE_NAME netopeer-server -d 21 | -------------------------------------------------------------------------------- /netconf-exercise/unregister_netconf_device.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ $# -ne 1 ] 3 | then 4 | echo "Usage: unregister_netconf_device " 5 | exit 0 6 | fi 7 | 8 | DEVICE_NAME=$1 9 | CONTROLLER_IP=localhost 10 | 11 | curl -u admin:admin -X DELETE http://${CONTROLLER_IP}:8181/restconf/config/opendaylight-inventory:nodes/node/controller-config/yang-ext:mount/config:modules/module/odl-sal-netconf-connector-cfg:sal-netconf-connector/$DEVICE_NAME 12 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | org.sdnhub.odl.tutorial 7 | commons 8 | 1.2.0-SNAPSHOT 9 | commons/parent 10 | 11 | 12 | main 13 | 0.6.0-SNAPSHOT 14 | pom 15 | http://sdnhub.org/tutorials/opendaylight 16 | 17 | commons/parent 18 | commons/utils 19 | learning-switch 20 | tapapp 21 | acl 22 | netconf-exercise 23 | features 24 | distribution 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /tapapp/config/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.sdnhub.odl.tutorial 7 | commons 8 | 1.2.0-SNAPSHOT 9 | ../../commons/parent/pom.xml 10 | 11 | 12 | org.sdnhub.odl.tutorial.tapapp 13 | tapapp-config 14 | 1.0.0-SNAPSHOT 15 | SDN Hub tutorial Project Tap application Config 16 | 17 | jar 18 | 19 | 20 | 21 | org.codehaus.mojo 22 | build-helper-maven-plugin 23 | ${build.plugins.plugin.version} 24 | 25 | 26 | attach-artifacts 27 | 28 | attach-artifact 29 | 30 | package 31 | 32 | 33 | 34 | ${project.build.directory}/classes/initial/${tapapp.configfile} 35 | xml 36 | config 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /tapapp/config/src/main/resources/initial/50-tapapp-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | prefix:tapapp-impl 9 | tapapp-impl 10 | 11 | 12 | binding:binding-notification-service 13 | binding-notification-broker 14 | 15 | 16 | binding:binding-async-data-broker 17 | binding-data-broker 18 | 19 | 20 | binding:binding-rpc-registry 21 | binding-rpc-broker 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | urn:sdnhub:odl:tutorial:tapapp:tapapp-impl?module=tapapp-impl&revision=2015-06-04 30 | urn:opendaylight:params:xml:ns:yang:openflow:common:config:impl?module=openflow-provider-impl&revision=2014-03-26 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /tapapp/implementation/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.sdnhub.odl.tutorial.tapapp 6 | tapapp-parent 7 | 0.1.0-SNAPSHOT 8 | 9 | 10 | tapapp-impl 11 | SDN Hub tutorial project Tap application Impl 12 | 1.0.0-SNAPSHOT 13 | bundle 14 | 15 | 16 | 17 | org.sdnhub.odl.tutorial 18 | utils 19 | ${utils.version} 20 | 21 | 22 | org.sdnhub.odl.tutorial.tapapp 23 | tapapp-model 24 | ${tapapp.version} 25 | 26 | 27 | org.opendaylight.openflowplugin.model 28 | model-flow-service 29 | ${openflowplugin.version} 30 | 31 | 32 | 33 | 34 | 35 | org.opendaylight.yangtools 36 | yang-maven-plugin 37 | ${yangtools.version} 38 | 39 | 40 | 41 | generate-sources 42 | 43 | 44 | src/main/yang 45 | 46 | 47 | org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl 48 | ${codeGeneratorPath} 49 | 50 | 51 | org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator 52 | ${configCodeGeneratorPath} 53 | 54 | urn:sdnhub:odl:tutorial:tapapp:tapapp-impl==org.sdnhub.odl.tutorial.tapapp.impl 55 | urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang 56 | 57 | 58 | 59 | org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl 60 | ${project.build.directory}/site/models 61 | 62 | 63 | true 64 | 65 | 66 | 67 | 68 | 69 | org.opendaylight.mdsal 70 | maven-sal-api-gen-plugin 71 | ${maven-sal-api-gen-plugin.version} 72 | jar 73 | 74 | 75 | org.opendaylight.controller 76 | yang-jmx-generator-plugin 77 | ${yang.jmx.version} 78 | 79 | 80 | 81 | 82 | org.apache.felix 83 | maven-bundle-plugin 84 | 2.4.0 85 | true 86 | 87 | 88 | * 89 | utils 90 | 91 | ${project.basedir}/META-INF 92 | 93 | 94 | 96 | 97 | org.codehaus.mojo 98 | build-helper-maven-plugin 99 | 1.8 100 | 101 | 102 | add-source 103 | 104 | add-source 105 | 106 | generate-sources 107 | 108 | 109 | src/main/yang 110 | ${codeGeneratorPath} 111 | ${configCodeGeneratorPath} 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | maven-clean-plugin 120 | 121 | 122 | 123 | ${codeGeneratorPath} 124 | 125 | ** 126 | 127 | 128 | 129 | ${configCodeGeneratorPath} 130 | 131 | ** 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /tapapp/implementation/src/main/java/org/sdnhub/odl/tutorial/tapapp/impl/TutorialTapAppModule.java: -------------------------------------------------------------------------------- 1 | package org.sdnhub.odl.tutorial.tapapp.impl; 2 | 3 | import org.opendaylight.controller.md.sal.binding.api.DataBroker; 4 | import org.opendaylight.controller.sal.binding.api.NotificationProviderService; 5 | import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import com.google.common.base.Preconditions; 10 | 11 | public class TutorialTapAppModule extends AbstractTutorialTapAppModule { 12 | private final Logger LOG = LoggerFactory.getLogger(this.getClass()); 13 | 14 | public TutorialTapAppModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { 15 | super(identifier, dependencyResolver); 16 | } 17 | 18 | public TutorialTapAppModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, AbstractTutorialTapAppModule oldModule, java.lang.AutoCloseable oldInstance) { 19 | super(identifier, dependencyResolver, oldModule, oldInstance); 20 | } 21 | 22 | @Override 23 | public void customValidation() { 24 | // add custom validation form module attributes here. 25 | } 26 | 27 | @Override 28 | public java.lang.AutoCloseable createInstance() { 29 | DataBroker dataBrokerService = getDataBrokerDependency(); 30 | RpcProviderRegistry rpcProviderRegistry = getRpcRegistryDependency(); 31 | NotificationProviderService notificationService = getNotificationServiceDependency(); 32 | 33 | Preconditions.checkNotNull(dataBrokerService); 34 | Preconditions.checkNotNull(rpcProviderRegistry); 35 | Preconditions.checkNotNull(notificationService); 36 | 37 | TutorialTapProvider tapProvider = new TutorialTapProvider(dataBrokerService, notificationService, rpcProviderRegistry); 38 | LOG.info("Tutorial TapApp (instance {}) initialized.", tapProvider); 39 | return tapProvider; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tapapp/implementation/src/main/java/org/sdnhub/odl/tutorial/tapapp/impl/TutorialTapAppModuleFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Generated file 3 | * 4 | * Generated from: yang module name: tapapp-impl yang module local name: tapapp-impl 5 | * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator 6 | * Generated at: Fri Jun 05 14:58:22 PDT 2015 7 | * 8 | * Do not modify this file unless it is present under src/main directory 9 | */ 10 | package org.sdnhub.odl.tutorial.tapapp.impl; 11 | public class TutorialTapAppModuleFactory extends AbstractTutorialTapAppModuleFactory { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /tapapp/implementation/src/main/yang/tapapp-impl.yang: -------------------------------------------------------------------------------- 1 | module tapapp-impl { 2 | yang-version 1; 3 | namespace "urn:sdnhub:odl:tutorial:tapapp:tapapp-impl"; 4 | prefix "tapapp-impl"; 5 | 6 | import config { prefix config; revision-date 2013-04-05; } 7 | import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; } 8 | 9 | description 10 | "This module contains the base YANG definitions for tapapp-impl."; 11 | 12 | revision "2015-06-04" { 13 | description 14 | "Initial revision."; 15 | } 16 | 17 | // This is the definition of the service implementation as a module identity 18 | identity tapapp-impl { 19 | base config:module-type; 20 | 21 | // Specifies the prefix for generated java classes. 22 | config:java-name-prefix TutorialTapApp; 23 | } 24 | 25 | // Augments the 'configuration' choice node under modules/module. 26 | augment "/config:modules/config:module/config:configuration" { 27 | case tapapp-impl { 28 | when "/config:modules/config:module/config:type = 'tapapp-impl'"; 29 | 30 | //wires in the data-broker service 31 | container data-broker { 32 | uses config:service-ref { 33 | refine type { 34 | mandatory true; 35 | config:required-identity mdsal:binding-async-data-broker; 36 | } 37 | } 38 | } 39 | container notification-service { 40 | uses config:service-ref { 41 | refine type { 42 | mandatory false; 43 | config:required-identity mdsal:binding-notification-service; 44 | } 45 | } 46 | } 47 | container rpc-registry { 48 | uses config:service-ref { 49 | refine type { 50 | mandatory true; 51 | config:required-identity mdsal:binding-rpc-registry; 52 | } 53 | } 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tapapp/model/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.sdnhub.odl.tutorial 6 | commons 7 | 1.2.0-SNAPSHOT 8 | ../../commons/parent/ 9 | 10 | 11 | org.sdnhub.odl.tutorial.tapapp 12 | tapapp-model 13 | 1.0.0-SNAPSHOT 14 | bundle 15 | SDN Hub tutorial project Tap application Model 16 | 17 | 18 | 19 | org.opendaylight.controller.model 20 | model-inventory 21 | ${controller-model.version} 22 | 23 | 24 | 25 | 26 | 27 | 28 | org.apache.felix 29 | maven-bundle-plugin 30 | true 31 | 32 | 33 | ${project.groupId}.${project.artifactId} 34 | org.opendaylight.yangtools.yang.binding.annotations, * 35 | ${project.basedir}/META-INF 36 | 37 | 38 | 39 | 40 | org.opendaylight.yangtools 41 | yang-maven-plugin 42 | ${yangtools.version} 43 | 44 | 45 | org.opendaylight.mdsal 46 | maven-sal-api-gen-plugin 47 | ${maven-sal-api-gen-plugin.version} 48 | jar 49 | 50 | 51 | org.opendaylight.mdsal 52 | yang-binding 53 | ${yang-binding.version} 54 | jar 55 | 56 | 57 | 58 | 59 | 60 | generate-sources 61 | 62 | 63 | src/main/yang 64 | 65 | 66 | org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl 67 | ${codeGeneratorPath} 68 | 69 | 70 | org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl 71 | target/site/models 72 | 73 | 74 | org.opendaylight.yangtools.yang.wadl.generator.maven.WadlGenerator 75 | target/site/models 76 | 77 | 78 | true 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | maven-clean-plugin 87 | 88 | 89 | 90 | ${codeGeneratorPath} 91 | 92 | ** 93 | 94 | 95 | 96 | ${codeGeneratorPath} 97 | 98 | ** 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /tapapp/model/src/main/yang/tap.yang: -------------------------------------------------------------------------------- 1 | module tap { 2 | yang-version 1; 3 | namespace "urn:sdnhub:tutorial:odl:tap"; 4 | prefix tap; 5 | 6 | import opendaylight-inventory {prefix inv; revision-date 2013-08-19;} 7 | import yang-ext {prefix ext; revision-date "2013-07-09";} 8 | import ietf-yang-types { prefix yang; revision-date 2010-09-24; } 9 | import ietf-inet-types { prefix inet; } 10 | description "Tap configuration"; 11 | 12 | revision "2015-06-01" { 13 | description "Initial version."; 14 | } 15 | 16 | typedef port-number { 17 | type uint32; 18 | } 19 | 20 | 21 | typedef field-type { 22 | type enumeration { 23 | enum source; 24 | enum destination; 25 | enum both; 26 | } 27 | } 28 | 29 | typedef traffic-type { 30 | type enumeration { 31 | enum ARP; 32 | enum DNS; 33 | enum HTTP; 34 | enum HTTPS; 35 | enum TCP; 36 | enum UDP; 37 | enum DHCP; 38 | enum ICMP; 39 | } 40 | } 41 | 42 | grouping tap-grouping { 43 | leaf node { 44 | mandatory true; 45 | type leafref { 46 | path "/inv:nodes/inv:node/inv:id"; 47 | } 48 | } 49 | leaf-list src-node-connector { 50 | min-elements 1; 51 | type leafref { 52 | path "/inv:nodes/inv:node/inv:node-connector/inv:id"; 53 | } 54 | } 55 | leaf-list sink-node-connector { 56 | min-elements 1; 57 | type leafref { 58 | path "/inv:nodes/inv:node/inv:node-connector/inv:id"; 59 | } 60 | } 61 | container mac-address-match { 62 | leaf type { 63 | type field-type; 64 | } 65 | leaf value { 66 | type yang:mac-address; 67 | } 68 | } 69 | container ip-address-match { 70 | leaf type { 71 | type field-type; 72 | } 73 | leaf value { 74 | type inet:ipv4-prefix; 75 | } 76 | } 77 | leaf traffic-match { 78 | type traffic-type; 79 | } 80 | } 81 | 82 | container tap-spec { 83 | list tap { 84 | key "id"; 85 | leaf id { 86 | type string; 87 | } 88 | uses tap-grouping; 89 | } 90 | } 91 | 92 | augment /tap-spec/tap { 93 | ext:augment-identifier "ProtocolInfo"; 94 | leaf dl-type { 95 | type uint16; 96 | } 97 | leaf nw-proto { 98 | type uint8; 99 | } 100 | leaf tp-src { 101 | type uint16; 102 | } 103 | leaf tp-dst { 104 | type uint16; 105 | } 106 | } 107 | } 108 | 109 | -------------------------------------------------------------------------------- /tapapp/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | org.sdnhub.odl.tutorial 9 | commons 10 | 1.2.0-SNAPSHOT 11 | ../commons/parent/ 12 | 13 | 14 | org.sdnhub.odl.tutorial.tapapp 15 | tapapp-parent 16 | 0.1.0-SNAPSHOT 17 | pom 18 | 19 | 20 | model 21 | implementation 22 | config 23 | 24 | 25 | -------------------------------------------------------------------------------- /tapapp/postman-resources/tapapp-postman.json: -------------------------------------------------------------------------------- 1 | {"id":"86c494e7-4a55-577d-da29-0baf1b37bed9","name":"Tutorial-TapApp","timestamp":1433658588597,"requests":[{"collectionId":"86c494e7-4a55-577d-da29-0baf1b37bed9","id":"1af34405-9f90-0296-4c5a-6b62051d3e01","name":"Tap 1 deletion","description":"","url":"http://localhost:8181/restconf/config/tap:tap-spec/tap/1","method":"DELETE","headers":"Content-Type: application/xml\n","data":"\n 1\n","dataMode":"raw","timestamp":0,"responses":[],"version":2},{"collectionId":"86c494e7-4a55-577d-da29-0baf1b37bed9","id":"5ebac46d-4ee5-ba70-d1d4-546247d6792b","name":"Tap 2 addition","description":"","url":"http://localhost:8181/restconf/config/tap:tap-spec/tap/2","method":"PUT","headers":"Content-Type: application/xml\n","data":"\n 2\n openflow:1\n \n openflow:1:2\n \n \n openflow:1:1\n \n DNS\n","dataMode":"raw","timestamp":0,"version":2},{"collectionId":"86c494e7-4a55-577d-da29-0baf1b37bed9","id":"6fc7a059-5afe-b941-78f6-70ab4cc1dfed","name":"Tap 1 addition","description":"","url":"http://localhost:8181/restconf/config/tap:tap-spec","method":"PUT","headers":"Content-Type: application/xml\n","data":"\n \n 1\n openflow:1\n \n openflow:1:1\n \n \n openflow:1:2\n \n HTTP\n \n","dataMode":"raw","timestamp":0,"version":2},{"collectionId":"86c494e7-4a55-577d-da29-0baf1b37bed9","id":"9c108ce8-269f-3916-9614-044cc9f2f32a","name":"Get all configured Taps","description":"","url":"http://localhost:8181/restconf/config/tap:tap-spec","method":"GET","headers":"Content-Type: application/xml\n","data":"","dataMode":"raw","timestamp":0,"version":2,"time":1438192927149},{"collectionId":"86c494e7-4a55-577d-da29-0baf1b37bed9","id":"e63dbd8b-b311-cb73-0ead-d44fd7fbaa42","name":"Tap 2 deletion","description":"","url":"http://localhost:8181/restconf/config/tap:tap-spec/tap/2","method":"DELETE","headers":"Content-Type: application/xml\n","data":"\n 2\n","dataMode":"raw","timestamp":0,"version":2}],"order":["9c108ce8-269f-3916-9614-044cc9f2f32a","6fc7a059-5afe-b941-78f6-70ab4cc1dfed","1af34405-9f90-0296-4c5a-6b62051d3e01","5ebac46d-4ee5-ba70-d1d4-546247d6792b","e63dbd8b-b311-cb73-0ead-d44fd7fbaa42"]} 2 | --------------------------------------------------------------------------------