Zayne Khouja
Committed by Gerrit Code Review

ONOS learning-switch tutorial

Change-Id: Id82a0886be5bbead60ea61dee30dd3ee12d20bbc
1 +COMPILE_DEPS = [
2 + '//lib:CORE_DEPS',
3 + '//lib:slf4j-api',
4 + '//lib:org.apache.felix.scr.annotations',
5 + '//lib:junit',
6 +]
7 +
8 +osgi_jar_with_tests (
9 + deps = COMPILE_DEPS,
10 +)
11 +
12 +onos_app (
13 + title = 'Learning Switch Tutorial',
14 + category = 'Tutorial',
15 + url = 'http://onosproject.org',
16 + description = 'Tutorial to help user create a learning switch',
17 +)
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2016 Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
18 + <modelVersion>4.0.0</modelVersion>
19 +
20 + <parent>
21 + <groupId>org.onosproject</groupId>
22 + <artifactId>onos-apps</artifactId>
23 + <version>1.7.0-SNAPSHOT</version>
24 + <relativePath>../pom.xml</relativePath>
25 + </parent>
26 +
27 + <artifactId>onos-apps-learning-switch</artifactId>
28 + <packaging>bundle</packaging>
29 +
30 + <description>Learning Switch Tutorial Implementation</description>
31 + <url>http://onosproject.org</url>
32 +
33 + <properties>
34 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
35 + <onos.app.name>org.onosproject.learningswitch</onos.app.name>
36 + <onos.app.title>Learning Switch</onos.app.title>
37 + <onos.app.origin>ON.Lab</onos.app.origin>
38 + <onos.app.category>Tutorial</onos.app.category>
39 + <onos.app.url>http://onosproject.org</onos.app.url>
40 + <onos.app.readme>Learning Switch Tutorial Implementation.</onos.app.readme>
41 + </properties>
42 +
43 + <dependencies>
44 + <dependency>
45 + <groupId>org.onosproject</groupId>
46 + <artifactId>onos-api</artifactId>
47 + <version>${project.version}</version>
48 + </dependency>
49 +
50 + <dependency>
51 + <groupId>org.onosproject</groupId>
52 + <artifactId>onlab-osgi</artifactId>
53 + <version>${project.version}</version>
54 + </dependency>
55 +
56 + <dependency>
57 + <groupId>junit</groupId>
58 + <artifactId>junit</artifactId>
59 + <version>4.12</version>
60 + <scope>test</scope>
61 + </dependency>
62 +
63 + <dependency>
64 + <groupId>org.onosproject</groupId>
65 + <artifactId>onos-api</artifactId>
66 + <version>${project.version}</version>
67 + <scope>test</scope>
68 + <classifier>tests</classifier>
69 + </dependency>
70 +
71 + <dependency>
72 + <groupId>org.apache.felix</groupId>
73 + <artifactId>org.apache.felix.scr.annotations</artifactId>
74 + <version>1.9.12</version>
75 + <scope>provided</scope>
76 + </dependency>
77 +
78 + <dependency>
79 + <groupId>org.slf4j</groupId>
80 + <artifactId>slf4j-api</artifactId>
81 + <version>1.7.21</version>
82 + </dependency>
83 + </dependencies>
84 +</project>
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
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 implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.learningswitch;
17 +
18 +import com.google.common.collect.Maps;
19 +import org.apache.felix.scr.annotations.Activate;
20 +import org.apache.felix.scr.annotations.Deactivate;
21 +import org.apache.felix.scr.annotations.Component;
22 +import org.apache.felix.scr.annotations.Reference;
23 +import org.apache.felix.scr.annotations.ReferenceCardinality;
24 +import org.onlab.packet.Ethernet;
25 +import org.onlab.packet.MacAddress;
26 +import org.onosproject.core.ApplicationId;
27 +import org.onosproject.core.CoreService;
28 +import org.onosproject.net.ConnectPoint;
29 +import org.onosproject.net.DeviceId;
30 +import org.onosproject.net.PortNumber;
31 +import org.onosproject.net.flow.DefaultFlowRule;
32 +import org.onosproject.net.flow.DefaultTrafficSelector;
33 +import org.onosproject.net.flow.DefaultTrafficTreatment;
34 +import org.onosproject.net.flow.FlowRule;
35 +import org.onosproject.net.flow.FlowRuleService;
36 +import org.onosproject.net.packet.PacketContext;
37 +import org.onosproject.net.packet.PacketPriority;
38 +import org.onosproject.net.packet.PacketProcessor;
39 +import org.onosproject.net.packet.PacketService;
40 +import org.slf4j.Logger;
41 +import org.slf4j.LoggerFactory;
42 +
43 +import java.util.Map;
44 +import java.util.Optional;
45 +
46 +/**
47 + * Tutorial class used to help build a basic onos learning switch application.
48 + * This class contains the solution to the learning switch tutorial. Change "enabled = false"
49 + * to "enabled = true" below, to run the solution.
50 + */
51 +@Component(immediate = true, enabled = false)
52 +public class LearningSwitchSolution {
53 +
54 + // Instantiates the relevant services.
55 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
56 + protected PacketService packetService;
57 +
58 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
59 + protected FlowRuleService flowRuleService;
60 +
61 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
62 + protected CoreService coreService;
63 +
64 + private final Logger log = LoggerFactory.getLogger(getClass());
65 +
66 + /*
67 + * Defining macTables as a concurrent map allows multiple threads and packets to
68 + * use the map without an issue.
69 + */
70 + protected Map<DeviceId, Map<MacAddress, PortNumber>> macTables = Maps.newConcurrentMap();
71 + private ApplicationId appId;
72 + private PacketProcessor processor;
73 +
74 + /**
75 + * Create a variable of the SwitchPacketProcessor class using the PacketProcessor defined above.
76 + * Activates the app.
77 + */
78 + @Activate
79 + protected void activate() {
80 + log.info("Started");
81 + appId = coreService.getAppId("org.onosproject.learningswitch"); //equal to the name shown in pom.xml file
82 +
83 + processor = new SwitchPacketProcesser();
84 + packetService.addProcessor(processor, PacketProcessor.director(3));
85 +
86 + /*
87 + * Restricts packet types to IPV4 and ARP by only requesting those types.
88 + */
89 + packetService.requestPackets(DefaultTrafficSelector.builder()
90 + .matchEthType(Ethernet.TYPE_IPV4).build(), PacketPriority.REACTIVE, appId, Optional.empty());
91 + packetService.requestPackets(DefaultTrafficSelector.builder()
92 + .matchEthType(Ethernet.TYPE_ARP).build(), PacketPriority.REACTIVE, appId, Optional.empty());
93 + }
94 +
95 + /**
96 + * Deactivates the processor by removing it.
97 + */
98 + @Deactivate
99 + protected void deactivate() {
100 + log.info("Stopped");
101 + packetService.removeProcessor(processor);
102 + }
103 +
104 + /**
105 + * This class contains pseudo code that you must replace with your own code. Your job is to
106 + * send the packet out the port previously learned for the destination MAC, if it
107 + * exists. Otherwise flood the packet (to all ports).
108 + */
109 + private class SwitchPacketProcesser implements PacketProcessor {
110 + /**
111 + * Learns the source port associated with the packet's DeviceId if it has not already been learned.
112 + * Calls actLikeSwitch to process and send the packet.
113 + * @param pc PacketContext object containing packet info
114 + */
115 + @Override
116 + public void process(PacketContext pc) {
117 + log.info(pc.toString());
118 + initMacTable(pc.inPacket().receivedFrom());
119 +
120 +
121 + // This is the basic flood all ports switch that is enabled.
122 + //actLikeHub(pc);
123 +
124 + /*
125 + * This is the call to the actLikeSwitch method you will be creating. When
126 + * you are ready to test it, uncomment the line below, and comment out the
127 + * actLikeHub call above.
128 + */
129 + actLikeSwitch(pc);
130 +
131 + }
132 +
133 + /**
134 + * Example method. Floods packet out of all switch ports.
135 + *
136 + * @param pc the PacketContext object passed through from activate() method
137 + */
138 + public void actLikeHub(PacketContext pc) {
139 + pc.treatmentBuilder().setOutput(PortNumber.FLOOD);
140 + pc.send();
141 + }
142 +
143 + /**
144 + * Ensures packet is of required type. Obtain the PortNumber associated with the inPackets DeviceId.
145 + * If this port has previously been learned (in initMacTable method) build a flow using the packet's
146 + * out port, treatment, destination, and other properties. Send the flow to the learned out port.
147 + * Otherwise, flood packet to all ports if out port is not learned.
148 + *
149 + * @param pc the PacketContext object passed through from activate() method
150 + */
151 + public void actLikeSwitch(PacketContext pc) {
152 +
153 + /*
154 + * Ensures the type of packet being processed is only of type IPV4 (not LLDP or BDDP). If it is not, return
155 + * and do nothing with the packet. actLikeSwitch can only process IPV4 packets.
156 + */
157 + Short type = pc.inPacket().parsed().getEtherType();
158 + if (type != Ethernet.TYPE_IPV4) {
159 + return;
160 + }
161 +
162 + /*
163 + * Learn the destination, source, and output port of the packet using a ConnectPoint and the
164 + * associated macTable. If there is a known port associated with the packet's destination MAC Address,
165 + * the output port will not be null.
166 + */
167 + ConnectPoint cp = pc.inPacket().receivedFrom();
168 + Map<MacAddress, PortNumber> macTable = macTables.get(cp.deviceId());
169 + MacAddress srcMac = pc.inPacket().parsed().getSourceMAC();
170 + MacAddress dstMac = pc.inPacket().parsed().getDestinationMAC();
171 + macTable.put(srcMac, cp.port());
172 + PortNumber outPort = macTable.get(dstMac);
173 +
174 + /*
175 + * If port is known, set pc's out port to the packet's learned output port and construct a
176 + * FlowRule using a source, destination, treatment and other properties. Send the FlowRule
177 + * to the designated output port.
178 + */
179 + if (outPort != null) {
180 + pc.treatmentBuilder().setOutput(outPort);
181 + FlowRule fr = DefaultFlowRule.builder()
182 + .withSelector(DefaultTrafficSelector.builder().matchEthDst(dstMac).build())
183 + .withTreatment(DefaultTrafficTreatment.builder().setOutput(outPort).build())
184 + .forDevice(cp.deviceId()).withPriority(PacketPriority.REACTIVE.priorityValue())
185 + .makeTemporary(60)
186 + .fromApp(appId).build();
187 +
188 + flowRuleService.applyFlowRules(fr);
189 + pc.send();
190 + } else {
191 + /*
192 + * else, the output port has not been learned yet. Flood the packet to all ports using
193 + * the actLikeHub method
194 + */
195 + actLikeHub(pc);
196 + }
197 + }
198 +
199 + /**
200 + * puts the ConnectPoint's device Id into the map macTables if it has not previously been added.
201 + * @param cp ConnectPoint containing the required DeviceId for the map
202 + */
203 + private void initMacTable(ConnectPoint cp) {
204 + macTables.putIfAbsent(cp.deviceId(), Maps.newConcurrentMap());
205 +
206 + }
207 + }
208 +}
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
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 implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.learningswitch;
17 +
18 +import com.google.common.collect.Maps;
19 +import org.apache.felix.scr.annotations.Activate;
20 +import org.apache.felix.scr.annotations.Deactivate;
21 +import org.apache.felix.scr.annotations.Component;
22 +import org.apache.felix.scr.annotations.Reference;
23 +import org.apache.felix.scr.annotations.ReferenceCardinality;
24 +import org.onlab.packet.Ethernet;
25 +import org.onlab.packet.MacAddress;
26 +import org.onosproject.core.ApplicationId;
27 +import org.onosproject.core.CoreService;
28 +import org.onosproject.net.ConnectPoint;
29 +import org.onosproject.net.DeviceId;
30 +import org.onosproject.net.PortNumber;
31 +import org.onosproject.net.flow.DefaultTrafficSelector;
32 +import org.onosproject.net.flow.FlowRuleService;
33 +import org.onosproject.net.packet.PacketContext;
34 +import org.onosproject.net.packet.PacketPriority;
35 +import org.onosproject.net.packet.PacketProcessor;
36 +import org.onosproject.net.packet.PacketService;
37 +import org.slf4j.Logger;
38 +import org.slf4j.LoggerFactory;
39 +
40 +import java.util.Map;
41 +import java.util.Optional;
42 +
43 +/**
44 + * Tutorial class used to help build a basic onos learning switch application.
45 + * Edit your code in the activate, deactivate, and actLikeSwitch methods.
46 + */
47 +@Component(immediate = true)
48 +public class LearningSwitchTutorial {
49 + // Instantiates the relevant services.
50 +
51 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
52 + protected PacketService packetService;
53 +
54 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
55 + protected FlowRuleService flowRuleService;
56 +
57 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
58 + protected CoreService coreService;
59 +
60 + private final Logger log = LoggerFactory.getLogger(getClass());
61 +
62 + /*
63 + * Defining macTables as a concurrent map allows multiple threads and packets to
64 + * use the map without an issue.
65 + */
66 + protected Map<DeviceId, Map<MacAddress, PortNumber>> macTables = Maps.newConcurrentMap();
67 + private ApplicationId appId;
68 + private PacketProcessor processor;
69 +
70 + /**
71 + * Create a variable of the SwitchPacketProcessor class using the PacketProcessor defined above.
72 + * Activates the app.
73 + *
74 + * Create code to add a processor
75 + */
76 + @Activate
77 + protected void activate() {
78 + log.info("Started");
79 + appId = coreService.getAppId("org.onosproject.learningswitch"); //equal to the name shown in pom.xml file
80 +
81 + //Create and processor and add it using packetService
82 +
83 + /*
84 + * Restricts packet types to IPV4 and ARP by only requesting those types
85 + */
86 + packetService.requestPackets(DefaultTrafficSelector.builder()
87 + .matchEthType(Ethernet.TYPE_IPV4).build(), PacketPriority.REACTIVE, appId, Optional.empty());
88 + packetService.requestPackets(DefaultTrafficSelector.builder()
89 + .matchEthType(Ethernet.TYPE_ARP).build(), PacketPriority.REACTIVE, appId, Optional.empty());
90 + }
91 +
92 + /**
93 + * Deactivates the processor by removing it.
94 + *
95 + * Create code to remove the processor.
96 + */
97 + @Deactivate
98 + protected void deactivate() {
99 + log.info("Stopped");
100 +
101 + //Remove the processor
102 + }
103 +
104 + /**
105 + * This class contains pseudo code that you must replace with your own code in actLikeSwitch. Your job is to
106 + * send the packet out the port previously learned for the destination MAC. If it does not exist,
107 + * flood the packet out (to all ports).
108 + */
109 + private class SwitchPacketProcesser implements PacketProcessor {
110 + /**
111 + * Learns the source port associated with the packet's DeviceId if it has not already been learned.
112 + * Calls actLikeSwitch to process and send the packet.
113 + * @param pc PacketContext object containing packet info
114 + */
115 + @Override
116 + public void process(PacketContext pc) {
117 + log.info(pc.toString());
118 + /*
119 + * Puts the packet's source's device Id into the map macTables if it has not previously been added.
120 + * (learns the output port)
121 + */
122 + ConnectPoint cp = pc.inPacket().receivedFrom();
123 + macTables.putIfAbsent(cp.deviceId(), Maps.newConcurrentMap());
124 +
125 +
126 +
127 + // This method simply floods all ports with the packet.
128 + actLikeHub(pc);
129 +
130 + /*
131 + * This is the call to the actLikeSwitch method you will be creating. When
132 + * you are ready to test it, uncomment the line below, and comment out the
133 + * actLikeHub call above.
134 + *
135 + * NOTE: The perk of an actLikeSwitch method over actLikeHub is speed.
136 + * FlowRule allows much faster processing.
137 + */
138 + //actLikeSwitch(pc);
139 + }
140 +
141 + /**
142 + * Example method. Floods packet out of all switch ports.
143 + *
144 + * @param pc the PacketContext object passed through from activate method
145 + */
146 + public void actLikeHub(PacketContext pc) {
147 + pc.treatmentBuilder().setOutput(PortNumber.FLOOD);
148 + pc.send();
149 + }
150 +
151 + /**
152 + * Ensures packet is of required type. Obtain the port number associated with the packet's source ID.
153 + * If this port has previously been learned (in the process method) build a flow using the packet's
154 + * out port, treatment, destination, and other properties. Send the flow to the learned out port.
155 + * Otherwise, flood packet to all ports if out port has not been learned.
156 + *
157 + * @param pc the PacketContext object passed through from activate() method
158 + */
159 + public void actLikeSwitch(PacketContext pc) {
160 +
161 + /*
162 + * Ensures the type of packet being processed is only of type IPV4 or ARP (not LLDP or BDDP).
163 + * If it is not, return and do nothing with the packet. actLikeSwitch can only process
164 + * IPV4 and ARP packets.
165 + */
166 + Short type = pc.inPacket().parsed().getEtherType();
167 + if (type != Ethernet.TYPE_IPV4 && type != Ethernet.TYPE_ARP) {
168 + return;
169 + }
170 +
171 + /*
172 + * Learn the destination, source, and output port of the packet using a ConnectPoint and the
173 + * associated macTable. If there is a known port associated with the packet's destination MAC Address,
174 + * the output port will not be null.
175 + */
176 + //find the packets connect point
177 + //save the macTables port value for the deviceID
178 + //save the outPort as a variable
179 + //PortNumber outPort = ...
180 +
181 + /*
182 + * If port is known, set output port to the packet's learned output port and construct a
183 + * FlowRule using a source, destination, treatment and other properties. Send the FlowRule
184 + * to the designated output port.
185 + */
186 + //if outPort isn't null
187 + //construct FlowRule
188 + //FlowRule fr = ...
189 + //send the packet
190 +
191 + /*
192 + * else, the output port has not been learned yet. Flood the packet to all ports using
193 + * the actLikeHub method
194 + */
195 + //else
196 + // call actLikeHub method
197 + }
198 + }
199 +}
1 +/*
2 + * Copyright 2016-present Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
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 implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +/**
18 + * Learning Switch Tutorial
19 + */
20 +package org.onosproject.learningswitch;
...\ No newline at end of file ...\ No newline at end of file