sangho
Committed by Gerrit Code Review

ONOS-686, 687, 1344 : The first commit for the Segment Routing application

 - ICMP/ARP/IP handlers are implemented as a part of the application for now
 - Default routing and link add/failure/recovery are also supprted
 - Temporary NetworkConfigHandler, which is hardcoded to support only 6 router FISH topology, is used for test
 - Some fixes on GroupHanlder app to support transit routers
 - Supports multi-instance (tested with two instances)

Change-Id: Idfa67903e59e1c4cac4da430f89cd4c50e821420
Showing 19 changed files with 2509 additions and 445 deletions
...@@ -152,11 +152,13 @@ public class DefaultGroupHandler { ...@@ -152,11 +152,13 @@ public class DefaultGroupHandler {
152 * @param newLink new neighbor link 152 * @param newLink new neighbor link
153 */ 153 */
154 public void linkUp(Link newLink) { 154 public void linkUp(Link newLink) {
155 +
155 if (newLink.type() != Link.Type.DIRECT) { 156 if (newLink.type() != Link.Type.DIRECT) {
156 log.warn("linkUp: unknown link type"); 157 log.warn("linkUp: unknown link type");
157 return; 158 return;
158 } 159 }
159 160
161 +
160 if (!newLink.src().deviceId().equals(deviceId)) { 162 if (!newLink.src().deviceId().equals(deviceId)) {
161 log.warn("linkUp: deviceId{} doesn't match with link src{}", 163 log.warn("linkUp: deviceId{} doesn't match with link src{}",
162 deviceId, 164 deviceId,
...@@ -307,13 +309,11 @@ public class DefaultGroupHandler { ...@@ -307,13 +309,11 @@ public class DefaultGroupHandler {
307 309
308 List<Integer> nsSegmentIds = new ArrayList<Integer>(); 310 List<Integer> nsSegmentIds = new ArrayList<Integer>();
309 311
310 - // Add one entry for "no label" (-1) to the list if 312 + // Always pair up with no edge label
311 - // dpid list has not more than one node/neighbor as 313 + //If (neighbors.size() == 1) {
312 - // there will never be a case a packet going to more than one
313 - // neighbor without a label at an edge router
314 - if (neighbors.size() == 1) {
315 nsSegmentIds.add(-1); 314 nsSegmentIds.add(-1);
316 - } 315 + //}
316 +
317 // Filter out SegmentIds matching with the 317 // Filter out SegmentIds matching with the
318 // nodes in the combo 318 // nodes in the combo
319 for (Integer sId : allSegmentIds) { 319 for (Integer sId : allSegmentIds) {
...@@ -405,7 +405,8 @@ public class DefaultGroupHandler { ...@@ -405,7 +405,8 @@ public class DefaultGroupHandler {
405 } 405 }
406 } 406 }
407 407
408 - protected GroupKey getGroupKey(Object obj) { 408 + public GroupKey getGroupKey(Object obj) {
409 return new DefaultGroupKey(kryo.build().serialize(obj)); 409 return new DefaultGroupKey(kryo.build().serialize(obj));
410 } 410 }
411 +
411 } 412 }
......
...@@ -90,6 +90,7 @@ public class DefaultGroupHandlerApp { ...@@ -90,6 +90,7 @@ public class DefaultGroupHandlerApp {
90 public void activate() { 90 public void activate() {
91 appId = coreService.registerApplication("org.onosproject.defaultgrouphandler"); 91 appId = coreService.registerApplication("org.onosproject.defaultgrouphandler");
92 log.info("DefaultGroupHandlerApp Activating"); 92 log.info("DefaultGroupHandlerApp Activating");
93 +
93 deviceService.addListener(deviceListener); 94 deviceService.addListener(deviceListener);
94 linkService.addListener(linkListener); 95 linkService.addListener(linkListener);
95 for (Device device: deviceService.getDevices()) { 96 for (Device device: deviceService.getDevices()) {
...@@ -111,6 +112,7 @@ public class DefaultGroupHandlerApp { ...@@ -111,6 +112,7 @@ public class DefaultGroupHandlerApp {
111 device.id()); 112 device.id());
112 } 113 }
113 } 114 }
115 +
114 log.info("Activated"); 116 log.info("Activated");
115 } 117 }
116 118
......
...@@ -138,7 +138,8 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler { ...@@ -138,7 +138,8 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler {
138 Set<DeviceId> updatedNeighbors) { 138 Set<DeviceId> updatedNeighbors) {
139 Set<Set<DeviceId>> powerSet = getPowerSetOfNeighbors(updatedNeighbors); 139 Set<Set<DeviceId>> powerSet = getPowerSetOfNeighbors(updatedNeighbors);
140 140
141 - Set<DeviceId> tmp = updatedNeighbors; 141 + Set<DeviceId> tmp = new HashSet<DeviceId>();
142 + tmp.addAll(updatedNeighbors);
142 tmp.remove(impactedNeighbor); 143 tmp.remove(impactedNeighbor);
143 Set<Set<DeviceId>> tmpPowerSet = getPowerSetOfNeighbors(tmp); 144 Set<Set<DeviceId>> tmpPowerSet = getPowerSetOfNeighbors(tmp);
144 145
......
...@@ -45,6 +45,8 @@ ...@@ -45,6 +45,8 @@
45 <module>reactive-routing</module> 45 <module>reactive-routing</module>
46 <module>bgprouter</module> 46 <module>bgprouter</module>
47 <module>test</module> 47 <module>test</module>
48 + <module>grouphandler</module>
49 + <module>segmentrouting</module>
48 </modules> 50 </modules>
49 51
50 <properties> 52 <properties>
......
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2014 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 + --><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">
17 + <modelVersion>4.0.0</modelVersion>
18 + <parent>
19 + <artifactId>onos-apps</artifactId>
20 + <groupId>org.onosproject</groupId>
21 + <version>1.2.0-SNAPSHOT</version>
22 + </parent>
23 +
24 + <artifactId>onos-app-segmentrouting</artifactId>
25 + <packaging>bundle</packaging>
26 +
27 + <description>ONOS OSGi bundle archetype</description>
28 + <url>http://onosproject.org</url>
29 +
30 + <dependencies>
31 + <dependency>
32 + <groupId>org.onosproject</groupId>
33 + <artifactId>onos-app-grouphandler</artifactId>
34 + <version>1.2.0-SNAPSHOT</version>
35 + </dependency>
36 + </dependencies>
37 +
38 +</project>
1 +/*
2 + * Copyright 2015 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.segmentrouting;
17 +
18 +import org.onlab.packet.ARP;
19 +import org.onlab.packet.Ethernet;
20 +import org.onlab.packet.Ip4Address;
21 +import org.onlab.packet.IpAddress;
22 +import org.onlab.packet.IpPrefix;
23 +import org.onlab.packet.MacAddress;
24 +import org.onosproject.net.ConnectPoint;
25 +import org.onosproject.net.DeviceId;
26 +import org.onosproject.net.Host;
27 +import org.onosproject.net.Port;
28 +import org.onosproject.net.PortNumber;
29 +import org.onosproject.net.flow.DefaultTrafficTreatment;
30 +import org.onosproject.net.flow.TrafficTreatment;
31 +import org.onosproject.net.packet.DefaultOutboundPacket;
32 +import org.onosproject.net.packet.InboundPacket;
33 +import org.onosproject.net.HostId;
34 +import org.onosproject.net.packet.OutboundPacket;
35 +import org.slf4j.Logger;
36 +import org.slf4j.LoggerFactory;
37 +
38 +import java.nio.ByteBuffer;
39 +
40 +import static com.google.common.base.Preconditions.checkNotNull;
41 +
42 +public class ArpHandler {
43 +
44 + private static Logger log = LoggerFactory.getLogger(ArpHandler.class);
45 +
46 + private SegmentRoutingManager srManager;
47 + private NetworkConfigHandler config;
48 +
49 + /**
50 + * Creates an ArpHandler object.
51 + *
52 + * @param srManager SegmentRoutingManager object
53 + */
54 + public ArpHandler(SegmentRoutingManager srManager) {
55 + this.srManager = srManager;
56 + this.config = checkNotNull(srManager.networkConfigHandler);
57 + }
58 +
59 + /**
60 + * Processes incoming ARP packets.
61 + * If it is an ARP request to router itself or known hosts,
62 + * then it sends ARP response.
63 + * If it is an ARP request to unknown hosts in its own subnet,
64 + * then it flood the ARP request to the ports.
65 + * If it is an ARP response, then set a flow rule for the host
66 + * and forward any IP packets to the host in the packet buffer to the host.
67 + *
68 + * @param pkt incoming packet
69 + */
70 + public void processPacketIn(InboundPacket pkt) {
71 +
72 + Ethernet ethernet = pkt.parsed();
73 + ARP arp = (ARP) ethernet.getPayload();
74 +
75 + ConnectPoint connectPoint = pkt.receivedFrom();
76 + PortNumber inPort = connectPoint.port();
77 + DeviceId deviceId = connectPoint.deviceId();
78 + byte[] senderMacAddressByte = arp.getSenderHardwareAddress();
79 + Ip4Address hostIpAddress = Ip4Address.valueOf(arp.getSenderProtocolAddress());
80 +
81 + srManager.routingRulePopulator.populateIpRuleForHost(deviceId, hostIpAddress, MacAddress.
82 + valueOf(senderMacAddressByte), inPort);
83 +
84 + if (arp.getOpCode() == ARP.OP_REQUEST) {
85 + handleArpRequest(deviceId, connectPoint, ethernet);
86 + } else {
87 + srManager.ipHandler.forwardPackets(deviceId, hostIpAddress);
88 + }
89 + }
90 +
91 + private void handleArpRequest(DeviceId deviceId, ConnectPoint inPort, Ethernet payload) {
92 +
93 + ARP arpRequest = (ARP) payload.getPayload();
94 + HostId targetHostId = HostId.hostId(MacAddress.valueOf(
95 + arpRequest.getTargetHardwareAddress()));
96 +
97 + // ARP request for router
98 + if (isArpReqForRouter(deviceId, arpRequest)) {
99 + Ip4Address targetAddress = Ip4Address.valueOf(arpRequest.getTargetProtocolAddress());
100 + sendArpResponse(arpRequest, config.getRouterMac(targetAddress));
101 +
102 + // ARP request for known hosts
103 + } else if (srManager.hostService.getHost(targetHostId) != null) {
104 + MacAddress targetMac = srManager.hostService.getHost(targetHostId).mac();
105 + sendArpResponse(arpRequest, targetMac);
106 +
107 + // ARP request for unknown host in the subnet
108 + } else if (isArpReqForSubnet(deviceId, arpRequest)) {
109 + flood(payload, inPort);
110 + }
111 + }
112 +
113 +
114 + private boolean isArpReqForRouter(DeviceId deviceId, ARP arpRequest) {
115 + Ip4Address gatewayIpAddress = config.getGatewayIpAddress(deviceId);
116 + if (gatewayIpAddress != null) {
117 + Ip4Address targetProtocolAddress = Ip4Address.valueOf(arpRequest
118 + .getTargetProtocolAddress());
119 + if (gatewayIpAddress.equals(targetProtocolAddress)) {
120 + return true;
121 + }
122 + }
123 + return false;
124 + }
125 +
126 + private boolean isArpReqForSubnet(DeviceId deviceId, ARP arpRequest) {
127 + String subnetInfo = config.getSubnetInfo(deviceId);
128 + if (subnetInfo != null) {
129 + IpPrefix prefix = IpPrefix.valueOf(subnetInfo);
130 + if (prefix.contains(Ip4Address.valueOf(arpRequest.getTargetProtocolAddress()))) {
131 + return true;
132 + }
133 + }
134 +
135 + return false;
136 + }
137 +
138 + /**
139 + * Sends an APR request for the target IP address to all ports except in-port.
140 + *
141 + * @param deviceId Switch device ID
142 + * @param targetAddress target IP address for ARP
143 + * @param inPort in-port
144 + */
145 + public void sendArpRequest(DeviceId deviceId, IpAddress targetAddress, ConnectPoint inPort) {
146 +
147 + byte[] senderMacAddress = config.getRouterMacAddress(deviceId).toBytes();
148 + byte[] senderIpAddress = config.getRouterIpAddress(deviceId)
149 + .getIp4Prefix().address().toOctets();
150 +
151 + ARP arpRequest = new ARP();
152 + arpRequest.setHardwareType(ARP.HW_TYPE_ETHERNET)
153 + .setProtocolType(ARP.PROTO_TYPE_IP)
154 + .setHardwareAddressLength(
155 + (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
156 + .setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH)
157 + .setOpCode(ARP.OP_REQUEST)
158 + .setSenderHardwareAddress(senderMacAddress)
159 + .setTargetHardwareAddress(MacAddress.ZERO.toBytes())
160 + .setSenderProtocolAddress(senderIpAddress)
161 + .setTargetProtocolAddress(targetAddress.toOctets());
162 +
163 + Ethernet eth = new Ethernet();
164 + eth.setDestinationMACAddress(MacAddress.BROADCAST.toBytes())
165 + .setSourceMACAddress(senderMacAddress)
166 + .setEtherType(Ethernet.TYPE_ARP).setPayload(arpRequest);
167 +
168 + flood(eth, inPort);
169 + }
170 +
171 + private void sendArpResponse(ARP arpRequest, MacAddress targetMac) {
172 +
173 + ARP arpReply = new ARP();
174 + arpReply.setHardwareType(ARP.HW_TYPE_ETHERNET)
175 + .setProtocolType(ARP.PROTO_TYPE_IP)
176 + .setHardwareAddressLength(
177 + (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
178 + .setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH)
179 + .setOpCode(ARP.OP_REPLY)
180 + .setSenderHardwareAddress(targetMac.toBytes())
181 + .setSenderProtocolAddress(arpRequest.getTargetProtocolAddress())
182 + .setTargetHardwareAddress(arpRequest.getSenderHardwareAddress())
183 + .setTargetProtocolAddress(arpRequest.getSenderProtocolAddress());
184 +
185 + Ethernet eth = new Ethernet();
186 + eth.setDestinationMACAddress(arpRequest.getSenderHardwareAddress())
187 + .setSourceMACAddress(targetMac.toBytes())
188 + .setEtherType(Ethernet.TYPE_ARP).setPayload(arpReply);
189 +
190 +
191 + HostId dstId = HostId.hostId(MacAddress.valueOf(
192 + arpReply.getTargetHardwareAddress()));
193 + Host dst = srManager.hostService.getHost(dstId);
194 + if (dst == null) {
195 + log.warn("Cannot send ARP response to unknown device");
196 + return;
197 + }
198 +
199 + TrafficTreatment treatment = DefaultTrafficTreatment.builder().
200 + setOutput(dst.location().port()).build();
201 + OutboundPacket packet = new DefaultOutboundPacket(dst.location().deviceId(),
202 + treatment, ByteBuffer.wrap(eth.serialize()));
203 +
204 + srManager.packetService.emit(packet);
205 + }
206 +
207 + private void flood(Ethernet request, ConnectPoint inPort) {
208 + TrafficTreatment.Builder builder;
209 + ByteBuffer buf = ByteBuffer.wrap(request.serialize());
210 +
211 + for (Port port: srManager.deviceService.getPorts(inPort.deviceId())) {
212 + if (!port.number().equals(inPort.port()) &&
213 + port.number().toLong() > 0) {
214 + builder = DefaultTrafficTreatment.builder();
215 + builder.setOutput(port.number());
216 + srManager.packetService.emit(new DefaultOutboundPacket(inPort.deviceId(),
217 + builder.build(), buf));
218 + }
219 + }
220 + }
221 +
222 +}
1 +/*
2 + * Copyright 2015 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.segmentrouting;
17 +
18 +import org.onlab.packet.IpPrefix;
19 +import org.onosproject.net.Device;
20 +import org.onosproject.net.DeviceId;
21 +import org.onosproject.net.MastershipRole;
22 +import org.onosproject.net.flow.FlowRule;
23 +import org.slf4j.Logger;
24 +import org.slf4j.LoggerFactory;
25 +
26 +import java.util.ArrayList;
27 +import java.util.HashMap;
28 +import java.util.HashSet;
29 +import java.util.Set;
30 +
31 +import static com.google.common.base.Preconditions.checkNotNull;
32 +
33 +public class DefaultRoutingHandler {
34 +
35 + private static Logger log = LoggerFactory.getLogger(DefaultRoutingHandler.class);
36 +
37 + private SegmentRoutingManager srManager;
38 + private RoutingRulePopulator rulePopulator;
39 + private NetworkConfigHandler config;
40 + private Status populationStatus;
41 +
42 + /**
43 + * Represents the default routing population status.
44 + */
45 + public enum Status {
46 + // population process is not started yet.
47 + IDLE,
48 +
49 + // population process started.
50 + STARTED,
51 +
52 + // population process was aborted due to errors, mostly for groups not found.
53 + ABORTED,
54 +
55 + // population process was finished successfully.
56 + SUCCEEDED
57 + }
58 +
59 + /**
60 + * Creates a DefaultRoutingHandler object.
61 + *
62 + * @param srManager SegmentRoutingManager object
63 + */
64 + public DefaultRoutingHandler(SegmentRoutingManager srManager) {
65 + this.srManager = srManager;
66 + this.rulePopulator = checkNotNull(srManager.routingRulePopulator);
67 + this.config = checkNotNull(srManager.networkConfigHandler);
68 + this.populationStatus = Status.IDLE;
69 + }
70 +
71 + /**
72 + * Populates all routing rules to all connected routers, including default
73 + * routing rules, adjacency rules, and policy rules if any.
74 + *
75 + * @return true if it succeeds in populating all rules, otherwise false
76 + */
77 + public boolean populateAllRoutingRules() {
78 +
79 + populationStatus = Status.STARTED;
80 + log.info("Starts to populate routing rules");
81 +
82 + for (Device sw : srManager.deviceService.getDevices()) {
83 + if (srManager.mastershipService.
84 + getLocalRole(sw.id()) != MastershipRole.MASTER) {
85 + continue;
86 + }
87 +
88 + ECMPShortestPathGraph ecmpSPG = new ECMPShortestPathGraph(sw.id(), srManager);
89 + if (!populateEcmpRoutingRules(sw, ecmpSPG)) {
90 + populationStatus = Status.ABORTED;
91 + log.debug("Abort routing rule population");
92 + return false;
93 + }
94 +
95 + // TODO: Set adjacency routing rule for all switches
96 + }
97 +
98 + populationStatus = Status.SUCCEEDED;
99 + log.info("Completes routing rule population");
100 + return true;
101 + }
102 +
103 + private boolean populateEcmpRoutingRules(Device sw,
104 + ECMPShortestPathGraph ecmpSPG) {
105 +
106 + HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
107 + ecmpSPG.getAllLearnedSwitchesAndVia();
108 + for (Integer itrIdx : switchVia.keySet()) {
109 + HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
110 + switchVia.get(itrIdx);
111 + for (DeviceId targetSw : swViaMap.keySet()) {
112 + DeviceId destSw = sw.id();
113 + Set<DeviceId> nextHops = new HashSet<>();
114 +
115 + for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
116 + if (via.isEmpty()) {
117 + nextHops.add(destSw);
118 + } else {
119 + nextHops.add(via.get(0));
120 + }
121 + }
122 + if (!populateEcmpRoutingRulePartial(targetSw, destSw, nextHops)) {
123 + return false;
124 + }
125 + }
126 + }
127 +
128 + return true;
129 + }
130 +
131 + private boolean populateEcmpRoutingRulePartial(DeviceId targetSw, DeviceId destSw,
132 + Set<DeviceId> nextHops) {
133 + boolean result;
134 +
135 + if (nextHops.isEmpty()) {
136 + nextHops.add(destSw);
137 + }
138 +
139 + // If both target switch and dest switch are edge routers, then set IP rule
140 + // for both subnet and router IP.
141 + if (config.isEdgeRouter(targetSw) && config.isEdgeRouter(destSw)) {
142 + String subnets = config.getSubnetInfo(destSw);
143 + result = rulePopulator.populateIpRuleForSubnet(targetSw, subnets, destSw, nextHops);
144 + if (!result) {
145 + return false;
146 + }
147 +
148 + IpPrefix routerIp = config.getRouterIpAddress(destSw);
149 + result = rulePopulator.populateIpRuleForRouter(targetSw, routerIp, destSw, nextHops);
150 + if (!result) {
151 + return false;
152 + }
153 +
154 + // If the target switch is an edge router, then set IP rules for the router IP.
155 + } else if (config.isEdgeRouter(targetSw)) {
156 + IpPrefix routerIp = config.getRouterIpAddress(destSw);
157 + result = rulePopulator.populateIpRuleForRouter(targetSw, routerIp, destSw, nextHops);
158 + if (!result) {
159 + return false;
160 + }
161 +
162 + // If the target switch is an transit router, then set MPLS rules only.
163 + } else if (config.isTransitRouter(targetSw)) {
164 + result = rulePopulator.populateMplsRule(targetSw, destSw, nextHops);
165 + if (!result) {
166 + return false;
167 + }
168 + } else {
169 + log.warn("The switch {} is neither an edge router nor a transit router.", targetSw);
170 + return false;
171 + }
172 +
173 + return true;
174 + }
175 +
176 + /**
177 + * Populates table miss entries for all tables, and pipeline rules for
178 + * VLAN and TACM tables.
179 + *
180 + * @param deviceId Switch ID to set the rules
181 + */
182 + public void populateTtpRules(DeviceId deviceId) {
183 +
184 + rulePopulator.populateTableMissEntry(deviceId, FlowRule.Type.VLAN,
185 + true, false, false, FlowRule.Type.DEFAULT);
186 + rulePopulator.populateTableMissEntry(deviceId, FlowRule.Type.ETHER,
187 + true, false, false, FlowRule.Type.DEFAULT);
188 + rulePopulator.populateTableMissEntry(deviceId, FlowRule.Type.IP,
189 + false, true, true, FlowRule.Type.ACL);
190 + rulePopulator.populateTableMissEntry(deviceId, FlowRule.Type.MPLS,
191 + false, true, true, FlowRule.Type.ACL);
192 + rulePopulator.populateTableMissEntry(deviceId, FlowRule.Type.ACL,
193 + false, false, false, FlowRule.Type.DEFAULT);
194 +
195 + rulePopulator.populateTableVlan(deviceId);
196 + rulePopulator.populateTableTMac(deviceId);
197 + }
198 +
199 + /**
200 + * Start the flow rule population process if it was never started.
201 + * The process finishes successfully when all flow rules are set and
202 + * stops with ABORTED status when any groups required for flows is not
203 + * set yet.
204 + */
205 + public void startPopulationProcess() {
206 + synchronized (populationStatus) {
207 + if (populationStatus == Status.IDLE ||
208 + populationStatus == Status.SUCCEEDED) {
209 + populationStatus = Status.STARTED;
210 + populateAllRoutingRules();
211 + }
212 + }
213 + }
214 +
215 + /**
216 + * Resume the flow rule population process if it was aborted for any reason.
217 + * Mostly the process is aborted when the groups required are not set yet.
218 + */
219 + public void resumePopulationProcess() {
220 + synchronized (populationStatus) {
221 + if (populationStatus == Status.ABORTED) {
222 + populationStatus = Status.STARTED;
223 + // TODO: we need to restart from the point aborted instead of restarting.
224 + populateAllRoutingRules();
225 + }
226 + }
227 + }
228 +}
1 +package org.onosproject.segmentrouting;
2 +
3 +import org.onlab.packet.Ip4Address;
4 +import org.onlab.packet.MacAddress;
5 +import org.onosproject.grouphandler.DeviceProperties;
6 +import org.onosproject.net.DeviceId;
7 +import org.slf4j.Logger;
8 +import org.slf4j.LoggerFactory;
9 +
10 +import java.util.Arrays;
11 +import java.util.HashMap;
12 +import java.util.List;
13 +import java.util.Map;
14 +
15 +public class DeviceConfiguration implements DeviceProperties {
16 +
17 + private static final Logger log = LoggerFactory
18 + .getLogger(DeviceConfiguration.class);
19 + private final List<Integer> allSegmentIds =
20 + Arrays.asList(101, 102, 103, 104, 105, 106);
21 + private HashMap<DeviceId, Integer> deviceSegmentIdMap =
22 + new HashMap<DeviceId, Integer>() {
23 + {
24 + put(DeviceId.deviceId("of:0000000000000001"), 101);
25 + put(DeviceId.deviceId("of:0000000000000002"), 102);
26 + put(DeviceId.deviceId("of:0000000000000003"), 103);
27 + put(DeviceId.deviceId("of:0000000000000004"), 104);
28 + put(DeviceId.deviceId("of:0000000000000005"), 105);
29 + put(DeviceId.deviceId("of:0000000000000006"), 106);
30 + }
31 + };
32 + private final HashMap<DeviceId, MacAddress> deviceMacMap =
33 + new HashMap<DeviceId, MacAddress>() {
34 + {
35 + put(DeviceId.deviceId("of:0000000000000001"),
36 + MacAddress.valueOf("00:00:00:00:00:01"));
37 + put(DeviceId.deviceId("of:0000000000000002"),
38 + MacAddress.valueOf("00:00:00:00:00:02"));
39 + put(DeviceId.deviceId("of:0000000000000003"),
40 + MacAddress.valueOf("00:00:00:00:00:03"));
41 + put(DeviceId.deviceId("of:0000000000000004"),
42 + MacAddress.valueOf("00:00:00:00:00:04"));
43 + put(DeviceId.deviceId("of:0000000000000005"),
44 + MacAddress.valueOf("00:00:00:00:00:05"));
45 + put(DeviceId.deviceId("of:0000000000000006"),
46 + MacAddress.valueOf("00:00:00:00:00:06"));
47 + }
48 + };
49 +
50 + private final HashMap<DeviceId, Ip4Address> deviceIpMap =
51 + new HashMap<DeviceId, Ip4Address>() {
52 + {
53 + put(DeviceId.deviceId("of:0000000000000001"),
54 + Ip4Address.valueOf("192.168.0.1"));
55 + put(DeviceId.deviceId("of:0000000000000002"),
56 + Ip4Address.valueOf("192.168.0.2"));
57 + put(DeviceId.deviceId("of:0000000000000003"),
58 + Ip4Address.valueOf("192.168.0.3"));
59 + put(DeviceId.deviceId("of:0000000000000004"),
60 + Ip4Address.valueOf("192.168.0.4"));
61 + put(DeviceId.deviceId("of:0000000000000005"),
62 + Ip4Address.valueOf("192.168.0.5"));
63 + put(DeviceId.deviceId("of:0000000000000006"),
64 + Ip4Address.valueOf("192.168.0.6"));
65 + }
66 + };
67 +
68 + @Override
69 + public int getSegmentId(DeviceId deviceId) {
70 + if (deviceSegmentIdMap.get(deviceId) != null) {
71 + log.debug("getSegmentId for device{} is {}",
72 + deviceId,
73 + deviceSegmentIdMap.get(deviceId));
74 + return deviceSegmentIdMap.get(deviceId);
75 + } else {
76 + throw new IllegalStateException();
77 + }
78 + }
79 +
80 +
81 + @Override
82 + public MacAddress getDeviceMac(DeviceId deviceId) {
83 + if (deviceMacMap.get(deviceId) != null) {
84 + log.debug("getDeviceMac for device{} is {}",
85 + deviceId,
86 + deviceMacMap.get(deviceId));
87 + return deviceMacMap.get(deviceId);
88 + } else {
89 + throw new IllegalStateException();
90 + }
91 + }
92 +
93 +
94 + @Override
95 + public boolean isEdgeDevice(DeviceId deviceId) {
96 + if (deviceId.equals(DeviceId.deviceId("of:0000000000000001"))
97 + || deviceId.equals(DeviceId.deviceId("of:0000000000000006"))) {
98 + return true;
99 + }
100 +
101 + return false;
102 + }
103 +
104 + @Override
105 + public List<Integer> getAllDeviceSegmentIds() {
106 + return allSegmentIds;
107 + }
108 +
109 +
110 + /**
111 + * Returns Segment ID for the router with the MAC address given.
112 + *
113 + * @param targetMac Mac address for the router
114 + * @return Segment ID for the router with the MAC address
115 + */
116 + public int getSegmentId(MacAddress targetMac) {
117 + for (Map.Entry<DeviceId, MacAddress> entry: deviceMacMap.entrySet()) {
118 + if (entry.getValue().equals(targetMac)) {
119 + return deviceSegmentIdMap.get(entry.getKey());
120 + }
121 + }
122 +
123 + return -1;
124 + }
125 +
126 + /**
127 + * Returns Segment ID for the router withe IP address given.
128 + *
129 + * @param targetAddress IP address of the router
130 + * @return Segment ID for the router with the IP address
131 + */
132 + public int getSegmentId(Ip4Address targetAddress) {
133 + for (Map.Entry<DeviceId, Ip4Address> entry: deviceIpMap.entrySet()) {
134 + if (entry.getValue().equals(targetAddress)) {
135 + return deviceSegmentIdMap.get(entry.getKey());
136 + }
137 + }
138 +
139 + return -1;
140 + }
141 +
142 + /**
143 + * Returns Router IP address for the router with the device ID given.
144 + *
145 + * @param deviceId device ID of the router
146 + * @return IP address of the router
147 + */
148 + public Ip4Address getRouterIp(DeviceId deviceId) {
149 + if (deviceIpMap.get(deviceId) != null) {
150 + log.debug("getDeviceIp for device{} is {}",
151 + deviceId,
152 + deviceIpMap.get(deviceId));
153 + return deviceIpMap.get(deviceId);
154 + } else {
155 + throw new IllegalStateException();
156 + }
157 + }
158 +
159 + /**
160 + * Returns the Device ID of the router with the Segment ID given.
161 + *
162 + * @param sid Segment ID of the router
163 + * @return Device ID of the router
164 + */
165 + public DeviceId getDeviceId(int sid) {
166 + for (Map.Entry<DeviceId, Integer> entry: deviceSegmentIdMap.entrySet()) {
167 + if (entry.getValue() == sid) {
168 + return entry.getKey();
169 + }
170 + }
171 +
172 + return null;
173 + }
174 +
175 + /**
176 + * Returns the Device ID of the router with the IP address given.
177 + *
178 + * @param ipAddress IP address of the router
179 + * @return Device ID of the router
180 + */
181 + public DeviceId getDeviceId(Ip4Address ipAddress) {
182 + for (Map.Entry<DeviceId, Ip4Address> entry: deviceIpMap.entrySet()) {
183 + if (entry.getValue().equals(ipAddress)) {
184 + return entry.getKey();
185 + }
186 + }
187 +
188 + return null;
189 + }
190 +}
1 +/*
2 + * Copyright 2015 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.segmentrouting;
17 +
18 +import org.onosproject.net.DefaultLink;
19 +import org.onosproject.net.DefaultPath;
20 +import org.onosproject.net.Device;
21 +import org.onosproject.net.DeviceId;
22 +import org.onosproject.net.Link;
23 +import org.onosproject.net.Path;
24 +import org.onosproject.net.provider.ProviderId;
25 +import org.slf4j.Logger;
26 +import org.slf4j.LoggerFactory;
27 +import java.util.ArrayList;
28 +import java.util.HashMap;
29 +import java.util.LinkedList;
30 +import java.util.List;
31 +
32 +/**
33 + * This class creates bandwidth constrained breadth first tree and returns paths
34 + * from root Device to leaf Devicees which satisfies the bandwidth condition. If
35 + * bandwidth parameter is not specified, the normal breadth first tree will be
36 + * calculated. The paths are snapshot paths at the point of the class
37 + * instantiation.
38 + */
39 +public class ECMPShortestPathGraph {
40 + LinkedList<DeviceId> deviceQueue = new LinkedList<>();
41 + LinkedList<Integer> distanceQueue = new LinkedList<>();
42 + HashMap<DeviceId, Integer> deviceSearched = new HashMap<>();
43 + HashMap<DeviceId, ArrayList<Link>> upstreamLinks = new HashMap<>();
44 + HashMap<DeviceId, ArrayList<Path>> paths = new HashMap<>();
45 + HashMap<Integer, ArrayList<DeviceId>> distanceDeviceMap = new HashMap<>();
46 + DeviceId rootDevice;
47 + private SegmentRoutingManager srManager;
48 + private static final Logger log = LoggerFactory
49 + .getLogger(ECMPShortestPathGraph.class);
50 +
51 + /**
52 + * Constructor.
53 + *
54 + * @param rootDevice root of the BFS tree
55 + * @param linkListToAvoid link list to avoid
56 + * @param deviceIdListToAvoid device list to avoid
57 + */
58 + public ECMPShortestPathGraph(DeviceId rootDevice, List<String> deviceIdListToAvoid,
59 + List<Link> linkListToAvoid) {
60 + this.rootDevice = rootDevice;
61 + calcECMPShortestPathGraph(deviceIdListToAvoid, linkListToAvoid);
62 + }
63 +
64 + /**
65 + * Constructor.
66 + *
67 + * @param rootDevice root of the BFS tree
68 + * @param srManager SegmentRoutingManager object
69 + */
70 + public ECMPShortestPathGraph(DeviceId rootDevice, SegmentRoutingManager srManager) {
71 + this.rootDevice = rootDevice;
72 + this.srManager = srManager;
73 + calcECMPShortestPathGraph();
74 + }
75 +
76 + /**
77 + * Calculates the BFS tree using any provided constraints and Intents.
78 + */
79 + private void calcECMPShortestPathGraph() {
80 + deviceQueue.add(rootDevice);
81 + int currDistance = 0;
82 + distanceQueue.add(currDistance);
83 + deviceSearched.put(rootDevice, currDistance);
84 + while (!deviceQueue.isEmpty()) {
85 + DeviceId sw = deviceQueue.poll();
86 + DeviceId prevSw = null;
87 + currDistance = distanceQueue.poll();
88 +
89 + for (Link link : srManager.linkService.getDeviceEgressLinks(sw)) {
90 + DeviceId reachedDevice = link.dst().deviceId();
91 + if ((prevSw != null)
92 + && (prevSw.equals(reachedDevice))) {
93 + /* Ignore LAG links between the same set of Devicees */
94 + continue;
95 + } else {
96 + prevSw = reachedDevice;
97 + }
98 +
99 + Integer distance = deviceSearched.get(reachedDevice);
100 + if ((distance != null) && (distance.intValue() < (currDistance + 1))) {
101 + continue;
102 + }
103 + if (distance == null) {
104 + /* First time visiting this Device node */
105 + deviceQueue.add(reachedDevice);
106 + distanceQueue.add(currDistance + 1);
107 + deviceSearched.put(reachedDevice, currDistance + 1);
108 +
109 + ArrayList<DeviceId> distanceSwArray = distanceDeviceMap
110 + .get(currDistance + 1);
111 + if (distanceSwArray == null) {
112 + distanceSwArray = new ArrayList<DeviceId>();
113 + distanceSwArray.add(reachedDevice);
114 + distanceDeviceMap.put(currDistance + 1, distanceSwArray);
115 + } else {
116 + distanceSwArray.add(reachedDevice);
117 + }
118 + }
119 +
120 + ArrayList<Link> upstreamLinkArray =
121 + upstreamLinks.get(reachedDevice);
122 + if (upstreamLinkArray == null) {
123 + upstreamLinkArray = new ArrayList<Link>();
124 + upstreamLinkArray.add(copyDefaultLink(link));
125 + //upstreamLinkArray.add(link);
126 + upstreamLinks.put(reachedDevice, upstreamLinkArray);
127 + } else {
128 + /* ECMP links */
129 + upstreamLinkArray.add(copyDefaultLink(link));
130 + }
131 + }
132 + }
133 + }
134 +
135 + /**
136 + * Calculates the BFS tree using any provided constraints and Intents.
137 + */
138 + private void calcECMPShortestPathGraph(List<String> deviceIdListToAvoid, List<Link> linksToAvoid) {
139 + deviceQueue.add(rootDevice);
140 + int currDistance = 0;
141 + distanceQueue.add(currDistance);
142 + deviceSearched.put(rootDevice, currDistance);
143 + boolean foundLinkToAvoid = false;
144 + while (!deviceQueue.isEmpty()) {
145 + DeviceId sw = deviceQueue.poll();
146 + DeviceId prevSw = null;
147 + currDistance = distanceQueue.poll();
148 + for (Link link : srManager.linkService.getDeviceEgressLinks(sw)) {
149 + for (Link linkToAvoid: linksToAvoid) {
150 + // TODO: equls should work
151 + //if (link.equals(linkToAvoid)) {
152 + if (linkContains(link, linksToAvoid)) {
153 + foundLinkToAvoid = true;
154 + break;
155 + }
156 + }
157 + if (foundLinkToAvoid) {
158 + foundLinkToAvoid = false;
159 + continue;
160 + }
161 + DeviceId reachedDevice = link.dst().deviceId();
162 + if (deviceIdListToAvoid.contains(reachedDevice.toString())) {
163 + continue;
164 + }
165 + if ((prevSw != null)
166 + && (prevSw.equals(reachedDevice))) {
167 + /* Ignore LAG links between the same set of Devicees */
168 + continue;
169 + } else {
170 + prevSw = reachedDevice;
171 + }
172 +
173 + Integer distance = deviceSearched.get(reachedDevice);
174 + if ((distance != null) && (distance.intValue() < (currDistance + 1))) {
175 + continue;
176 + }
177 + if (distance == null) {
178 + /* First time visiting this Device node */
179 + deviceQueue.add(reachedDevice);
180 + distanceQueue.add(currDistance + 1);
181 + deviceSearched.put(reachedDevice, currDistance + 1);
182 +
183 + ArrayList<DeviceId> distanceSwArray = distanceDeviceMap
184 + .get(currDistance + 1);
185 + if (distanceSwArray == null) {
186 + distanceSwArray = new ArrayList<DeviceId>();
187 + distanceSwArray.add(reachedDevice);
188 + distanceDeviceMap.put(currDistance + 1, distanceSwArray);
189 + } else {
190 + distanceSwArray.add(reachedDevice);
191 + }
192 + }
193 +
194 + ArrayList<Link> upstreamLinkArray =
195 + upstreamLinks.get(reachedDevice);
196 + if (upstreamLinkArray == null) {
197 + upstreamLinkArray = new ArrayList<Link>();
198 + upstreamLinkArray.add(copyDefaultLink(link));
199 + upstreamLinks.put(reachedDevice, upstreamLinkArray);
200 + } else {
201 + /* ECMP links */
202 + upstreamLinkArray.add(copyDefaultLink(link));
203 + }
204 + }
205 + }
206 + }
207 +
208 +
209 + private boolean linkContains(Link link, List<Link> links) {
210 +
211 + DeviceId srcDevice1 = link.src().deviceId();
212 + DeviceId dstDevice1 = link.dst().deviceId();
213 + long srcPort1 = link.src().port().toLong();
214 + long dstPort1 = link.dst().port().toLong();
215 +
216 + for (Link link2: links) {
217 + DeviceId srcDevice2 = link2.src().deviceId();
218 + DeviceId dstDevice2 = link2.dst().deviceId();
219 + long srcPort2 = link2.src().port().toLong();
220 + long dstPort2 = link2.dst().port().toLong();
221 +
222 + if (srcDevice1.toString().equals(srcDevice2.toString())
223 + && dstDevice1.toString().equals(dstDevice2.toString())
224 + && srcPort1 == srcPort2 && dstPort1 == dstPort2) {
225 + return true;
226 + }
227 + }
228 +
229 + return false;
230 + }
231 +
232 + private void getDFSPaths(DeviceId dstDeviceDeviceId, Path path, ArrayList<Path> paths) {
233 + DeviceId rootDeviceDeviceId = rootDevice;
234 + for (Link upstreamLink : upstreamLinks.get(dstDeviceDeviceId)) {
235 + /* Deep clone the path object */
236 + Path sofarPath;
237 + ArrayList<Link> sofarLinks = new ArrayList<Link>();
238 + if (path != null && !path.links().isEmpty()) {
239 + sofarLinks.addAll(path.links());
240 + }
241 + sofarLinks.add(upstreamLink);
242 + sofarPath = new DefaultPath(ProviderId.NONE, sofarLinks, 0);
243 + if (upstreamLink.src().deviceId().equals(rootDeviceDeviceId)) {
244 + paths.add(sofarPath);
245 + return;
246 + } else {
247 + getDFSPaths(upstreamLink.src().deviceId(), sofarPath, paths);
248 + }
249 + }
250 + }
251 +
252 + /**
253 + * Return root Device for the graph.
254 + *
255 + * @return root Device
256 + */
257 + public DeviceId getRootDevice() {
258 + return rootDevice;
259 + }
260 +
261 + /**
262 + * Return the computed ECMP paths from the root Device to a given Device in
263 + * the network.
264 + *
265 + * @param targetDevice the target Device
266 + * @return the list of ECMP Paths from the root Device to the target Device
267 + */
268 + public ArrayList<Path> getECMPPaths(DeviceId targetDevice) {
269 + ArrayList<Path> pathArray = paths.get(targetDevice);
270 + if (pathArray == null && deviceSearched.containsKey(
271 + targetDevice)) {
272 + pathArray = new ArrayList<>();
273 + DeviceId sw = targetDevice;
274 + getDFSPaths(sw, null, pathArray);
275 + paths.put(targetDevice, pathArray);
276 + }
277 + return pathArray;
278 + }
279 +
280 + /**
281 + * Return the complete info of the computed ECMP paths for each Device
282 + * learned in multiple iterations from the root Device.
283 + *
284 + * @return the hash table of Devicees learned in multiple Dijkstra
285 + * iterations and corresponding ECMP paths to it from the root
286 + * Device
287 + */
288 + public HashMap<Integer, HashMap<DeviceId,
289 + ArrayList<Path>>> getCompleteLearnedDeviceesAndPaths() {
290 +
291 + HashMap<Integer, HashMap<DeviceId, ArrayList<Path>>> pathGraph = new
292 + HashMap<Integer, HashMap<DeviceId, ArrayList<Path>>>();
293 +
294 + for (Integer itrIndx : distanceDeviceMap.keySet()) {
295 + HashMap<DeviceId, ArrayList<Path>> swMap = new
296 + HashMap<DeviceId, ArrayList<Path>>();
297 + for (DeviceId sw : distanceDeviceMap.get(itrIndx)) {
298 + swMap.put(sw, getECMPPaths(sw));
299 + }
300 + pathGraph.put(itrIndx, swMap);
301 + }
302 +
303 + return pathGraph;
304 + }
305 +
306 + /**
307 + * Return the complete info of the computed ECMP paths for each Device
308 + * learned in multiple iterations from the root Device.
309 + *
310 + * @return the hash table of Devicees learned in multiple Dijkstra
311 + * iterations and corresponding ECMP paths in terms of Devicees to
312 + * be traversed to it from the root Device
313 + */
314 + public HashMap<Integer, HashMap<DeviceId,
315 + ArrayList<ArrayList<DeviceId>>>> getAllLearnedSwitchesAndVia() {
316 +
317 + HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> deviceViaMap =
318 + new HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>>();
319 +
320 + for (Integer itrIndx : distanceDeviceMap.keySet()) {
321 + HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swMap =
322 + new HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>();
323 +
324 + for (DeviceId sw : distanceDeviceMap.get(itrIndx)) {
325 + ArrayList<ArrayList<DeviceId>> swViaArray = new ArrayList<>();
326 + for (Path path : getECMPPaths(sw)) {
327 + ArrayList<DeviceId> swVia = new ArrayList<>();
328 + for (Link link : path.links()) {
329 + if (link.src().deviceId().equals(rootDevice)) {
330 + /* No need to add the root Device again in
331 + * the Via list
332 + */
333 + continue;
334 + }
335 + swVia.add(link.src().deviceId());
336 + }
337 + swViaArray.add(swVia);
338 + }
339 + swMap.put(sw, swViaArray);
340 + }
341 + deviceViaMap.put(itrIndx, swMap);
342 + }
343 + return deviceViaMap;
344 + }
345 +
346 +
347 + private Link copyDefaultLink(Link link) {
348 + DefaultLink src = (DefaultLink) link;
349 + DefaultLink defaultLink = new DefaultLink(src.providerId(), src.src(),
350 + src.dst(), src.type(), src.annotations());
351 +
352 + return defaultLink;
353 + }
354 +
355 + @Override
356 + public String toString() {
357 + StringBuilder sBuilder = new StringBuilder();
358 + for (Device device: srManager.deviceService.getDevices()) {
359 + if (device.id() != rootDevice) {
360 + sBuilder.append("Paths from" + rootDevice + " to " + device.id() + "\r\n");
361 + ArrayList<Path> paths = getECMPPaths(device.id());
362 + if (paths != null) {
363 + for (Path path : paths) {
364 + for (Link link : path.links()) {
365 + sBuilder.append(" : " + link.src() + " -> " + link.dst());
366 + }
367 + }
368 + }
369 + }
370 + }
371 + return sBuilder.toString();
372 + }
373 +}
374 +
1 +/*
2 + * Copyright 2015 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.segmentrouting;
17 +
18 +import java.nio.ByteBuffer;
19 +
20 +import org.onlab.packet.Ethernet;
21 +import org.onlab.packet.ICMP;
22 +import org.onlab.packet.IPv4;
23 +import org.onlab.packet.Ip4Address;
24 +import org.onlab.packet.IpPrefix;
25 +import org.onlab.packet.MPLS;
26 +import org.onosproject.net.ConnectPoint;
27 +import org.onosproject.net.DeviceId;
28 +import org.onosproject.net.flow.DefaultTrafficTreatment;
29 +import org.onosproject.net.flow.TrafficTreatment;
30 +import org.onosproject.net.packet.DefaultOutboundPacket;
31 +import org.onosproject.net.packet.InboundPacket;
32 +import org.onosproject.net.packet.OutboundPacket;
33 +import org.slf4j.Logger;
34 +import org.slf4j.LoggerFactory;
35 +
36 +import static com.google.common.base.Preconditions.checkNotNull;
37 +
38 +public class IcmpHandler {
39 +
40 + private static Logger log = LoggerFactory.getLogger(IcmpHandler.class);
41 + private SegmentRoutingManager srManager;
42 + private NetworkConfigHandler config;
43 +
44 + /**
45 + * Creates an IcmpHandler object.
46 + *
47 + * @param srManager SegmentRoutingManager object
48 + */
49 + public IcmpHandler(SegmentRoutingManager srManager) {
50 + this.srManager = srManager;
51 + this.config = checkNotNull(srManager.networkConfigHandler);
52 + }
53 +
54 + /**
55 + * Process incoming ICMP packet.
56 + * If it is an ICMP request to router or known host, then sends an ICMP response.
57 + * If it is an ICMP packet to known host and forward the packet to the host.
58 + * If it is an ICMP packet to unknown host in a subnet, then sends an ARP request
59 + * to the subnet.
60 + *
61 + * @param pkt
62 + */
63 + public void processPacketIn(InboundPacket pkt) {
64 +
65 + Ethernet ethernet = pkt.parsed();
66 + IPv4 ipv4 = (IPv4) ethernet.getPayload();
67 +
68 + ConnectPoint connectPoint = pkt.receivedFrom();
69 + DeviceId deviceId = connectPoint.deviceId();
70 + Ip4Address destinationAddress =
71 + Ip4Address.valueOf(ipv4.getDestinationAddress());
72 + Ip4Address gatewayIpAddress = config.getGatewayIpAddress(deviceId);
73 + IpPrefix routerIpPrefix = config.getRouterIpAddress(deviceId);
74 + Ip4Address routerIpAddress = routerIpPrefix.getIp4Prefix().address();
75 +
76 + // ICMP to the router IP or gateway IP
77 + if (((ICMP) ipv4.getPayload()).getIcmpType() == ICMP.TYPE_ECHO_REQUEST &&
78 + (destinationAddress.equals(routerIpAddress) ||
79 + gatewayIpAddress.equals(destinationAddress))) {
80 + sendICMPResponse(ethernet, connectPoint);
81 + // TODO: do we need to set the flow rule again ??
82 +
83 + // ICMP for any known host
84 + } else if (!srManager.hostService.getHostsByIp(destinationAddress).isEmpty()) {
85 + srManager.ipHandler.forwardPackets(deviceId, destinationAddress);
86 +
87 + // ICMP for an unknown host in the subnet of the router
88 + } else if (config.inSameSubnet(deviceId, destinationAddress)) {
89 + srManager.arpHandler.sendArpRequest(deviceId, destinationAddress, connectPoint);
90 +
91 + // ICMP for an unknown host
92 + } else {
93 + log.debug("ICMP request for unknown host {} ", destinationAddress);
94 + // Do nothing
95 + }
96 + }
97 +
98 + private void sendICMPResponse(Ethernet icmpRequest, ConnectPoint outport) {
99 +
100 + Ethernet icmpReplyEth = new Ethernet();
101 +
102 + IPv4 icmpRequestIpv4 = (IPv4) icmpRequest.getPayload();
103 + IPv4 icmpReplyIpv4 = new IPv4();
104 +
105 + int destAddress = icmpRequestIpv4.getDestinationAddress();
106 + icmpReplyIpv4.setDestinationAddress(icmpRequestIpv4.getSourceAddress());
107 + icmpReplyIpv4.setSourceAddress(destAddress);
108 + icmpReplyIpv4.setTtl((byte) 64);
109 + icmpReplyIpv4.setChecksum((short) 0);
110 +
111 + ICMP icmpReply = (ICMP) icmpRequestIpv4.getPayload().clone();
112 + icmpReply.setIcmpType(ICMP.TYPE_ECHO_REPLY);
113 + icmpReply.setIcmpCode(ICMP.SUBTYPE_ECHO_REPLY);
114 + icmpReply.setChecksum((short) 0);
115 +
116 + icmpReplyIpv4.setPayload(icmpReply);
117 +
118 + icmpReplyEth.setPayload(icmpReplyIpv4);
119 + icmpReplyEth.setEtherType(Ethernet.TYPE_IPV4);
120 + icmpReplyEth.setDestinationMACAddress(icmpRequest.getSourceMACAddress());
121 + icmpReplyEth.setSourceMACAddress(icmpRequest.getDestinationMACAddress());
122 + icmpReplyEth.setVlanID(icmpRequest.getVlanID());
123 +
124 + Ip4Address destIpAddress = Ip4Address.valueOf(icmpReplyIpv4.getDestinationAddress());
125 + Ip4Address destRouterAddress = config.getDestinationRouterAddress(destIpAddress);
126 + int sid = config.getMplsId(destRouterAddress);
127 + if (sid < 0) {
128 + log.warn("Cannot find the Segment ID for {}", destAddress);
129 + return;
130 + }
131 +
132 + sendPacketOut(outport, icmpReplyEth, sid);
133 +
134 + }
135 +
136 + private void sendPacketOut(ConnectPoint outport, Ethernet payload, int sid) {
137 +
138 + IPv4 ipPacket = (IPv4) payload.getPayload();
139 + Ip4Address destIpAddress = Ip4Address.valueOf(ipPacket.getDestinationAddress());
140 +
141 + if (sid == -1 || config.getMplsId(payload.getDestinationMAC()) == sid ||
142 + config.inSameSubnet(outport.deviceId(), destIpAddress)) {
143 + TrafficTreatment treatment = DefaultTrafficTreatment.builder().
144 + setOutput(outport.port()).build();
145 + OutboundPacket packet = new DefaultOutboundPacket(outport.deviceId(),
146 + treatment, ByteBuffer.wrap(payload.serialize()));
147 + srManager.packetService.emit(packet);
148 + } else {
149 + log.warn("Send a MPLS packet as a ICMP response");
150 + TrafficTreatment treatment = DefaultTrafficTreatment.builder()
151 + .setOutput(outport.port())
152 + .build();
153 +
154 + payload.setEtherType(Ethernet.MPLS_UNICAST);
155 + MPLS mplsPkt = new MPLS();
156 + mplsPkt.setLabel(sid);
157 + mplsPkt.setTtl(((IPv4) payload.getPayload()).getTtl());
158 + mplsPkt.setPayload(payload.getPayload());
159 + payload.setPayload(mplsPkt);
160 +
161 + OutboundPacket packet = new DefaultOutboundPacket(outport.deviceId(),
162 + treatment, ByteBuffer.wrap(payload.serialize()));
163 +
164 + srManager.packetService.emit(packet);
165 + }
166 + }
167 +}
1 +/*
2 + * Copyright 2015 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.segmentrouting;
17 +
18 +import org.onlab.packet.Ethernet;
19 +import org.onlab.packet.IPv4;
20 +import org.onlab.packet.Ip4Address;
21 +import org.onosproject.net.ConnectPoint;
22 +import org.onosproject.net.DeviceId;
23 +import org.onosproject.net.Host;
24 +import org.onosproject.net.flow.DefaultTrafficTreatment;
25 +import org.onosproject.net.flow.TrafficTreatment;
26 +import org.onosproject.net.packet.DefaultOutboundPacket;
27 +import org.onosproject.net.packet.InboundPacket;
28 +import org.onosproject.net.packet.OutboundPacket;
29 +import org.slf4j.Logger;
30 +import org.slf4j.LoggerFactory;
31 +
32 +import java.nio.ByteBuffer;
33 +import java.util.concurrent.ConcurrentHashMap;
34 +import java.util.concurrent.ConcurrentLinkedQueue;
35 +
36 +import static com.google.common.base.Preconditions.checkNotNull;
37 +
38 +public class IpHandler {
39 +
40 + private static Logger log = LoggerFactory.getLogger(IpHandler.class);
41 + private SegmentRoutingManager srManager;
42 + private NetworkConfigHandler config;
43 + private ConcurrentHashMap<Ip4Address, ConcurrentLinkedQueue<IPv4>> ipPacketQueue;
44 +
45 + /**
46 + * Creates an IpHandler object.
47 + *
48 + * @param srManager SegmentRoutingManager object
49 + */
50 + public IpHandler(SegmentRoutingManager srManager) {
51 + this.srManager = srManager;
52 + this.config = checkNotNull(srManager.networkConfigHandler);
53 + ipPacketQueue = new ConcurrentHashMap<Ip4Address, ConcurrentLinkedQueue<IPv4>>();
54 + }
55 +
56 + /**
57 + * Processes incoming IP packets.
58 + *
59 + * If it is an IP packet for known host, then forward it to the host.
60 + * If it is an IP packet for unknown host in subnet, then send an ARP request
61 + * to the subnet.
62 + *
63 + * @param pkt incoming packet
64 + */
65 + public void processPacketIn(InboundPacket pkt) {
66 + Ethernet ethernet = pkt.parsed();
67 + IPv4 ipv4 = (IPv4) ethernet.getPayload();
68 +
69 + ConnectPoint connectPoint = pkt.receivedFrom();
70 + DeviceId deviceId = connectPoint.deviceId();
71 + Ip4Address destinationAddress =
72 + Ip4Address.valueOf(ipv4.getDestinationAddress());
73 +
74 + // IP packet for know hosts
75 + if (!srManager.hostService.getHostsByIp(destinationAddress).isEmpty()) {
76 + forwardPackets(deviceId, destinationAddress);
77 +
78 + // IP packet for unknown host in the subnet of the router
79 + } else if (config.inSameSubnet(deviceId, destinationAddress)) {
80 + srManager.arpHandler.sendArpRequest(deviceId, destinationAddress, connectPoint);
81 +
82 + // IP packets for unknown host
83 + } else {
84 + log.debug("ICMP request for unknown host {} which is not in the subnet",
85 + destinationAddress);
86 + // Do nothing
87 + }
88 + }
89 +
90 + /**
91 + * Adds the IP packet to a buffer.
92 + * The packets are forwarded to corresponding destination when the destination
93 + * MAC address is known via ARP response.
94 + *
95 + * @param ipPacket IP packet to add to the buffer
96 + */
97 + public void addToPacketBuffer(IPv4 ipPacket) {
98 +
99 + // Better not buffer TPC packets due to out-of-order packet transfer
100 + if (ipPacket.getProtocol() == IPv4.PROTOCOL_TCP) {
101 + return;
102 + }
103 +
104 + Ip4Address destIpAddress = Ip4Address.valueOf(ipPacket.getDestinationAddress());
105 +
106 + if (ipPacketQueue.get(destIpAddress) == null) {
107 + ConcurrentLinkedQueue<IPv4> queue = new ConcurrentLinkedQueue<IPv4>();
108 + queue.add(ipPacket);
109 + ipPacketQueue.put(destIpAddress, queue);
110 + } else {
111 + ipPacketQueue.get(destIpAddress).add(ipPacket);
112 + }
113 + }
114 +
115 + /**
116 + * Forwards IP packets in the buffer to the destination IP address.
117 + * It is called when the controller finds the destination MAC address
118 + * via ARP responsees.
119 + *
120 + * @param deviceId switch device ID
121 + * @param destIpAddress destination IP address
122 + */
123 + public void forwardPackets(DeviceId deviceId, Ip4Address destIpAddress) {
124 + for (IPv4 ipPacket : ipPacketQueue.get(destIpAddress)) {
125 + Ip4Address destAddress = Ip4Address.valueOf(ipPacket.getDestinationAddress());
126 + if (ipPacket != null && config.inSameSubnet(deviceId, destAddress)) {
127 + ipPacket.setTtl((byte) (ipPacket.getTtl() - 1));
128 + ipPacket.setChecksum((short) 0);
129 + for (Host dest: srManager.hostService.getHostsByIp(destIpAddress)) {
130 + Ethernet eth = new Ethernet();
131 + eth.setDestinationMACAddress(dest.mac());
132 + eth.setSourceMACAddress(config.getRouterMacAddress(
133 + deviceId));
134 + eth.setEtherType(Ethernet.TYPE_IPV4);
135 + eth.setPayload(ipPacket);
136 +
137 + TrafficTreatment treatment = DefaultTrafficTreatment.builder().
138 + setOutput(dest.location().port()).build();
139 + OutboundPacket packet = new DefaultOutboundPacket(deviceId,
140 + treatment, ByteBuffer.wrap(eth.serialize()));
141 + srManager.packetService.emit(packet);
142 + }
143 + }
144 + }
145 + }
146 +}
1 +/*
2 + * Copyright 2015 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.segmentrouting;
17 +
18 +import com.google.common.collect.Lists;
19 +import org.onlab.packet.Ip4Address;
20 +import org.onlab.packet.Ip4Prefix;
21 +import org.onlab.packet.IpPrefix;
22 +import org.onlab.packet.MacAddress;
23 +import org.onosproject.net.DeviceId;
24 +import org.onosproject.net.Link;
25 +import org.onosproject.net.PortNumber;
26 +import org.slf4j.Logger;
27 +import org.slf4j.LoggerFactory;
28 +
29 +import java.net.URI;
30 +import java.util.List;
31 +import java.util.Set;
32 +
33 +/**
34 + * This class is temporary class and used only for test.
35 + * It will be replaced with "real" Network Config Manager.
36 + */
37 +
38 +public class NetworkConfigHandler {
39 +
40 + private static Logger log = LoggerFactory.getLogger(NetworkConfigHandler.class);
41 + private SegmentRoutingManager srManager;
42 + private DeviceConfiguration deviceConfig = new DeviceConfiguration();
43 +
44 + public NetworkConfigHandler(SegmentRoutingManager srManager) {
45 + this.srManager = srManager;
46 + }
47 +
48 + public Ip4Address getGatewayIpAddress(DeviceId deviceId) {
49 +
50 + if (deviceId.uri().equals(URI.create("of:0000000000000001"))) {
51 + return Ip4Address.valueOf("10.0.1.128");
52 + } else if (deviceId.uri().equals(URI.create("of:0000000000000006"))) {
53 + return Ip4Address.valueOf("7.7.7.128");
54 + }
55 +
56 + log.warn("No gateway Ip address was found for {}", deviceId);
57 + return Ip4Address.valueOf("0.0.0.0");
58 + }
59 +
60 + public IpPrefix getRouterIpAddress(DeviceId deviceId) {
61 +
62 + return IpPrefix.valueOf(deviceConfig.getRouterIp(deviceId), 32);
63 + }
64 +
65 + public MacAddress getRouterMacAddress(DeviceId deviceId) {
66 + return deviceConfig.getDeviceMac(deviceId);
67 + }
68 +
69 + public boolean inSameSubnet(DeviceId deviceId, Ip4Address destIp) {
70 +
71 + String subnetInfo = getSubnetInfo(deviceId);
72 + if (subnetInfo == null) {
73 + return false;
74 + }
75 +
76 + IpPrefix prefix = IpPrefix.valueOf(subnetInfo);
77 + if (prefix.contains(destIp)) {
78 + return true;
79 + }
80 +
81 + return false;
82 + }
83 +
84 + public boolean inSameSubnet(Ip4Address address, int sid) {
85 + DeviceId deviceId = deviceConfig.getDeviceId(sid);
86 + if (deviceId == null) {
87 + log.warn("Cannot find a device for SID {}", sid);
88 + return false;
89 + }
90 +
91 + String subnetInfo = getSubnetInfo(deviceId);
92 + if (subnetInfo == null) {
93 + log.warn("Cannot find the subnet info for {}", deviceId);
94 + return false;
95 + }
96 +
97 + Ip4Prefix subnet = Ip4Prefix.valueOf(subnetInfo);
98 + if (subnet.contains(address)) {
99 + return true;
100 + }
101 +
102 + return false;
103 +
104 + }
105 +
106 + public String getSubnetInfo(DeviceId deviceId) {
107 + // TODO : supports multiple subnet
108 + if (deviceId.uri().equals(URI.create("of:0000000000000001"))) {
109 + return "10.0.1.1/24";
110 + } else if (deviceId.uri().equals(URI.create("of:0000000000000006"))) {
111 + return "7.7.7.7/24";
112 + } else {
113 + log.error("Switch {} is not an edge router", deviceId);
114 + return null;
115 + }
116 + }
117 +
118 + public int getMplsId(DeviceId deviceId) {
119 + return deviceConfig.getSegmentId(deviceId);
120 + }
121 +
122 + public int getMplsId(MacAddress mac) {
123 + return deviceConfig.getSegmentId(mac);
124 + }
125 +
126 + public int getMplsId(Ip4Address address) {
127 + return deviceConfig.getSegmentId(address);
128 + }
129 +
130 + public boolean isEcmpNotSupportedInTransit(DeviceId deviceId) {
131 + return false;
132 + }
133 +
134 + public boolean isTransitRouter(DeviceId deviceId) {
135 + return true;
136 + }
137 +
138 +
139 + public boolean isEdgeRouter(DeviceId deviceId) {
140 + if (deviceId.uri().equals(URI.create("of:0000000000000001"))
141 + || deviceId.uri().equals(URI.create("of:0000000000000006"))) {
142 + return true;
143 + }
144 +
145 + return false;
146 + }
147 +
148 + private List<PortNumber> getPortsToNeighbors(DeviceId deviceId, List<DeviceId> fwdSws) {
149 +
150 + List<PortNumber> portNumbers = Lists.newArrayList();
151 +
152 + Set<Link> links = srManager.linkService.getDeviceEgressLinks(deviceId);
153 + for (Link link: links) {
154 + for (DeviceId swId: fwdSws) {
155 + if (link.dst().deviceId().equals(swId)) {
156 + portNumbers.add(link.src().port());
157 + break;
158 + }
159 + }
160 + }
161 +
162 + return portNumbers;
163 + }
164 +
165 + public List<PortNumber> getPortsToDevice(DeviceId deviceId) {
166 + List<PortNumber> portNumbers = Lists.newArrayList();
167 +
168 + Set<Link> links = srManager.linkService.getDeviceEgressLinks(deviceId);
169 + for (Link link: links) {
170 + if (link.dst().deviceId().equals(deviceId)) {
171 + portNumbers.add(link.src().port());
172 + }
173 + }
174 +
175 + return portNumbers;
176 + }
177 +
178 +
179 + public Ip4Address getDestinationRouterAddress(Ip4Address destIpAddress) {
180 + // TODO: need to check the subnet info
181 + if (destIpAddress.toString().equals("10.0.1.1")) {
182 + return Ip4Address.valueOf("192.168.0.1");
183 + } else if (destIpAddress.toString().equals("7.7.7.7")) {
184 + return Ip4Address.valueOf("192.168.0.6");
185 + } else {
186 + log.warn("No router was found for {}", destIpAddress);
187 + return null;
188 + }
189 +
190 + }
191 +
192 + public DeviceId getDeviceId(Ip4Address ip4Address) {
193 + return deviceConfig.getDeviceId(ip4Address);
194 + }
195 +
196 + public MacAddress getRouterMac(Ip4Address targetAddress) {
197 + if (targetAddress.toString().equals("10.0.1.128")) {
198 + return MacAddress.valueOf("00:00:00:00:00:01");
199 + } else if (targetAddress.toString().equals("7.7.7.128")) {
200 + return MacAddress.valueOf("00:00:00:00:00:06");
201 + } else {
202 + log.warn("Cannot find a router for {}", targetAddress);
203 + return null;
204 + }
205 + }
206 +}
1 +/*
2 + * Copyright 2015 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.segmentrouting;
17 +
18 +import org.onlab.packet.Ethernet;
19 +import org.onlab.packet.Ip4Address;
20 +import org.onlab.packet.IpPrefix;
21 +import org.onlab.packet.MacAddress;
22 +
23 +import org.onlab.packet.MplsLabel;
24 +import org.onosproject.grouphandler.NeighborSet;
25 +import org.onosproject.net.DeviceId;
26 +import org.onosproject.net.Link;
27 +import org.onosproject.net.PortNumber;
28 +import org.onosproject.net.flow.DefaultFlowRule;
29 +import org.onosproject.net.flow.DefaultTrafficSelector;
30 +import org.onosproject.net.flow.DefaultTrafficTreatment;
31 +import org.onosproject.net.flow.FlowRule;
32 +import org.onosproject.net.flow.TrafficSelector;
33 +import org.onosproject.net.flow.TrafficTreatment;
34 +import org.onosproject.net.group.DefaultGroupKey;
35 +import org.onosproject.net.group.Group;
36 +import org.slf4j.Logger;
37 +import org.slf4j.LoggerFactory;
38 +
39 +import java.util.ArrayList;
40 +import java.util.Collection;
41 +import java.util.List;
42 +import java.util.Set;
43 +
44 +import static com.google.common.base.Preconditions.checkNotNull;
45 +
46 +public class RoutingRulePopulator {
47 +
48 + private static final Logger log = LoggerFactory.getLogger(RoutingRulePopulator.class);
49 +
50 + private SegmentRoutingManager srManager;
51 + private NetworkConfigHandler config;
52 +
53 + /**
54 + * Creates a RoutingRulePopulator object.
55 + *
56 + * @param srManager
57 + */
58 + public RoutingRulePopulator(SegmentRoutingManager srManager) {
59 + this.srManager = srManager;
60 + this.config = checkNotNull(srManager.networkConfigHandler);
61 + }
62 +
63 + /**
64 + * Populates IP flow rules for specific hosts directly connected to the switch.
65 + *
66 + * @param deviceId switch ID to set the rules
67 + * @param hostIp host IP address
68 + * @param hostMac host MAC address
69 + * @param outPort port where the host is connected
70 + */
71 + public void populateIpRuleForHost(DeviceId deviceId, Ip4Address hostIp,
72 + MacAddress hostMac, PortNumber outPort) {
73 + TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
74 + TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
75 +
76 + sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, 32));
77 + sbuilder.matchEthType(Ethernet.TYPE_IPV4);
78 +
79 + tbuilder.setEthDst(hostMac)
80 + .setEthSrc(config.getRouterMacAddress(deviceId))
81 + .setOutput(outPort);
82 +
83 + TrafficTreatment treatment = tbuilder.build();
84 + TrafficSelector selector = sbuilder.build();
85 +
86 + FlowRule f = new DefaultFlowRule(deviceId, selector, treatment, 100,
87 + srManager.appId, 600, false, FlowRule.Type.IP);
88 +
89 + srManager.flowRuleService.applyFlowRules(f);
90 + log.debug("Flow rule {} is set to switch {}", f, deviceId);
91 + }
92 +
93 + /**
94 + * Populates IP flow rules for the subnets of the destination router.
95 + *
96 + * @param deviceId switch ID to set the rules
97 + * @param subnetInfo subnet information
98 + * @param destSw destination switch ID
99 + * @param nextHops next hop switch ID list
100 + * @return true if all rules are set successfully, false otherwise
101 + */
102 + public boolean populateIpRuleForSubnet(DeviceId deviceId, String subnetInfo,
103 + DeviceId destSw, Set<DeviceId> nextHops) {
104 +
105 + List<IpPrefix> subnets = extractSubnet(subnetInfo);
106 + for (IpPrefix subnet: subnets) {
107 + if (!populateIpRuleForRouter(deviceId, subnet, destSw, nextHops)) {
108 + return false;
109 + }
110 + }
111 +
112 + return true;
113 + }
114 +
115 + /**
116 + * Populates IP flow rules for the router IP address.
117 + *
118 + * @param deviceId device ID to set the rules
119 + * @param ipPrefix the IP address of the destination router
120 + * @param destSw device ID of the destination router
121 + * @param nextHops next hop switch ID list
122 + * @return true if all rules are set successfully, false otherwise
123 + */
124 + public boolean populateIpRuleForRouter(DeviceId deviceId, IpPrefix ipPrefix,
125 + DeviceId destSw, Set<DeviceId> nextHops) {
126 +
127 + TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
128 + TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
129 +
130 + sbuilder.matchIPDst(ipPrefix);
131 + sbuilder.matchEthType(Ethernet.TYPE_IPV4);
132 +
133 + NeighborSet ns = null;
134 +
135 + //If the next hop is the same as the final destination, then MPLS label is not set.
136 + if (nextHops.size() == 1 && nextHops.toArray()[0].equals(destSw)) {
137 + tbuilder.decNwTtl();
138 + ns = new NeighborSet(nextHops);
139 + } else {
140 + tbuilder.copyTtlOut();
141 + ns = new NeighborSet(nextHops, config.getMplsId(destSw));
142 + }
143 +
144 + DefaultGroupKey groupKey = (DefaultGroupKey) srManager.getGroupKey(ns);
145 + if (groupKey == null) {
146 + log.warn("Group key is not found for ns {}", ns);
147 + return false;
148 + }
149 + Group group = srManager.groupService.getGroup(deviceId, groupKey);
150 + if (group != null) {
151 + tbuilder.group(group.id());
152 + } else {
153 + log.warn("No group found for NeighborSet {} from {} to {}",
154 + ns, deviceId, destSw);
155 + return false;
156 + }
157 +
158 + TrafficTreatment treatment = tbuilder.build();
159 + TrafficSelector selector = sbuilder.build();
160 +
161 + FlowRule f = new DefaultFlowRule(deviceId, selector, treatment, 100,
162 + srManager.appId, 600, false, FlowRule.Type.IP);
163 +
164 + srManager.flowRuleService.applyFlowRules(f);
165 + log.debug("IP flow rule {} is set to switch {}", f, deviceId);
166 +
167 + return true;
168 + }
169 +
170 +
171 + /**
172 + * Populates MPLS flow rules to all transit routers.
173 + *
174 + * @param deviceId device ID of the switch to set the rules
175 + * @param destSwId destination switch device ID
176 + * @param nextHops next hops switch ID list
177 + * @return true if all rules are set successfully, false otherwise
178 + */
179 + public boolean populateMplsRule(DeviceId deviceId, DeviceId destSwId, Set<DeviceId> nextHops) {
180 +
181 + TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
182 + Collection<TrafficTreatment> treatments = new ArrayList<>();
183 +
184 + // TODO Handle the case of Bos == false
185 + sbuilder.matchMplsLabel(MplsLabel.mplsLabel(config.getMplsId(destSwId)));
186 + sbuilder.matchEthType(Ethernet.MPLS_UNICAST);
187 +
188 + //If the next hop is the destination router, do PHP
189 + if (nextHops.size() == 1 && destSwId.equals(nextHops.toArray()[0])) {
190 + TrafficTreatment treatmentBos =
191 + getMplsTreatment(deviceId, destSwId, nextHops, true, true);
192 + TrafficTreatment treatment =
193 + getMplsTreatment(deviceId, destSwId, nextHops, true, false);
194 + if (treatmentBos != null) {
195 + treatments.add(treatmentBos);
196 + } else {
197 + log.warn("Failed to set MPLS rules.");
198 + return false;
199 + }
200 + } else {
201 + TrafficTreatment treatmentBos =
202 + getMplsTreatment(deviceId, destSwId, nextHops, false, true);
203 + TrafficTreatment treatment =
204 + getMplsTreatment(deviceId, destSwId, nextHops, false, false);
205 +
206 + if (treatmentBos != null) {
207 + treatments.add(treatmentBos);
208 + } else {
209 + log.warn("Failed to set MPLS rules.");
210 + return false;
211 + }
212 + }
213 +
214 + TrafficSelector selector = sbuilder.build();
215 + for (TrafficTreatment treatment: treatments) {
216 + FlowRule f = new DefaultFlowRule(deviceId, selector, treatment, 100,
217 + srManager.appId, 600, false, FlowRule.Type.MPLS);
218 + srManager.flowRuleService.applyFlowRules(f);
219 + log.debug("MPLS rule {} is set to {}", f, deviceId);
220 + }
221 +
222 + return true;
223 + }
224 +
225 +
226 + private TrafficTreatment getMplsTreatment(DeviceId deviceId, DeviceId destSw,
227 + Set<DeviceId> nextHops,
228 + boolean phpRequired, boolean isBos) {
229 +
230 + TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
231 +
232 + if (phpRequired) {
233 + tbuilder.copyTtlIn();
234 + if (isBos) {
235 + tbuilder.popMpls(Ethernet.TYPE_IPV4)
236 + .decNwTtl();
237 + } else {
238 + tbuilder.popMpls(Ethernet.MPLS_UNICAST)
239 + .decMplsTtl();
240 + }
241 + } else {
242 + tbuilder.decMplsTtl();
243 + }
244 +
245 + if (config.isEcmpNotSupportedInTransit(deviceId)
246 + && config.isTransitRouter(deviceId)) {
247 + Link link = selectOneLink(deviceId, nextHops);
248 + if (link == null) {
249 + log.warn("No link from {} to {}", deviceId, nextHops);
250 + return null;
251 + }
252 + tbuilder.setEthSrc(config.getRouterMacAddress(deviceId))
253 + .setEthDst(config.getRouterMacAddress(link.dst().deviceId()))
254 + .setOutput(link.src().port());
255 + } else {
256 + NeighborSet ns = new NeighborSet(nextHops);
257 + DefaultGroupKey groupKey = (DefaultGroupKey) srManager.getGroupKey(ns);
258 + if (groupKey == null) {
259 + log.warn("Group key is not found for ns {}", ns);
260 + return null;
261 + }
262 + Group group = srManager.groupService.getGroup(deviceId, groupKey);
263 + if (group != null) {
264 + tbuilder.group(group.id());
265 + } else {
266 + log.warn("No group found for ns {} key {} in {}", ns,
267 + srManager.getGroupKey(ns), deviceId);
268 + return null;
269 + }
270 + }
271 +
272 + return tbuilder.build();
273 + }
274 +
275 + /**
276 + * Populates VLAN flows rules.
277 + * All packets are forwarded to TMAC table.
278 + *
279 + * @param deviceId switch ID to set the rules
280 + */
281 + public void populateTableVlan(DeviceId deviceId) {
282 + TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
283 + TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
284 +
285 + tbuilder.transition(FlowRule.Type.ETHER);
286 +
287 + TrafficTreatment treatment = tbuilder.build();
288 + TrafficSelector selector = sbuilder.build();
289 +
290 + FlowRule f = new DefaultFlowRule(deviceId, selector, treatment, 100,
291 + srManager.appId, 600, false, FlowRule.Type.VLAN);
292 +
293 + srManager.flowRuleService.applyFlowRules(f);
294 +
295 + log.debug("Vlan flow rule {} is set to switch {}", f, deviceId);
296 + }
297 +
298 + /**
299 + * Populates TMAC table rules.
300 + * IP packets are forwarded to IP table.
301 + * MPLS packets are forwarded to MPLS table.
302 + *
303 + * @param deviceId switch ID to set the rules
304 + */
305 + public void populateTableTMac(DeviceId deviceId) {
306 +
307 + // flow rule for IP packets
308 + TrafficSelector selectorIp = DefaultTrafficSelector.builder()
309 + .matchEthType(Ethernet.TYPE_IPV4)
310 + .matchEthDst(config.getRouterMacAddress(deviceId))
311 + .build();
312 + TrafficTreatment treatmentIp = DefaultTrafficTreatment.builder()
313 + .transition(FlowRule.Type.IP)
314 + .build();
315 +
316 + FlowRule flowIp = new DefaultFlowRule(deviceId, selectorIp, treatmentIp, 100,
317 + srManager.appId, 600, false, FlowRule.Type.ETHER);
318 +
319 + srManager.flowRuleService.applyFlowRules(flowIp);
320 +
321 + // flow rule for MPLS packets
322 + TrafficSelector selectorMpls = DefaultTrafficSelector.builder()
323 + .matchEthType(Ethernet.MPLS_UNICAST)
324 + .matchEthDst(config.getRouterMacAddress(deviceId))
325 + .build();
326 + TrafficTreatment treatmentMpls = DefaultTrafficTreatment.builder()
327 + .transition(FlowRule.Type.MPLS)
328 + .build();
329 +
330 + FlowRule flowMpls = new DefaultFlowRule(deviceId, selectorMpls, treatmentMpls, 100,
331 + srManager.appId, 600, false, FlowRule.Type.ETHER);
332 +
333 + srManager.flowRuleService.applyFlowRules(flowMpls);
334 +
335 + }
336 +
337 + /**
338 + * Populates a table miss entry.
339 + *
340 + * @param deviceId switch ID to set rules
341 + * @param tableToAdd table to set the rules
342 + * @param toControllerNow flag to send packets to controller immediately
343 + * @param toControllerWrite flag to send packets to controller at the end of pipeline
344 + * @param toTable flag to send packets to a specific table
345 + * @param tableToSend table type to send packets when the toTable flag is set
346 + */
347 + public void populateTableMissEntry(DeviceId deviceId, FlowRule.Type tableToAdd, boolean toControllerNow,
348 + boolean toControllerWrite,
349 + boolean toTable, FlowRule.Type tableToSend) {
350 + // TODO: Change arguments to EnumSet
351 + TrafficSelector selector = DefaultTrafficSelector.builder()
352 + .build();
353 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
354 +
355 + if (toControllerNow) {
356 + tBuilder.setOutput(PortNumber.CONTROLLER);
357 + }
358 +
359 + if (toControllerWrite) {
360 + tBuilder.deferred().setOutput(PortNumber.CONTROLLER);
361 + }
362 +
363 + if (toTable) {
364 + tBuilder.transition(tableToSend);
365 + }
366 +
367 + FlowRule flow = new DefaultFlowRule(deviceId, selector, tBuilder.build(), 0,
368 + srManager.appId, 600, false, tableToAdd);
369 +
370 + srManager.flowRuleService.applyFlowRules(flow);
371 +
372 + }
373 +
374 +
375 + private List<IpPrefix> extractSubnet(String subnetInfo) {
376 + List<IpPrefix> subnetIpPrefixes = new ArrayList<>();
377 +
378 + // TODO: refactoring required depending on the format of the subnet info
379 + IpPrefix prefix = IpPrefix.valueOf(subnetInfo);
380 + if (prefix == null) {
381 + log.error("Wrong ip prefix type {}", subnetInfo);
382 + } else {
383 + subnetIpPrefixes.add(prefix);
384 + }
385 +
386 + return subnetIpPrefixes;
387 + }
388 +
389 + private Link selectOneLink(DeviceId srcId, Set<DeviceId> destIds) {
390 +
391 + Set<Link> links = srManager.linkService.getDeviceEgressLinks(srcId);
392 + DeviceId destId = (DeviceId) destIds.toArray()[0];
393 + for (Link link: links) {
394 + if (link.dst().deviceId().equals(destId)) {
395 + return link;
396 + }
397 + }
398 +
399 + return null;
400 + }
401 +
402 +}
1 +/*
2 + * Copyright 2015 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.segmentrouting;
17 +
18 +import org.apache.felix.scr.annotations.Activate;
19 +import org.apache.felix.scr.annotations.Component;
20 +import org.apache.felix.scr.annotations.Deactivate;
21 +import org.apache.felix.scr.annotations.Reference;
22 +import org.apache.felix.scr.annotations.ReferenceCardinality;
23 +import org.onlab.packet.Ethernet;
24 +import org.onlab.packet.IPv4;
25 +import org.onosproject.core.ApplicationId;
26 +import org.onosproject.core.CoreService;
27 +import org.onosproject.event.Event;
28 +import org.onosproject.grouphandler.DefaultGroupHandler;
29 +import org.onosproject.grouphandler.NeighborSet;
30 +import org.onosproject.mastership.MastershipService;
31 +import org.onosproject.net.Device;
32 +import org.onosproject.net.DeviceId;
33 +import org.onosproject.net.Link;
34 +import org.onosproject.net.MastershipRole;
35 +import org.onosproject.net.Port;
36 +import org.onosproject.net.device.DeviceEvent;
37 +import org.onosproject.net.device.DeviceListener;
38 +import org.onosproject.net.device.DeviceService;
39 +import org.onosproject.net.flow.FlowRuleService;
40 +import org.onosproject.net.group.Group;
41 +import org.onosproject.net.group.GroupEvent;
42 +import org.onosproject.net.group.GroupKey;
43 +import org.onosproject.net.group.GroupListener;
44 +import org.onosproject.net.group.GroupService;
45 +import org.onosproject.net.host.HostService;
46 +import org.onosproject.net.intent.IntentService;
47 +import org.onosproject.net.link.LinkEvent;
48 +import org.onosproject.net.link.LinkListener;
49 +import org.onosproject.net.link.LinkService;
50 +import org.onosproject.net.packet.InboundPacket;
51 +import org.onosproject.net.packet.PacketContext;
52 +import org.onosproject.net.packet.PacketProcessor;
53 +import org.onosproject.net.packet.PacketService;
54 +import org.onosproject.net.topology.TopologyService;
55 +import org.slf4j.Logger;
56 +import org.slf4j.LoggerFactory;
57 +
58 +import java.util.Map;
59 +import java.util.concurrent.ConcurrentHashMap;
60 +import java.util.concurrent.ConcurrentLinkedQueue;
61 +import java.util.concurrent.Executors;
62 +import java.util.concurrent.ScheduledExecutorService;
63 +import java.util.concurrent.ScheduledFuture;
64 +import java.util.concurrent.TimeUnit;
65 +
66 +@SuppressWarnings("ALL")
67 +@Component(immediate = true)
68 +public class SegmentRoutingManager {
69 +
70 + private static Logger log = LoggerFactory.getLogger(SegmentRoutingManager.class);
71 +
72 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 + protected CoreService coreService;
74 +
75 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 + protected TopologyService topologyService;
77 +
78 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 + protected PacketService packetService;
80 +
81 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 + protected IntentService intentService;
83 +
84 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 + protected HostService hostService;
86 +
87 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 + protected DeviceService deviceService;
89 +
90 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 + protected FlowRuleService flowRuleService;
92 +
93 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 + protected LinkService linkService;
95 +
96 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 + protected GroupService groupService;
98 +
99 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 + protected MastershipService mastershipService;
101 +
102 + protected NetworkConfigHandler networkConfigHandler = new NetworkConfigHandler(this);
103 + protected ArpHandler arpHandler = new ArpHandler(this);
104 + protected IcmpHandler icmpHandler = new IcmpHandler(this);
105 + protected IpHandler ipHandler = new IpHandler(this);
106 + protected RoutingRulePopulator routingRulePopulator = new RoutingRulePopulator(this);
107 + protected ApplicationId appId;
108 +
109 + private DefaultRoutingHandler defaultRoutingHandler = new DefaultRoutingHandler(this);
110 + private DeviceConfiguration deviceConfiguration = new DeviceConfiguration();
111 + private InternalPacketProcessor processor = new InternalPacketProcessor();
112 + private InternalEventHandler eventHandler = new InternalEventHandler();
113 +
114 + private ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
115 +
116 + private static ScheduledFuture<?> eventHandlerFuture = null;
117 + private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
118 + private Map<DeviceId, DefaultGroupHandler> groupHandlerMap
119 + = new ConcurrentHashMap<DeviceId, DefaultGroupHandler>();
120 +
121 + private static int numOfEvents = 0;
122 + private static int numOfHandlerExecution = 0;
123 + private static int numOfHandlerScheduled = 0;
124 +
125 + @Activate
126 + protected void activate() {
127 + appId = coreService.registerApplication("org.onosproject.segmentrouting");
128 + packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 2);
129 + linkService.addListener(new InternalLinkListener());
130 + groupService.addListener(new InternalGroupListener());
131 + deviceService.addListener(new InternalDeviceListener());
132 +
133 + for (Device device: deviceService.getDevices()) {
134 + if (mastershipService.
135 + getLocalRole(device.id()) == MastershipRole.MASTER) {
136 + DefaultGroupHandler groupHandler =
137 + DefaultGroupHandler.createGroupHandler(device.id(),
138 + appId, deviceConfiguration, linkService, groupService);
139 + groupHandler.createGroups();
140 + groupHandlerMap.put(device.id(), groupHandler);
141 + log.debug("Initiating default group handling for {}", device.id());
142 +
143 + defaultRoutingHandler.startPopulationProcess();
144 + } else {
145 + log.debug("Activate: Local role {} "
146 + + "is not MASTER for device {}",
147 + mastershipService.
148 + getLocalRole(device.id()),
149 + device.id());
150 + }
151 + }
152 +
153 + log.info("Started");
154 + }
155 +
156 + @Deactivate
157 + protected void deactivate() {
158 + packetService.removeProcessor(processor);
159 + processor = null;
160 + log.info("Stopped");
161 + }
162 +
163 + /**
164 + * Returns the GrouopKey object for the device and the NighborSet given.
165 + *
166 + * @param ns NeightborSet object for the GroupKey
167 + * @return GroupKey object for the NeighborSet
168 + */
169 + public GroupKey getGroupKey(NeighborSet ns) {
170 +
171 + for (DefaultGroupHandler groupHandler: groupHandlerMap.values()) {
172 + return groupHandler.getGroupKey(ns);
173 + }
174 +
175 + return null;
176 + }
177 +
178 + private class InternalPacketProcessor implements PacketProcessor {
179 +
180 + @Override
181 + public void process(PacketContext context) {
182 +
183 + if (context.isHandled()) {
184 + return;
185 + }
186 +
187 + InboundPacket pkt = context.inPacket();
188 + Ethernet ethernet = pkt.parsed();
189 +
190 + if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
191 + arpHandler.processPacketIn(pkt);
192 + } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
193 + IPv4 ipPacket = (IPv4) ethernet.getPayload();
194 + ipHandler.addToPacketBuffer(ipPacket);
195 + if (ipPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
196 + icmpHandler.processPacketIn(pkt);
197 + } else {
198 + ipHandler.processPacketIn(pkt);
199 + }
200 + }
201 + }
202 + }
203 +
204 + private class InternalLinkListener implements LinkListener {
205 + @Override
206 + public void event(LinkEvent event) {
207 + if (event.type() == LinkEvent.Type.LINK_ADDED ||
208 + event.type() == LinkEvent.Type.LINK_REMOVED) {
209 + scheduleEventHandlerIfNotScheduled(event);
210 + }
211 + }
212 + }
213 +
214 + private class InternalDeviceListener implements DeviceListener {
215 +
216 + @Override
217 + public void event(DeviceEvent event) {
218 + if (mastershipService.
219 + getLocalRole(event.subject().id()) != MastershipRole.MASTER) {
220 + log.debug("Local role {} is not MASTER for device {}",
221 + mastershipService.
222 + getLocalRole(event.subject().id()),
223 + event.subject().id());
224 + return;
225 + }
226 +
227 + switch (event.type()) {
228 + case DEVICE_ADDED:
229 + case PORT_REMOVED:
230 + scheduleEventHandlerIfNotScheduled(event);
231 + break;
232 + default:
233 + }
234 + }
235 + }
236 +
237 + private class InternalGroupListener implements GroupListener {
238 +
239 + @Override
240 + public void event(GroupEvent event) {
241 + switch (event.type()) {
242 + case GROUP_ADDED:
243 + scheduleEventHandlerIfNotScheduled(event);
244 + break;
245 + case GROUP_ADD_REQUESTED:
246 + log.info("Group add requested");
247 + break;
248 + case GROUP_UPDATED:
249 + break;
250 + default:
251 + log.warn("Unhandled group event type: {}", event.type());
252 + }
253 + }
254 + }
255 +
256 + private void scheduleEventHandlerIfNotScheduled(Event event) {
257 +
258 + eventQueue.add(event);
259 + numOfEvents++;
260 + if (eventHandlerFuture == null ||
261 + eventHandlerFuture.isDone()) {
262 + eventHandlerFuture = executorService.schedule(eventHandler,
263 + 100, TimeUnit.MILLISECONDS);
264 + numOfHandlerScheduled++;
265 + }
266 +
267 + log.trace("numOfEvents {}, numOfEventHanlderScheduled {}", numOfEvents,
268 + numOfHandlerScheduled);
269 +
270 + }
271 +
272 + private class InternalEventHandler implements Runnable {
273 +
274 + public void run() {
275 + numOfHandlerExecution++;
276 + while (!eventQueue.isEmpty()) {
277 + Event event = eventQueue.poll();
278 + if (event.type() == LinkEvent.Type.LINK_ADDED) {
279 + processLinkAdded((Link) event.subject());
280 + } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
281 + processLinkRemoved((Link) event.subject());
282 + } else if (event.type() == GroupEvent.Type.GROUP_ADDED) {
283 + processGroupAdded((Group) event.subject());
284 + } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED) {
285 + processDeviceAdded((Device) event.subject());
286 + } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
287 + processPortRemoved((Device) event.subject(),
288 + ((DeviceEvent) event).port());
289 + } else {
290 + log.warn("Unhandled event type: {}", event.type());
291 + }
292 + }
293 + log.debug("numOfHandlerExecution {} numOfEventHanlderScheduled {} numOfEvents {}",
294 + numOfHandlerExecution, numOfHandlerScheduled, numOfEvents);
295 + }
296 + }
297 +
298 +
299 +
300 + private void processLinkAdded(Link link) {
301 + log.debug("A new link {} was added", link.toString());
302 +
303 + if (mastershipService.
304 + getLocalRole(link.src().deviceId()) == MastershipRole.MASTER) {
305 + DefaultGroupHandler groupHandler =
306 + groupHandlerMap.get(link.src().deviceId());
307 + if (groupHandler != null) {
308 + groupHandler.linkUp(link);
309 + }
310 + }
311 + defaultRoutingHandler.startPopulationProcess();
312 + }
313 +
314 + private void processLinkRemoved(Link link) {
315 + log.debug("A link {} was removed", link.toString());
316 + defaultRoutingHandler.startPopulationProcess();
317 + }
318 +
319 +
320 + private void processGroupAdded(Group group) {
321 + log.debug("A new group with ID {} was added", group.id());
322 + defaultRoutingHandler.resumePopulationProcess();
323 + }
324 +
325 + private void processDeviceAdded(Device device) {
326 + log.debug("A new device with ID {} was added", device.id());
327 + defaultRoutingHandler.populateTtpRules(device.id());
328 + DefaultGroupHandler dgh = DefaultGroupHandler.createGroupHandler(
329 + device.id(), appId, new DeviceConfiguration(), linkService, groupService);
330 + dgh.createGroups();
331 + groupHandlerMap.put(device.id(), dgh);
332 + }
333 +
334 + private void processPortRemoved(Device device, Port port) {
335 + log.debug("Port {} was removed", port.toString());
336 + DefaultGroupHandler groupHandler =
337 + groupHandlerMap.get(device.id());
338 + if (groupHandler != null) {
339 + groupHandler.portDown(port.number());
340 + }
341 + }
342 +}
...@@ -345,7 +345,8 @@ public final class KryoNamespaces { ...@@ -345,7 +345,8 @@ public final class KryoNamespaces {
345 MplsLabelResourceAllocation.class, 345 MplsLabelResourceAllocation.class,
346 MplsLabelResourceRequest.class, 346 MplsLabelResourceRequest.class,
347 MplsLabel.class, 347 MplsLabel.class,
348 - org.onlab.packet.MplsLabel.class 348 + org.onlab.packet.MplsLabel.class,
349 + org.onlab.packet.MPLS.class
349 ) 350 )
350 351
351 .build(); 352 .build();
......
...@@ -285,4 +285,18 @@ ...@@ -285,4 +285,18 @@
285 <bundle>mvn:org.onosproject/onos-app-calendar/@ONOS-VERSION</bundle> 285 <bundle>mvn:org.onosproject/onos-app-calendar/@ONOS-VERSION</bundle>
286 </feature> 286 </feature>
287 287
288 + <feature name="onos-app-grouphandler" version="@FEATURE-VERSION"
289 + description="Group Handler Sample App">
290 + <feature>onos-api</feature>
291 + <bundle>mvn:org.onosproject/onos-app-grouphandler/@ONOS-VERSION</bundle>
292 + </feature>
293 +
294 + <feature name="onos-app-segmentrouting" version="@FEATURE-VERSION"
295 + description="Segment routing application">
296 + <feature>onos-api</feature>
297 + <bundle>mvn:org.onosproject/onos-app-segmentrouting/@ONOS-VERSION</bundle>
298 + <bundle>mvn:org.onosproject/onos-app-grouphandler/@ONOS-VERSION</bundle>
299 + </feature>
300 +
301 +
288 </features> 302 </features>
......
...@@ -70,7 +70,7 @@ public final class DriverManager implements OpenFlowSwitchDriverFactory { ...@@ -70,7 +70,7 @@ public final class DriverManager implements OpenFlowSwitchDriverFactory {
70 if (vendor.startsWith("Stanford University, Ericsson Research and CPqD Research") 70 if (vendor.startsWith("Stanford University, Ericsson Research and CPqD Research")
71 && 71 &&
72 hw.startsWith("OpenFlow 1.3 Reference Userspace Switch")) { 72 hw.startsWith("OpenFlow 1.3 Reference Userspace Switch")) {
73 - return new OFSwitchImplCPqD13(dpid, desc); 73 + return new OFSwitchImplSpringOpenTTP(dpid, desc);
74 } 74 }
75 75
76 if (hw.startsWith("Open vSwitch")) { 76 if (hw.startsWith("Open vSwitch")) {
......
...@@ -15,43 +15,21 @@ ...@@ -15,43 +15,21 @@
15 */ 15 */
16 package org.onosproject.openflow.drivers; 16 package org.onosproject.openflow.drivers;
17 17
18 +import com.google.common.collect.Lists;
18 import org.onosproject.openflow.controller.Dpid; 19 import org.onosproject.openflow.controller.Dpid;
19 -import org.onosproject.openflow.controller.RoleState;
20 -import org.onosproject.openflow.controller.OpenFlowSwitch.TableType;
21 import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch; 20 import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch;
22 import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeAlreadyStarted; 21 import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeAlreadyStarted;
23 import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeCompleted; 22 import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeCompleted;
24 import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeNotStarted; 23 import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeNotStarted;
25 -import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
26 -import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
27 -import org.projectfloodlight.openflow.protocol.OFErrorMsg;
28 -import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
29 -import org.projectfloodlight.openflow.protocol.OFGroupFeaturesStatsReply;
30 -import org.projectfloodlight.openflow.protocol.OFMatchV3;
31 -import org.projectfloodlight.openflow.protocol.OFOxmList;
32 -import org.projectfloodlight.openflow.protocol.OFPortDesc;
33 -import org.projectfloodlight.openflow.protocol.OFStatsReply;
34 import org.projectfloodlight.openflow.protocol.OFFlowMod; 24 import org.projectfloodlight.openflow.protocol.OFFlowMod;
35 import org.projectfloodlight.openflow.protocol.OFDescStatsReply; 25 import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
36 import org.projectfloodlight.openflow.protocol.OFFactory; 26 import org.projectfloodlight.openflow.protocol.OFFactory;
37 import org.projectfloodlight.openflow.protocol.OFMessage; 27 import org.projectfloodlight.openflow.protocol.OFMessage;
38 import org.projectfloodlight.openflow.protocol.OFType; 28 import org.projectfloodlight.openflow.protocol.OFType;
39 -import org.projectfloodlight.openflow.protocol.action.OFAction;
40 import org.projectfloodlight.openflow.protocol.instruction.OFInstruction; 29 import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
41 -import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthType; 30 +import org.projectfloodlight.openflow.protocol.instruction.OFInstructionGotoTable;
42 -import org.projectfloodlight.openflow.protocol.oxm.OFOxmInPort;
43 -import org.projectfloodlight.openflow.protocol.oxm.OFOxmVlanVid;
44 -import org.projectfloodlight.openflow.types.EthType;
45 -import org.projectfloodlight.openflow.types.MacAddress;
46 -import org.projectfloodlight.openflow.types.OFBufferId;
47 -import org.projectfloodlight.openflow.types.OFPort;
48 -import org.projectfloodlight.openflow.types.OFVlanVidMatch;
49 import org.projectfloodlight.openflow.types.TableId; 31 import org.projectfloodlight.openflow.types.TableId;
50 -import org.projectfloodlight.openflow.types.U32;
51 -import org.projectfloodlight.openflow.util.HexString;
52 32
53 -import java.io.IOException;
54 -import java.util.ArrayList;
55 import java.util.Collections; 33 import java.util.Collections;
56 import java.util.List; 34 import java.util.List;
57 import java.util.concurrent.atomic.AtomicBoolean; 35 import java.util.concurrent.atomic.AtomicBoolean;
...@@ -63,8 +41,6 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { ...@@ -63,8 +41,6 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch {
63 private final AtomicBoolean driverHandshakeComplete; 41 private final AtomicBoolean driverHandshakeComplete;
64 private AtomicBoolean haltStateMachine; 42 private AtomicBoolean haltStateMachine;
65 43
66 - private DriverState driverState;
67 -
68 /* Default table ID - compatible with CpqD switch */ 44 /* Default table ID - compatible with CpqD switch */
69 private static final int TABLE_VLAN = 0; 45 private static final int TABLE_VLAN = 0;
70 private static final int TABLE_TMAC = 1; 46 private static final int TABLE_TMAC = 1;
...@@ -72,14 +48,6 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { ...@@ -72,14 +48,6 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch {
72 private static final int TABLE_MPLS = 3; 48 private static final int TABLE_MPLS = 3;
73 private static final int TABLE_ACL = 5; 49 private static final int TABLE_ACL = 5;
74 50
75 - private static final long TEST_FLOW_REMOVED_MASK = 0xf;
76 - private static final long TEST_PACKET_IN_MASK = 0x7;
77 - private static final long TEST_PORT_STATUS_MASK = 0x7;
78 -
79 - private static final int OFPCML_NO_BUFFER = 0xffff;
80 -
81 - private long barrierXidToWaitFor = -1;
82 -
83 /* Set the default values. These variables will get 51 /* Set the default values. These variables will get
84 * overwritten based on the switch vendor type 52 * overwritten based on the switch vendor type
85 */ 53 */
...@@ -89,17 +57,10 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { ...@@ -89,17 +57,10 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch {
89 protected int mplsTableId = TABLE_MPLS; 57 protected int mplsTableId = TABLE_MPLS;
90 protected int aclTableId = TABLE_ACL; 58 protected int aclTableId = TABLE_ACL;
91 59
92 - /* priority values for OF message */
93 - private static final short MAX_PRIORITY = (short) 0xffff;
94 - private static final short PRIORITY_MULTIPLIER = (short) 2046;
95 - private static final short MIN_PRIORITY = 0x0;
96 -
97 -
98 protected OFSwitchImplSpringOpenTTP(Dpid dpid, OFDescStatsReply desc) { 60 protected OFSwitchImplSpringOpenTTP(Dpid dpid, OFDescStatsReply desc) {
99 super(dpid); 61 super(dpid);
100 driverHandshakeComplete = new AtomicBoolean(false); 62 driverHandshakeComplete = new AtomicBoolean(false);
101 haltStateMachine = new AtomicBoolean(false); 63 haltStateMachine = new AtomicBoolean(false);
102 - driverState = DriverState.INIT;
103 setSwitchDescription(desc); 64 setSwitchDescription(desc);
104 } 65 }
105 66
...@@ -117,6 +78,7 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { ...@@ -117,6 +78,7 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch {
117 return null; 78 return null;
118 } 79 }
119 80
81 +
120 @Override 82 @Override
121 public void startDriverHandshake() { 83 public void startDriverHandshake() {
122 log.debug("Starting driver handshake for sw {}", getStringId()); 84 log.debug("Starting driver handshake for sw {}", getStringId());
...@@ -126,12 +88,9 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { ...@@ -126,12 +88,9 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch {
126 startDriverHandshakeCalled = true; 88 startDriverHandshakeCalled = true;
127 factory = this.factory(); 89 factory = this.factory();
128 90
129 - try { 91 + driverHandshakeComplete.set(true);
130 - nextDriverState(); 92 + log.debug("Driver handshake is complete");
131 - } catch (IOException e) { 93 +
132 - log.error("Error {} during driver handshake for sw {}", e.getCause(),
133 - getStringId());
134 - }
135 } 94 }
136 95
137 @Override 96 @Override
...@@ -142,6 +101,8 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { ...@@ -142,6 +101,8 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch {
142 return driverHandshakeComplete.get(); 101 return driverHandshakeComplete.get();
143 } 102 }
144 103
104 +
105 +
145 @Override 106 @Override
146 public void processDriverHandshakeMessage(OFMessage m) { 107 public void processDriverHandshakeMessage(OFMessage m) {
147 if (!startDriverHandshakeCalled) { 108 if (!startDriverHandshakeCalled) {
...@@ -150,13 +111,9 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { ...@@ -150,13 +111,9 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch {
150 if (driverHandshakeComplete.get()) { 111 if (driverHandshakeComplete.get()) {
151 throw new SwitchDriverSubHandshakeCompleted(m); 112 throw new SwitchDriverSubHandshakeCompleted(m);
152 } 113 }
153 - try {
154 - processOFMessage(m);
155 - } catch (IOException e) {
156 - log.error("Error generated when processing OFMessage {}", e.getCause());
157 - }
158 } 114 }
159 115
116 +
160 @Override 117 @Override
161 public void write(OFMessage msg) { 118 public void write(OFMessage msg) {
162 this.channel.write(Collections.singletonList(msg)); 119 this.channel.write(Collections.singletonList(msg));
...@@ -168,384 +125,51 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { ...@@ -168,384 +125,51 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch {
168 } 125 }
169 126
170 @Override 127 @Override
171 - public void transformAndSendMsg(OFMessage m, TableType tableType) { 128 + public void transformAndSendMsg(OFMessage msg, TableType type) {
172 - 129 + if (msg.getType() == OFType.FLOW_MOD) {
173 - if (m.getType() == OFType.FLOW_MOD) { 130 + OFFlowMod flowMod = (OFFlowMod) msg;
174 - OFFlowMod flowMod = (OFFlowMod) m;
175 OFFlowMod.Builder builder = flowMod.createBuilder(); 131 OFFlowMod.Builder builder = flowMod.createBuilder();
176 - builder.setTableId(getTableId(tableType)); 132 + List<OFInstruction> instructions = flowMod.getInstructions();
177 - OFFlowMod newFlowMod = builder.build(); 133 + List<OFInstruction> newInstructions = Lists.newArrayList();
178 - if (role == RoleState.MASTER) { 134 + for (OFInstruction i : instructions) {
179 - this.write(newFlowMod); 135 + if (i instanceof OFInstructionGotoTable) {
180 - } 136 + OFInstructionGotoTable gotoTable = (OFInstructionGotoTable) i;
137 + TableType tid = TableType.values()[gotoTable.getTableId().getValue()];
138 + newInstructions.add(
139 + gotoTable.createBuilder()
140 + .setTableId(getTableId(tid)).build());
181 } else { 141 } else {
182 - if (role == RoleState.MASTER) { 142 + newInstructions.add(i);
183 - this.write(m);
184 - }
185 - }
186 - }
187 -
188 - /*
189 - * Driver handshake state machine
190 - */
191 -
192 - enum DriverState {
193 - INIT,
194 - SET_TABLE_MISS_ENTRIES,
195 - SET_TABLE_VLAN_TMAC,
196 - AUDIT_GROUPS,
197 - SET_GROUPS,
198 - VERIFY_GROUPS,
199 - SET_ADJACENCY_LABELS,
200 - EXIT
201 - }
202 -
203 - protected void nextDriverState() throws IOException {
204 - DriverState currentState = driverState;
205 - if (haltStateMachine.get()) {
206 - return;
207 - }
208 - switch (currentState) {
209 - case INIT:
210 - driverState = DriverState.SET_TABLE_MISS_ENTRIES;
211 - setTableMissEntries();
212 - sendHandshakeBarrier();
213 - break;
214 - case SET_TABLE_MISS_ENTRIES:
215 - driverState = DriverState.SET_TABLE_VLAN_TMAC;
216 - /* TODO: read network configuration
217 - boolean isConfigured = getNetworkConfig();
218 - if (!isConfigured) {
219 - return; // this will result in a handshake timeout
220 - }
221 - */
222 - populateTableVlan();
223 - populateTableTMac();
224 - sendHandshakeBarrier();
225 - break;
226 - case SET_TABLE_VLAN_TMAC:
227 - driverState = DriverState.EXIT;
228 - driverHandshakeComplete.set(true);
229 - log.debug("Driver handshake is complete");
230 - break;
231 - case EXIT:
232 - default:
233 - driverState = DriverState.EXIT;
234 - log.error("Driver handshake has exited for sw: {}", getStringId());
235 - }
236 - }
237 -
238 - private void processStatsReply(OFStatsReply sr) {
239 - switch (sr.getStatsType()) {
240 - case AGGREGATE:
241 - break;
242 - case DESC:
243 - break;
244 - case EXPERIMENTER:
245 - break;
246 - case FLOW:
247 - break;
248 - case GROUP_DESC:
249 - processGroupDesc((OFGroupDescStatsReply) sr);
250 - break;
251 - case GROUP_FEATURES:
252 - processGroupFeatures((OFGroupFeaturesStatsReply) sr);
253 - break;
254 - case METER_CONFIG:
255 - break;
256 - case METER_FEATURES:
257 - break;
258 - case PORT_DESC:
259 - break;
260 - case TABLE_FEATURES:
261 - break;
262 - default:
263 - break;
264 -
265 } 143 }
266 } 144 }
145 + builder.setTableId(getTableId(type));
146 + builder.setInstructions(newInstructions);
147 + OFMessage msgnew = builder.build();
148 + channel.write(Collections.singletonList(msgnew));
149 + log.trace("Installed {}", msgnew);
267 150
268 - private void processOFMessage(OFMessage m) throws IOException {
269 - switch (m.getType()) {
270 - case BARRIER_REPLY:
271 - processBarrierReply(m);
272 - break;
273 -
274 - case ERROR:
275 - processErrorMessage(m);
276 - break;
277 -
278 - case GET_ASYNC_REPLY:
279 - OFAsyncGetReply asrep = (OFAsyncGetReply) m;
280 - decodeAsyncGetReply(asrep);
281 - break;
282 -
283 - case PACKET_IN:
284 - // not ready to handle packet-ins
285 - break;
286 -
287 - case QUEUE_GET_CONFIG_REPLY:
288 - // not doing queue config yet
289 - break;
290 -
291 - case STATS_REPLY:
292 - processStatsReply((OFStatsReply) m);
293 - break;
294 -
295 - case ROLE_REPLY: // channelHandler should handle this
296 - case PORT_STATUS: // channelHandler should handle this
297 - case FEATURES_REPLY: // don't care
298 - case FLOW_REMOVED: // don't care
299 - default:
300 - log.debug("Received message {} during switch-driver subhandshake "
301 - + "from switch {} ... Ignoring message", m, getStringId());
302 - }
303 - }
304 -
305 - private void processBarrierReply(OFMessage m) throws IOException {
306 - if (m.getXid() == barrierXidToWaitFor) {
307 - // Driver state-machine progresses to the next state.
308 - // If Barrier messages is not received, then eventually
309 - // the ChannelHandler state machine will timeout, and the switch
310 - // will be disconnected.
311 - nextDriverState();
312 } else { 151 } else {
313 - log.error("Received incorrect barrier-message xid {} (expected: {}) in " 152 + channel.write(Collections.singletonList(msg));
314 - + "switch-driver state {} for switch {}", m, barrierXidToWaitFor,
315 - driverState, getStringId());
316 - }
317 - }
318 -
319 - private void processErrorMessage(OFMessage m) {
320 - log.error("Switch {} Error {} in DriverState", getStringId(),
321 - (OFErrorMsg) m, driverState);
322 - }
323 -
324 - private void processGroupFeatures(OFGroupFeaturesStatsReply gfsr) {
325 - log.info("Sw: {} Group Features {}", getStringId(), gfsr);
326 - }
327 -
328 - private void processGroupDesc(OFGroupDescStatsReply gdsr) {
329 - log.info("Sw: {} Group Desc {}", getStringId(), gdsr);
330 - }
331 -
332 - /*
333 - * Utility functions
334 - */
335 -
336 - private void decodeAsyncGetReply(OFAsyncGetReply rep) {
337 - long frm = rep.getFlowRemovedMaskEqualMaster();
338 - //long frs = rep.getFlowRemovedMaskSlave();
339 - long pim = rep.getPacketInMaskEqualMaster();
340 - //long pis = rep.getPacketInMaskSlave();
341 - long psm = rep.getPortStatusMaskEqualMaster();
342 - //long pss = rep.getPortStatusMaskSlave();
343 -
344 - if (role == RoleState.MASTER || role == RoleState.EQUAL) { // should separate
345 - log.info("FRM:{}", HexString.toHexString((frm & TEST_FLOW_REMOVED_MASK)));
346 - log.info("PIM:{}", HexString.toHexString((pim & TEST_PACKET_IN_MASK)));
347 - log.info("PSM:{}", HexString.toHexString((psm & TEST_PORT_STATUS_MASK)));
348 - }
349 - }
350 -
351 - protected void setTableMissEntries() throws IOException {
352 - // set all table-miss-entries
353 - populateTableMissEntry(vlanTableId, true, false, false, -1);
354 - populateTableMissEntry(tmacTableId, true, false, false, -1);
355 - populateTableMissEntry(ipv4UnicastTableId, false, true, true,
356 - aclTableId);
357 - populateTableMissEntry(mplsTableId, false, true, true,
358 - aclTableId);
359 - populateTableMissEntry(aclTableId, false, false, false, -1);
360 - log.debug("TableMissEntries are set");
361 - }
362 -
363 - /**
364 - * Adds a table-miss-entry to a pipeline table.
365 - * <p>
366 - * The table-miss-entry can be added with 'write-actions' or
367 - * 'apply-actions'. It can also add a 'goto-table' instruction. By default
368 - * if none of the booleans in the call are set, then the table-miss entry is
369 - * added with no instructions, which means that if a packet hits the
370 - * table-miss-entry, pipeline execution will stop, and the action set
371 - * associated with the packet will be executed.
372 - *
373 - * @param tableToAdd the table to where the table-miss-entry will be added
374 - * @param toControllerNow as an APPLY_ACTION instruction
375 - * @param toControllerWrite as a WRITE_ACTION instruction
376 - * @param toTable as a GOTO_TABLE instruction
377 - * @param tableToSend the table to send as per the GOTO_TABLE instruction it
378 - * needs to be set if 'toTable' is true. Ignored of 'toTable' is
379 - * false.
380 - */
381 - protected void populateTableMissEntry(int tableToAdd, boolean toControllerNow,
382 - boolean toControllerWrite,
383 - boolean toTable, int tableToSend) {
384 - OFOxmList oxmList = OFOxmList.EMPTY;
385 - OFMatchV3 match = factory.buildMatchV3()
386 - .setOxmList(oxmList)
387 - .build();
388 - OFAction outc = factory.actions()
389 - .buildOutput()
390 - .setPort(OFPort.CONTROLLER)
391 - .setMaxLen(OFPCML_NO_BUFFER)
392 - .build();
393 - List<OFInstruction> instructions = new ArrayList<OFInstruction>();
394 - if (toControllerNow) {
395 - // table-miss instruction to send to controller immediately
396 - OFInstruction instr = factory.instructions()
397 - .buildApplyActions()
398 - .setActions(Collections.singletonList(outc))
399 - .build();
400 - instructions.add(instr);
401 - }
402 -
403 - if (toControllerWrite) {
404 - // table-miss instruction to write-action to send to controller
405 - // this will be executed whenever the action-set gets executed
406 - OFInstruction instr = factory.instructions()
407 - .buildWriteActions()
408 - .setActions(Collections.singletonList(outc))
409 - .build();
410 - instructions.add(instr);
411 - }
412 -
413 - if (toTable) {
414 - // table-miss instruction to goto-table x
415 - OFInstruction instr = factory.instructions()
416 - .gotoTable(TableId.of(tableToSend));
417 - instructions.add(instr);
418 - }
419 -
420 - if (!toControllerNow && !toControllerWrite && !toTable) {
421 - // table-miss has no instruction - at which point action-set will be
422 - // executed - if there is an action to output/group in the action
423 - // set
424 - // the packet will be sent there, otherwise it will be dropped.
425 - instructions = Collections.<OFInstruction>emptyList();
426 - }
427 -
428 - OFMessage tableMissEntry = factory.buildFlowAdd()
429 - .setTableId(TableId.of(tableToAdd))
430 - .setMatch(match) // match everything
431 - .setInstructions(instructions)
432 - .setPriority(MIN_PRIORITY)
433 - .setBufferId(OFBufferId.NO_BUFFER)
434 - .setIdleTimeout(0)
435 - .setHardTimeout(0)
436 - .setXid(getNextTransactionId())
437 - .build();
438 - write(tableMissEntry);
439 - }
440 -
441 - private void populateTableVlan() throws IOException {
442 - List<OFMessage> msglist = new ArrayList<OFMessage>();
443 - for (OFPortDesc p : getPorts()) {
444 - int pnum = p.getPortNo().getPortNumber();
445 - if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
446 - OFOxmInPort oxp = factory.oxms().inPort(p.getPortNo());
447 - OFOxmVlanVid oxv = factory.oxms()
448 - .vlanVid(OFVlanVidMatch.UNTAGGED);
449 - OFOxmList oxmList = OFOxmList.of(oxp, oxv);
450 - OFMatchV3 match = factory.buildMatchV3()
451 - .setOxmList(oxmList).build();
452 -
453 - // TODO: match on vlan-tagged packets for vlans configured on
454 - // subnet ports and strip-vlan
455 -
456 - OFInstruction gotoTbl = factory.instructions().buildGotoTable()
457 - .setTableId(TableId.of(tmacTableId)).build();
458 - List<OFInstruction> instructions = new ArrayList<OFInstruction>();
459 - instructions.add(gotoTbl);
460 - OFMessage flowEntry = factory.buildFlowAdd()
461 - .setTableId(TableId.of(vlanTableId))
462 - .setMatch(match)
463 - .setInstructions(instructions)
464 - .setPriority(1000) // does not matter - all rules
465 - // exclusive
466 - .setBufferId(OFBufferId.NO_BUFFER)
467 - .setIdleTimeout(0)
468 - .setHardTimeout(0)
469 - .setXid(getNextTransactionId())
470 - .build();
471 - msglist.add(flowEntry);
472 - }
473 } 153 }
474 - write(msglist);
475 - log.debug("Adding {} port/vlan-rules in sw {}", msglist.size(), getStringId());
476 } 154 }
477 155
478 - private void populateTableTMac() throws IOException { 156 + @Override
479 - // match for router-mac and ip-packets 157 + public TableType getTableType(TableId tid) {
480 - OFOxmEthType oxe = factory.oxms().ethType(EthType.IPv4); 158 + switch (tid.getValue()) {
481 - 159 + case TABLE_IPV4_UNICAST:
482 - /* TODO: need to read network config and need to allow only 160 + return TableType.IP;
483 - the packets with DMAC as the correspondent router MAC address 161 + case TABLE_MPLS:
484 - Until network configuration is implemented, all packets are allowed 162 + return TableType.MPLS;
485 - 163 + case TABLE_ACL:
486 - OFOxmEthDst dmac = factory.oxms().ethDst(getRouterMacAddr()); 164 + return TableType.ACL;
487 - OFOxmList oxmListIp = OFOxmList.of(dmac, oxe); 165 + case TABLE_VLAN:
488 - OFMatchV3 matchIp = factory.buildMatchV3() 166 + return TableType.VLAN;
489 - .setOxmList(oxmListIp).build(); 167 + case TABLE_TMAC:
490 - */ 168 + return TableType.ETHER;
491 - OFOxmList oxmList = OFOxmList.EMPTY; 169 + default:
492 - OFMatchV3 matchIp = factory.buildMatchV3() 170 + log.error("Table type for Table id {} is not supported in the driver", tid);
493 - .setOxmList(oxmList) 171 + return TableType.NONE;
494 - .build();
495 -
496 - OFInstruction gotoTblIp = factory.instructions().buildGotoTable()
497 - .setTableId(TableId.of(ipv4UnicastTableId)).build();
498 - List<OFInstruction> instructionsIp = Collections.singletonList(gotoTblIp);
499 - OFMessage ipEntry = factory.buildFlowAdd()
500 - .setTableId(TableId.of(tmacTableId))
501 - .setMatch(matchIp)
502 - .setInstructions(instructionsIp)
503 - .setPriority(1000) // strict priority required lower than
504 - // multicastMac
505 - .setBufferId(OFBufferId.NO_BUFFER)
506 - .setIdleTimeout(0)
507 - .setHardTimeout(0)
508 - .setXid(getNextTransactionId())
509 - .build();
510 -
511 - // match for router-mac and mpls packets
512 - OFOxmEthType oxmpls = factory.oxms().ethType(EthType.MPLS_UNICAST);
513 - /* TODO: need to read network config and need to allow only
514 - the packets with DMAC as the correspondent router MAC address
515 - OFOxmList oxmListMpls = OFOxmList.of(dmac, oxmpls);
516 - OFMatchV3 matchMpls = factory.buildMatchV3()
517 - .setOxmList(oxmListMpls).build();
518 - */
519 - OFOxmList oxmListMpls = OFOxmList.EMPTY;
520 - OFMatchV3 matchMpls = factory.buildMatchV3()
521 - .setOxmList(oxmList)
522 - .build();
523 -
524 - OFInstruction gotoTblMpls = factory.instructions().buildGotoTable()
525 - .setTableId(TableId.of(mplsTableId)).build();
526 - List<OFInstruction> instructionsMpls = Collections.singletonList(gotoTblMpls);
527 - OFMessage mplsEntry = factory.buildFlowAdd()
528 - .setTableId(TableId.of(tmacTableId))
529 - .setMatch(matchMpls)
530 - .setInstructions(instructionsMpls)
531 - .setPriority(1001) // strict priority required lower than
532 - // multicastMac
533 - .setBufferId(OFBufferId.NO_BUFFER)
534 - .setIdleTimeout(0)
535 - .setHardTimeout(0)
536 - .setXid(getNextTransactionId())
537 - .build();
538 -
539 - log.debug("Adding termination-mac-rules in sw {}", getStringId());
540 - List<OFMessage> msglist = new ArrayList<OFMessage>(2);
541 - msglist.add(ipEntry);
542 - msglist.add(mplsEntry);
543 - write(msglist);
544 } 172 }
545 -
546 - private MacAddress getRouterMacAddr() {
547 - // TODO: need to read network config : RouterIp
548 - return MacAddress.of("00:00:00:00:00:00");
549 } 173 }
550 174
551 private TableId getTableId(TableType tableType) { 175 private TableId getTableId(TableType tableType) {
...@@ -556,6 +180,10 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { ...@@ -556,6 +180,10 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch {
556 return TableId.of(mplsTableId); 180 return TableId.of(mplsTableId);
557 case ACL: 181 case ACL:
558 return TableId.of(aclTableId); 182 return TableId.of(aclTableId);
183 + case VLAN:
184 + return TableId.of(vlanTableId);
185 + case ETHER:
186 + return TableId.of(tmacTableId);
559 default: { 187 default: {
560 log.error("Table type {} is not supported in the driver", tableType); 188 log.error("Table type {} is not supported in the driver", tableType);
561 return TableId.NONE; 189 return TableId.NONE;
...@@ -563,19 +191,4 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { ...@@ -563,19 +191,4 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch {
563 } 191 }
564 } 192 }
565 193
566 - private void sendHandshakeBarrier() throws IOException {
567 - long xid = getNextTransactionId();
568 - barrierXidToWaitFor = xid;
569 - OFBarrierRequest br = factory()
570 - .buildBarrierRequest()
571 - .setXid(xid)
572 - .build();
573 - write(br);
574 - }
575 -
576 - @Override
577 - public TableType getTableType(TableId tid) {
578 - return TableType.NONE; // XXX this needs to be fixed
579 - }
580 -
581 } 194 }
......
1 +package org.onlab.packet;
2 +
3 +import java.nio.ByteBuffer;
4 +import java.util.HashMap;
5 +import java.util.Map;
6 +
7 +public class MPLS extends BasePacket {
8 + public static final int ADDRESS_LENGTH = 4;
9 + public static final byte PROTOCOL_IPV4 = 0x1;
10 + public static final byte PROTOCOL_MPLS = 0x6;
11 + public static final Map<Byte, Class<? extends IPacket>> PROTOCOL_CLASS_MAP;
12 +
13 + static {
14 + PROTOCOL_CLASS_MAP = new HashMap<Byte, Class<? extends IPacket>>();
15 + PROTOCOL_CLASS_MAP.put(PROTOCOL_IPV4, IPv4.class);
16 + PROTOCOL_CLASS_MAP.put(PROTOCOL_MPLS, MPLS.class);
17 + }
18 +
19 + protected int label; //20bits
20 + protected byte bos; //1bit
21 + protected byte ttl; //8bits
22 + protected byte protocol;
23 +
24 + /**
25 + * Default constructor that sets the version to 4.
26 + */
27 + public MPLS() {
28 + super();
29 + this.bos = 1;
30 + this.protocol = PROTOCOL_IPV4;
31 + }
32 +
33 + @Override
34 + public byte[] serialize() {
35 + byte[] payloadData = null;
36 + if (payload != null) {
37 + payload.setParent(this);
38 + payloadData = payload.serialize();
39 + }
40 +
41 + byte[] data = new byte[(4 + ((payloadData != null) ? payloadData.length : 0)) ];
42 + ByteBuffer bb = ByteBuffer.wrap(data);
43 +
44 + bb.putInt(((this.label & 0x000fffff) << 12) | ((this.bos & 0x1) << 8 | (this.ttl & 0xff)));
45 + if (payloadData != null) {
46 + bb.put(payloadData);
47 + }
48 +
49 + return data;
50 + }
51 +
52 + @Override
53 + public IPacket deserialize(byte[] data, int offset, int length) {
54 + ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
55 +
56 + int mplsheader = bb.getInt();
57 + this.label = ((mplsheader & 0xfffff000) >> 12);
58 + this.bos = (byte) ((mplsheader & 0x00000100) >> 8);
59 + this.bos = (byte) (mplsheader & 0x000000ff);
60 + this.protocol = (this.bos == 1) ? PROTOCOL_IPV4 : PROTOCOL_MPLS;
61 +
62 + IPacket payload;
63 + if (IPv4.PROTOCOL_CLASS_MAP.containsKey(this.protocol)) {
64 + Class<? extends IPacket> clazz = IPv4.PROTOCOL_CLASS_MAP.get(this.protocol);
65 + try {
66 + payload = clazz.newInstance();
67 + } catch (Exception e) {
68 + throw new RuntimeException("Error parsing payload for MPLS packet", e);
69 + }
70 + } else {
71 + payload = new Data();
72 + }
73 + this.payload = payload.deserialize(data, bb.position(), bb.limit() - bb.position());
74 + this.payload.setParent(this);
75 +
76 + return this;
77 + }
78 +
79 + /**
80 + * Returns the MPLS label.
81 + *
82 + * @return MPLS label
83 + */
84 + public int getLabel() {
85 + return label;
86 + }
87 +
88 + /**
89 + * Sets the MPLS label.
90 + *
91 + * @param label
92 + */
93 + public void setLabel(int label) {
94 + this.label = label;
95 + }
96 +
97 + /**
98 + * Returns the MPLS TTL of the packet.
99 + *
100 + * @return MPLS TTL of the packet
101 + */
102 + public byte getTtl() {
103 + return ttl;
104 + }
105 +
106 + /**
107 + * Sets the MPLS TTL of the packet.
108 + *
109 + * @param ttl MPLS TTL
110 + */
111 + public void setTtl(byte ttl) {
112 + this.ttl = ttl;
113 + }
114 +
115 +}