blob: 7abf1347c6f3d2075c178f447751734530803ece [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 Open Networking Laboratory
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.fwd;
alshabib030111e2014-09-15 15:56:42 -070017
Jonathan Hartbc4a7932014-10-21 11:46:00 -070018import static org.slf4j.LoggerFactory.getLogger;
19
20import java.util.Dictionary;
21import java.util.Set;
Dusan Pajin0d1d48f2015-02-20 16:05:11 +010022import static com.google.common.base.Strings.isNullOrEmpty;
Jonathan Hartbc4a7932014-10-21 11:46:00 -070023
alshabib030111e2014-09-15 15:56:42 -070024import org.apache.felix.scr.annotations.Activate;
25import org.apache.felix.scr.annotations.Component;
26import org.apache.felix.scr.annotations.Deactivate;
tomc16656f2014-10-15 18:30:31 -070027import org.apache.felix.scr.annotations.Modified;
28import org.apache.felix.scr.annotations.Property;
alshabib030111e2014-09-15 15:56:42 -070029import org.apache.felix.scr.annotations.Reference;
30import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Harte8600eb2015-01-12 10:30:45 -080031import org.onlab.packet.Ethernet;
Dusan Pajin0d1d48f2015-02-20 16:05:11 +010032import org.onlab.packet.IPv4;
33import org.onlab.packet.IPv6;
34import org.onlab.packet.TCP;
35import org.onlab.packet.UDP;
36import org.onlab.packet.ICMP;
37import org.onlab.packet.ICMP6;
38import org.onlab.packet.Ip4Prefix;
39import org.onlab.packet.Ip6Prefix;
40import org.onlab.packet.VlanId;
Brian O'Connorabafb502014-12-02 22:26:20 -080041import org.onosproject.core.ApplicationId;
42import org.onosproject.core.CoreService;
43import org.onosproject.net.Host;
44import org.onosproject.net.HostId;
45import org.onosproject.net.Path;
46import org.onosproject.net.PortNumber;
47import org.onosproject.net.flow.DefaultFlowRule;
48import org.onosproject.net.flow.DefaultTrafficSelector;
49import org.onosproject.net.flow.DefaultTrafficTreatment;
50import org.onosproject.net.flow.FlowRule;
51import org.onosproject.net.flow.FlowRuleService;
52import org.onosproject.net.flow.TrafficSelector;
53import org.onosproject.net.flow.TrafficTreatment;
54import org.onosproject.net.host.HostService;
55import org.onosproject.net.packet.InboundPacket;
56import org.onosproject.net.packet.PacketContext;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080057import org.onosproject.net.packet.PacketPriority;
Brian O'Connorabafb502014-12-02 22:26:20 -080058import org.onosproject.net.packet.PacketProcessor;
59import org.onosproject.net.packet.PacketService;
60import org.onosproject.net.topology.TopologyService;
tomc16656f2014-10-15 18:30:31 -070061import org.osgi.service.component.ComponentContext;
tomc370ebd2014-09-16 01:25:21 -070062import org.slf4j.Logger;
alshabib030111e2014-09-15 15:56:42 -070063
tomc370ebd2014-09-16 01:25:21 -070064/**
65 * Sample reactive forwarding application.
66 */
67@Component(immediate = true)
alshabib030111e2014-09-15 15:56:42 -070068public class ReactiveForwarding {
69
Dusan Pajin0d1d48f2015-02-20 16:05:11 +010070 private static final int DEFAULT_TIMEOUT = 10;
71 private static final int DEFAULT_PRIORITY = 10;
alshabibba5ac482014-10-02 17:15:20 -070072
tomc370ebd2014-09-16 01:25:21 -070073 private final Logger log = getLogger(getClass());
74
alshabib030111e2014-09-15 15:56:42 -070075 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected TopologyService topologyService;
77
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected PacketService packetService;
80
alshabib8aef1ad2014-09-15 17:47:31 -070081 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected HostService hostService;
83
alshabib7b2748f2014-09-16 20:21:11 -070084 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected FlowRuleService flowRuleService;
86
alshabib92c65ad2014-10-08 21:56:05 -070087 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected CoreService coreService;
89
tomc370ebd2014-09-16 01:25:21 -070090 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
alshabib030111e2014-09-15 15:56:42 -070091
alshabiba68eb962014-09-24 20:34:13 -070092 private ApplicationId appId;
93
Thomas Vachuskabd7f4b32014-12-04 20:54:55 -080094 @Property(name = "packetOutOnly", boolValue = false,
95 label = "Enable packet-out only forwarding; default is false")
96 private boolean packetOutOnly = false;
tomc16656f2014-10-15 18:30:31 -070097
Dusan Pajin0d1d48f2015-02-20 16:05:11 +010098 @Property(name = "packetOutOfppTable", boolValue = false,
99 label = "Enable first packet forwarding using OFPP_TABLE port " +
100 "instead of PacketOut with actual port; default is false")
101 private boolean packetOutOfppTable = false;
102
103 @Property(name = "flowTimeout", intValue = DEFAULT_TIMEOUT,
104 label = "Configure Flow Timeout for installed flow rules; " +
105 "default is 10 sec")
106 private int flowTimeout = DEFAULT_TIMEOUT;
107
108 @Property(name = "flowPriority", intValue = DEFAULT_PRIORITY,
109 label = "Configure Flow Priority for installed flow rules; " +
110 "default is 10")
111 private int flowPriority = DEFAULT_PRIORITY;
112
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900113 @Property(name = "ipv6Forwarding", boolValue = false,
114 label = "Enable IPv6 forwarding; default is false")
115 private boolean ipv6Forwarding = false;
116
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100117 @Property(name = "matchDstMacOnly", boolValue = false,
118 label = "Enable matching Dst Mac Only; default is false")
119 private boolean matchDstMacOnly = false;
120
121 @Property(name = "matchVlanId", boolValue = false,
122 label = "Enable matching Vlan ID; default is false")
123 private boolean matchVlanId = false;
124
125 @Property(name = "matchIpv4Address", boolValue = false,
126 label = "Enable matching IPv4 Addresses; default is false")
127 private boolean matchIpv4Address = false;
128
129 @Property(name = "matchIpv4Dscp", boolValue = false,
130 label = "Enable matching IPv4 DSCP and ECN; default is false")
131 private boolean matchIpv4Dscp = false;
132
133 @Property(name = "matchIpv6Address", boolValue = false,
134 label = "Enable matching IPv6 Addresses; default is false")
135 private boolean matchIpv6Address = false;
136
137 @Property(name = "matchIpv6FlowLabel", boolValue = false,
138 label = "Enable matching IPv6 FlowLabel; default is false")
139 private boolean matchIpv6FlowLabel = false;
140
141 @Property(name = "matchTcpUdpPorts", boolValue = false,
142 label = "Enable matching TCP/UDP ports; default is false")
143 private boolean matchTcpUdpPorts = false;
144
145 @Property(name = "matchIcmpFields", boolValue = false,
146 label = "Enable matching ICMPv4 and ICMPv6 fields; " +
147 "default is false")
148 private boolean matchIcmpFields = false;
149
150
alshabib030111e2014-09-15 15:56:42 -0700151 @Activate
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900152 public void activate(ComponentContext context) {
Brian O'Connorabafb502014-12-02 22:26:20 -0800153 appId = coreService.registerApplication("org.onosproject.fwd");
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800154
alshabibc274c902014-10-03 14:58:27 -0700155 packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 2);
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900156 readComponentConfiguration(context);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800157
158 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
159 selector.matchEthType(Ethernet.TYPE_IPV4);
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100160 packetService.requestPackets(selector.build(), PacketPriority.REACTIVE,
161 appId);
162 selector.matchEthType(Ethernet.TYPE_ARP);
163 packetService.requestPackets(selector.build(), PacketPriority.REACTIVE,
164 appId);
165
166 if (ipv6Forwarding) {
167 selector.matchEthType(Ethernet.TYPE_IPV6);
168 packetService.requestPackets(selector.build(),
169 PacketPriority.REACTIVE, appId);
170 }
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800171
alshabiba68eb962014-09-24 20:34:13 -0700172 log.info("Started with Application ID {}", appId.id());
alshabib030111e2014-09-15 15:56:42 -0700173 }
174
175 @Deactivate
176 public void deactivate() {
alshabiba68eb962014-09-24 20:34:13 -0700177 flowRuleService.removeFlowRulesById(appId);
alshabib030111e2014-09-15 15:56:42 -0700178 packetService.removeProcessor(processor);
179 processor = null;
tomc370ebd2014-09-16 01:25:21 -0700180 log.info("Stopped");
alshabib030111e2014-09-15 15:56:42 -0700181 }
tomc370ebd2014-09-16 01:25:21 -0700182
tomc16656f2014-10-15 18:30:31 -0700183 @Modified
184 public void modified(ComponentContext context) {
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900185 readComponentConfiguration(context);
186 }
187
188 /**
189 * Extracts properties from the component configuration context.
190 *
191 * @param context the component context
192 */
193 private void readComponentConfiguration(ComponentContext context) {
194 Dictionary<?, ?> properties = context.getProperties();
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100195 boolean packetOutOnlyEnabled =
196 isPropertyEnabled(properties, "packetOutOnly");
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900197 if (packetOutOnly != packetOutOnlyEnabled) {
198 packetOutOnly = packetOutOnlyEnabled;
199 log.info("Configured. Packet-out only forwarding is {}",
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100200 packetOutOnly ? "enabled" : "disabled");
tomc16656f2014-10-15 18:30:31 -0700201 }
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100202 boolean packetOutOfppTableEnabled =
203 isPropertyEnabled(properties, "packetOutOfppTable");
204 if (packetOutOfppTable != packetOutOfppTableEnabled) {
205 packetOutOfppTable = packetOutOfppTableEnabled;
206 log.info("Configured. Forwarding using OFPP_TABLE port is {}",
207 packetOutOfppTable ? "enabled" : "disabled");
208 }
209 boolean ipv6ForwardingEnabled =
210 isPropertyEnabled(properties, "ipv6Forwarding");
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900211 if (ipv6Forwarding != ipv6ForwardingEnabled) {
212 ipv6Forwarding = ipv6ForwardingEnabled;
213 log.info("Configured. IPv6 forwarding is {}",
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100214 ipv6Forwarding ? "enabled" : "disabled");
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900215 }
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100216 boolean matchDstMacOnlyEnabled =
217 isPropertyEnabled(properties, "matchDstMacOnly");
218 if (matchDstMacOnly != matchDstMacOnlyEnabled) {
219 matchDstMacOnly = matchDstMacOnlyEnabled;
220 log.info("Configured. Match Dst MAC Only is {}",
221 matchDstMacOnly ? "enabled" : "disabled");
222 }
223 boolean matchVlanIdEnabled =
224 isPropertyEnabled(properties, "matchVlanId");
225 if (matchVlanId != matchVlanIdEnabled) {
226 matchVlanId = matchVlanIdEnabled;
227 log.info("Configured. Matching Vlan ID is {}",
228 matchVlanId ? "enabled" : "disabled");
229 }
230 boolean matchIpv4AddressEnabled =
231 isPropertyEnabled(properties, "matchIpv4Address");
232 if (matchIpv4Address != matchIpv4AddressEnabled) {
233 matchIpv4Address = matchIpv4AddressEnabled;
234 log.info("Configured. Matching IPv4 Addresses is {}",
235 matchIpv4Address ? "enabled" : "disabled");
236 }
237 boolean matchIpv4DscpEnabled =
238 isPropertyEnabled(properties, "matchIpv4Dscp");
239 if (matchIpv4Dscp != matchIpv4DscpEnabled) {
240 matchIpv4Dscp = matchIpv4DscpEnabled;
241 log.info("Configured. Matching IPv4 DSCP and ECN is {}",
242 matchIpv4Dscp ? "enabled" : "disabled");
243 }
244 boolean matchIpv6AddressEnabled =
245 isPropertyEnabled(properties, "matchIpv6Address");
246 if (matchIpv6Address != matchIpv6AddressEnabled) {
247 matchIpv6Address = matchIpv6AddressEnabled;
248 log.info("Configured. Matching IPv6 Addresses is {}",
249 matchIpv6Address ? "enabled" : "disabled");
250 }
251 boolean matchIpv6FlowLabelEnabled =
252 isPropertyEnabled(properties, "matchIpv6FlowLabel");
253 if (matchIpv6FlowLabel != matchIpv6FlowLabelEnabled) {
254 matchIpv6FlowLabel = matchIpv6FlowLabelEnabled;
255 log.info("Configured. Matching IPv6 FlowLabel is {}",
256 matchIpv6FlowLabel ? "enabled" : "disabled");
257 }
258 boolean matchTcpUdpPortsEnabled =
259 isPropertyEnabled(properties, "matchTcpUdpPorts");
260 if (matchTcpUdpPorts != matchTcpUdpPortsEnabled) {
261 matchTcpUdpPorts = matchTcpUdpPortsEnabled;
262 log.info("Configured. Matching TCP/UDP fields is {}",
263 matchTcpUdpPorts ? "enabled" : "disabled");
264 }
265 boolean matchIcmpFieldsEnabled =
266 isPropertyEnabled(properties, "matchIcmpFields");
267 if (matchIcmpFields != matchIcmpFieldsEnabled) {
268 matchIcmpFields = matchIcmpFieldsEnabled;
269 log.info("Configured. Matching ICMP (v4 and v6) fields is {}",
270 matchIcmpFields ? "enabled" : "disabled");
271 }
272 Integer flowTimeoutConfigured =
273 getIntegerProperty(properties, "flowTimeout");
274 if (flowTimeoutConfigured == null) {
275 log.info("Flow Timeout is not configured, default value is {}",
276 flowTimeout);
277 } else {
278 flowTimeout = flowTimeoutConfigured;
279 log.info("Configured. Flow Timeout is configured to {}",
280 flowTimeout, " seconds");
281 }
282 Integer flowPriorityConfigured =
283 getIntegerProperty(properties, "flowPriority");
284 if (flowPriorityConfigured == null) {
285 log.info("Flow Priority is not configured, default value is {}",
286 flowPriority);
287 } else {
288 flowPriority = flowPriorityConfigured;
289 log.info("Configured. Flow Priority is configured to {}",
290 flowPriority);
291 }
292 }
293
294 /**
295 * Get Integer property from the propertyName
296 * Return null if propertyName is not found.
297 *
298 * @param properties properties to be looked up
299 * @param propertyName the name of the property to look up
300 * @return value when the propertyName is defined or return null
301 */
302 private static Integer getIntegerProperty(Dictionary<?, ?> properties,
303 String propertyName) {
304 Integer value = null;
305 try {
306 String s = (String) properties.get(propertyName);
307 value = isNullOrEmpty(s) ? value : Integer.parseInt(s.trim());
308 } catch (NumberFormatException e) {
309 value = null;
310 }
311 return value;
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900312 }
313
314 /**
315 * Check property name is defined and set to true.
316 *
317 * @param properties properties to be looked up
318 * @param propertyName the name of the property to look up
319 * @return true when the propertyName is defined and set to true
320 */
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100321 private static boolean isPropertyEnabled(Dictionary<?, ?> properties,
322 String propertyName) {
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900323 boolean enabled = false;
324 try {
325 String flag = (String) properties.get(propertyName);
326 if (flag != null) {
Ayaka Koshibe8851ed92015-01-22 12:07:24 -0800327 enabled = flag.trim().equals("true");
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900328 }
329 } catch (ClassCastException e) {
330 // No propertyName defined.
331 enabled = false;
332 }
333 return enabled;
tomc16656f2014-10-15 18:30:31 -0700334 }
tomc370ebd2014-09-16 01:25:21 -0700335
336 /**
337 * Packet processor responsible for forwarding packets along their paths.
338 */
339 private class ReactivePacketProcessor implements PacketProcessor {
340
341 @Override
342 public void process(PacketContext context) {
tomdc95b8a2014-09-17 08:07:26 -0700343 // Stop processing if the packet has been handled, since we
344 // can't do any more to it.
Thomas Vachuskabd7f4b32014-12-04 20:54:55 -0800345 if (context.isHandled()) {
alshabib7b2748f2014-09-16 20:21:11 -0700346 return;
347 }
tomdc95b8a2014-09-17 08:07:26 -0700348
tomc370ebd2014-09-16 01:25:21 -0700349 InboundPacket pkt = context.inPacket();
tom642b2262014-09-17 13:52:55 -0700350 Ethernet ethPkt = pkt.parsed();
alshabib6eb438a2014-10-01 16:39:37 -0700351
Jonathan Harte8600eb2015-01-12 10:30:45 -0800352 if (ethPkt == null) {
353 return;
354 }
355
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900356 // Bail if this is deemed to be a control packet.
357 if (isControlPacket(ethPkt)) {
358 return;
359 }
360
361 // Skip IPv6 multicast packet when IPv6 forward is disabled.
362 if (!ipv6Forwarding && isIpv6Multicast(ethPkt)) {
Thomas Vachuska01a6ec02014-11-05 09:54:09 -0800363 return;
364 }
365
tom642b2262014-09-17 13:52:55 -0700366 HostId id = HostId.hostId(ethPkt.getDestinationMAC());
tomc370ebd2014-09-16 01:25:21 -0700367
Thomas Vachuskae1bcb0b2014-10-27 17:45:10 -0700368 // Do not process link-local addresses in any way.
369 if (id.mac().isLinkLocal()) {
370 return;
371 }
372
tomc370ebd2014-09-16 01:25:21 -0700373 // Do we know who this is for? If not, flood and bail.
374 Host dst = hostService.getHost(id);
375 if (dst == null) {
376 flood(context);
377 return;
378 }
379
380 // Are we on an edge switch that our destination is on? If so,
381 // simply forward out to the destination and bail.
382 if (pkt.receivedFrom().deviceId().equals(dst.location().deviceId())) {
alshabib6eb438a2014-10-01 16:39:37 -0700383 if (!context.inPacket().receivedFrom().port().equals(dst.location().port())) {
384 installRule(context, dst.location().port());
385 }
tomc370ebd2014-09-16 01:25:21 -0700386 return;
387 }
388
389 // Otherwise, get a set of paths that lead from here to the
390 // destination edge switch.
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100391 Set<Path> paths =
392 topologyService.getPaths(topologyService.currentTopology(),
393 pkt.receivedFrom().deviceId(),
394 dst.location().deviceId());
tomc370ebd2014-09-16 01:25:21 -0700395 if (paths.isEmpty()) {
396 // If there are no paths, flood and bail.
397 flood(context);
398 return;
399 }
400
401 // Otherwise, pick a path that does not lead back to where we
402 // came from; if no such path, flood and bail.
403 Path path = pickForwardPath(paths, pkt.receivedFrom().port());
404 if (path == null) {
tom642b2262014-09-17 13:52:55 -0700405 log.warn("Doh... don't know where to go... {} -> {} received on {}",
tomc16656f2014-10-15 18:30:31 -0700406 ethPkt.getSourceMAC(), ethPkt.getDestinationMAC(),
407 pkt.receivedFrom());
tomc370ebd2014-09-16 01:25:21 -0700408 flood(context);
409 return;
410 }
411
412 // Otherwise forward and be done with it.
alshabib7b2748f2014-09-16 20:21:11 -0700413 installRule(context, path.src().port());
tomc370ebd2014-09-16 01:25:21 -0700414 }
Thomas Vachuska01a6ec02014-11-05 09:54:09 -0800415
416 }
417
418 // Indicates whether this is a control packet, e.g. LLDP, BDDP
419 private boolean isControlPacket(Ethernet eth) {
420 short type = eth.getEtherType();
421 return type == Ethernet.TYPE_LLDP || type == Ethernet.TYPE_BSN;
tomc370ebd2014-09-16 01:25:21 -0700422 }
423
Thomas Vachuska5dd52f72014-11-28 19:27:45 -0800424 // Indicated whether this is an IPv6 multicast packet.
425 private boolean isIpv6Multicast(Ethernet eth) {
426 return eth.getEtherType() == Ethernet.TYPE_IPV6 && eth.isMulticast();
427 }
428
tomc370ebd2014-09-16 01:25:21 -0700429 // Selects a path from the given set that does not lead back to the
430 // specified port.
431 private Path pickForwardPath(Set<Path> paths, PortNumber notToPort) {
432 for (Path path : paths) {
433 if (!path.src().port().equals(notToPort)) {
434 return path;
435 }
436 }
437 return null;
438 }
439
tom642b2262014-09-17 13:52:55 -0700440 // Floods the specified packet if permissible.
tomc370ebd2014-09-16 01:25:21 -0700441 private void flood(PacketContext context) {
tomdc95b8a2014-09-17 08:07:26 -0700442 if (topologyService.isBroadcastPoint(topologyService.currentTopology(),
tomc16656f2014-10-15 18:30:31 -0700443 context.inPacket().receivedFrom())) {
tom642b2262014-09-17 13:52:55 -0700444 packetOut(context, PortNumber.FLOOD);
tomc370ebd2014-09-16 01:25:21 -0700445 } else {
446 context.block();
447 }
448 }
449
tom642b2262014-09-17 13:52:55 -0700450 // Sends a packet out the specified port.
451 private void packetOut(PacketContext context, PortNumber portNumber) {
alshabib010c31d2014-09-26 10:01:12 -0700452 context.treatmentBuilder().setOutput(portNumber);
alshabib7b2748f2014-09-16 20:21:11 -0700453 context.send();
454 }
455
456 // Install a rule forwarding the packet to the specified port.
457 private void installRule(PacketContext context, PortNumber portNumber) {
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100458 //
459 // We don't support (yet) buffer IDs in the Flow Service so
460 // packet out first.
461 //
462 Ethernet inPkt = context.inPacket().parsed();
463 TrafficSelector.Builder builder = DefaultTrafficSelector.builder();
464
465 // If PacketOutOnly or ARP packet than forward directly to output port
466 if (packetOutOnly || inPkt.getEtherType() == Ethernet.TYPE_ARP) {
467 packetOut(context, portNumber);
468 return;
469 }
470
471 //
472 // If matchDstMacOnly
473 // Create flows matching dstMac only
474 // Else
475 // Create flows with default matching and include configured fields
476 //
477 if (matchDstMacOnly) {
478 builder.matchEthDst(inPkt.getDestinationMAC());
479 } else {
480 builder.matchInPort(context.inPacket().receivedFrom().port())
Thomas Vachuskabd7f4b32014-12-04 20:54:55 -0800481 .matchEthSrc(inPkt.getSourceMAC())
482 .matchEthDst(inPkt.getDestinationMAC())
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100483 .matchEthType(inPkt.getEtherType());
alshabib7b2748f2014-09-16 20:21:11 -0700484
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100485 // If configured Match Vlan ID
486 if (matchVlanId && inPkt.getVlanID() != Ethernet.VLAN_UNTAGGED) {
487 builder.matchVlanId(VlanId.vlanId(inPkt.getVlanID()));
488 }
alshabib7b2748f2014-09-16 20:21:11 -0700489
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100490 //
491 // If configured and EtherType is IPv4 - Match IPv4 and
492 // TCP/UDP/ICMP fields
493 //
494 if (matchIpv4Address && inPkt.getEtherType() == Ethernet.TYPE_IPV4) {
495 IPv4 ipv4Packet = (IPv4) inPkt.getPayload();
496 byte ipv4Protocol = ipv4Packet.getProtocol();
497 Ip4Prefix matchIp4SrcPrefix =
498 Ip4Prefix.valueOf(ipv4Packet.getSourceAddress(),
499 Ip4Prefix.MAX_MASK_LENGTH);
500 Ip4Prefix matchIp4DstPrefix =
501 Ip4Prefix.valueOf(ipv4Packet.getDestinationAddress(),
502 Ip4Prefix.MAX_MASK_LENGTH);
503 builder.matchIPSrc(matchIp4SrcPrefix)
504 .matchIPDst(matchIp4DstPrefix)
505 .matchIPProtocol(ipv4Protocol);
alshabib6eb438a2014-10-01 16:39:37 -0700506
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100507 if (matchIpv4Dscp) {
508 int dscp = ipv4Packet.getDiffServ() >>> 2;
509 int ecn = ipv4Packet.getDiffServ() % 4;
510 builder.matchIPDscp((byte) (dscp))
511 .matchIPEcn((byte) (ecn));
512 }
513
514 if (matchTcpUdpPorts && ipv4Protocol == IPv4.PROTOCOL_TCP) {
515 TCP tcpPacket = (TCP) ipv4Packet.getPayload();
516 builder.matchTcpSrc(tcpPacket.getSourcePort())
517 .matchTcpDst(tcpPacket.getDestinationPort());
518 }
519 if (matchTcpUdpPorts && ipv4Protocol == IPv4.PROTOCOL_UDP) {
520 UDP udpPacket = (UDP) ipv4Packet.getPayload();
521 builder.matchUdpSrc(udpPacket.getSourcePort())
522 .matchUdpDst(udpPacket.getDestinationPort());
523 }
524 if (matchIcmpFields && ipv4Protocol == IPv4.PROTOCOL_ICMP) {
525 ICMP icmpPacket = (ICMP) ipv4Packet.getPayload();
526 builder.matchIcmpType(icmpPacket.getIcmpType())
527 .matchIcmpCode(icmpPacket.getIcmpCode());
528 }
529 }
530
531 //
532 // If configured and EtherType is IPv6 - Match IPv6 and
533 // TCP/UDP/ICMP fields
534 //
535 if (matchIpv6Address && inPkt.getEtherType() == Ethernet.TYPE_IPV6) {
536 IPv6 ipv6Packet = (IPv6) inPkt.getPayload();
537 byte ipv6NextHeader = ipv6Packet.getNextHeader();
538 Ip6Prefix matchIp6SrcPrefix =
539 Ip6Prefix.valueOf(ipv6Packet.getSourceAddress(),
540 Ip6Prefix.MAX_MASK_LENGTH);
541 Ip6Prefix matchIp6DstPrefix =
542 Ip6Prefix.valueOf(ipv6Packet.getDestinationAddress(),
543 Ip6Prefix.MAX_MASK_LENGTH);
544 builder.matchIPv6Src(matchIp6SrcPrefix)
545 .matchIPv6Dst(matchIp6DstPrefix)
546 .matchIPProtocol(ipv6NextHeader);
547
548 if (matchIpv6FlowLabel) {
549 builder.matchIPv6FlowLabel(ipv6Packet.getFlowLabel());
550 }
551
552 if (matchTcpUdpPorts && ipv6NextHeader == IPv6.PROTOCOL_TCP) {
553 TCP tcpPacket = (TCP) ipv6Packet.getPayload();
554 builder.matchTcpSrc(tcpPacket.getSourcePort())
555 .matchTcpDst(tcpPacket.getDestinationPort());
556 }
557 if (matchTcpUdpPorts && ipv6NextHeader == IPv6.PROTOCOL_UDP) {
558 UDP udpPacket = (UDP) ipv6Packet.getPayload();
559 builder.matchUdpSrc(udpPacket.getSourcePort())
560 .matchUdpDst(udpPacket.getDestinationPort());
561 }
562 if (matchIcmpFields && ipv6NextHeader == IPv6.PROTOCOL_ICMP6) {
563 ICMP6 icmp6Packet = (ICMP6) ipv6Packet.getPayload();
564 builder.matchIcmpv6Type(icmp6Packet.getIcmpType())
565 .matchIcmpv6Code(icmp6Packet.getIcmpCode());
566 }
567 }
568 }
569 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
570 treat.setOutput(portNumber);
571
572 FlowRule f =
573 new DefaultFlowRule(context.inPacket().receivedFrom().deviceId(),
574 builder.build(), treat.build(), flowPriority,
575 appId, flowTimeout, false);
576
577 flowRuleService.applyFlowRules(f);
578
579 //
580 // If packetOutOfppTable
581 // Send packet back to the OpenFlow pipeline to match installed flow
582 // Else
583 // Send packet direction on the appropriate port
584 //
585 if (packetOutOfppTable) {
586 packetOut(context, PortNumber.TABLE);
587 } else {
588 packetOut(context, portNumber);
Thomas Vachuskabd7f4b32014-12-04 20:54:55 -0800589 }
tomc370ebd2014-09-16 01:25:21 -0700590 }
alshabib030111e2014-09-15 15:56:42 -0700591}