blob: f28f2a57d49ca4d52f42d21805a72501bac7097f [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;
Thomas Vachuska6519e6f2015-03-11 02:29:31 -070041import org.onosproject.cfg.ComponentConfigService;
Brian O'Connorabafb502014-12-02 22:26:20 -080042import org.onosproject.core.ApplicationId;
43import org.onosproject.core.CoreService;
44import org.onosproject.net.Host;
45import org.onosproject.net.HostId;
46import org.onosproject.net.Path;
47import org.onosproject.net.PortNumber;
48import org.onosproject.net.flow.DefaultFlowRule;
49import org.onosproject.net.flow.DefaultTrafficSelector;
50import org.onosproject.net.flow.DefaultTrafficTreatment;
51import org.onosproject.net.flow.FlowRule;
52import org.onosproject.net.flow.FlowRuleService;
53import org.onosproject.net.flow.TrafficSelector;
54import org.onosproject.net.flow.TrafficTreatment;
55import org.onosproject.net.host.HostService;
56import org.onosproject.net.packet.InboundPacket;
57import org.onosproject.net.packet.PacketContext;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080058import org.onosproject.net.packet.PacketPriority;
Brian O'Connorabafb502014-12-02 22:26:20 -080059import org.onosproject.net.packet.PacketProcessor;
60import org.onosproject.net.packet.PacketService;
61import org.onosproject.net.topology.TopologyService;
tomc16656f2014-10-15 18:30:31 -070062import org.osgi.service.component.ComponentContext;
tomc370ebd2014-09-16 01:25:21 -070063import org.slf4j.Logger;
alshabib030111e2014-09-15 15:56:42 -070064
tomc370ebd2014-09-16 01:25:21 -070065/**
66 * Sample reactive forwarding application.
67 */
68@Component(immediate = true)
alshabib030111e2014-09-15 15:56:42 -070069public class ReactiveForwarding {
70
Dusan Pajin0d1d48f2015-02-20 16:05:11 +010071 private static final int DEFAULT_TIMEOUT = 10;
72 private static final int DEFAULT_PRIORITY = 10;
alshabibba5ac482014-10-02 17:15:20 -070073
tomc370ebd2014-09-16 01:25:21 -070074 private final Logger log = getLogger(getClass());
75
alshabib030111e2014-09-15 15:56:42 -070076 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected TopologyService topologyService;
78
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected PacketService packetService;
81
alshabib8aef1ad2014-09-15 17:47:31 -070082 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected HostService hostService;
84
alshabib7b2748f2014-09-16 20:21:11 -070085 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected FlowRuleService flowRuleService;
87
alshabib92c65ad2014-10-08 21:56:05 -070088 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected CoreService coreService;
90
Thomas Vachuska6519e6f2015-03-11 02:29:31 -070091 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected ComponentConfigService cfgService;
93
tomc370ebd2014-09-16 01:25:21 -070094 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
alshabib030111e2014-09-15 15:56:42 -070095
alshabiba68eb962014-09-24 20:34:13 -070096 private ApplicationId appId;
97
Thomas Vachuskabd7f4b32014-12-04 20:54:55 -080098 @Property(name = "packetOutOnly", boolValue = false,
99 label = "Enable packet-out only forwarding; default is false")
100 private boolean packetOutOnly = false;
tomc16656f2014-10-15 18:30:31 -0700101
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100102 @Property(name = "packetOutOfppTable", boolValue = false,
103 label = "Enable first packet forwarding using OFPP_TABLE port " +
104 "instead of PacketOut with actual port; default is false")
105 private boolean packetOutOfppTable = false;
106
107 @Property(name = "flowTimeout", intValue = DEFAULT_TIMEOUT,
108 label = "Configure Flow Timeout for installed flow rules; " +
109 "default is 10 sec")
110 private int flowTimeout = DEFAULT_TIMEOUT;
111
112 @Property(name = "flowPriority", intValue = DEFAULT_PRIORITY,
113 label = "Configure Flow Priority for installed flow rules; " +
114 "default is 10")
115 private int flowPriority = DEFAULT_PRIORITY;
116
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900117 @Property(name = "ipv6Forwarding", boolValue = false,
118 label = "Enable IPv6 forwarding; default is false")
119 private boolean ipv6Forwarding = false;
120
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100121 @Property(name = "matchDstMacOnly", boolValue = false,
122 label = "Enable matching Dst Mac Only; default is false")
123 private boolean matchDstMacOnly = false;
124
125 @Property(name = "matchVlanId", boolValue = false,
126 label = "Enable matching Vlan ID; default is false")
127 private boolean matchVlanId = false;
128
129 @Property(name = "matchIpv4Address", boolValue = false,
130 label = "Enable matching IPv4 Addresses; default is false")
131 private boolean matchIpv4Address = false;
132
133 @Property(name = "matchIpv4Dscp", boolValue = false,
134 label = "Enable matching IPv4 DSCP and ECN; default is false")
135 private boolean matchIpv4Dscp = false;
136
137 @Property(name = "matchIpv6Address", boolValue = false,
138 label = "Enable matching IPv6 Addresses; default is false")
139 private boolean matchIpv6Address = false;
140
141 @Property(name = "matchIpv6FlowLabel", boolValue = false,
142 label = "Enable matching IPv6 FlowLabel; default is false")
143 private boolean matchIpv6FlowLabel = false;
144
145 @Property(name = "matchTcpUdpPorts", boolValue = false,
146 label = "Enable matching TCP/UDP ports; default is false")
147 private boolean matchTcpUdpPorts = false;
148
149 @Property(name = "matchIcmpFields", boolValue = false,
150 label = "Enable matching ICMPv4 and ICMPv6 fields; " +
151 "default is false")
152 private boolean matchIcmpFields = false;
153
154
alshabib030111e2014-09-15 15:56:42 -0700155 @Activate
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900156 public void activate(ComponentContext context) {
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700157 cfgService.registerProperties(getClass());
Brian O'Connorabafb502014-12-02 22:26:20 -0800158 appId = coreService.registerApplication("org.onosproject.fwd");
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800159
alshabibc274c902014-10-03 14:58:27 -0700160 packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 2);
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900161 readComponentConfiguration(context);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800162
163 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
164 selector.matchEthType(Ethernet.TYPE_IPV4);
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100165 packetService.requestPackets(selector.build(), PacketPriority.REACTIVE,
166 appId);
167 selector.matchEthType(Ethernet.TYPE_ARP);
168 packetService.requestPackets(selector.build(), PacketPriority.REACTIVE,
169 appId);
170
171 if (ipv6Forwarding) {
172 selector.matchEthType(Ethernet.TYPE_IPV6);
173 packetService.requestPackets(selector.build(),
174 PacketPriority.REACTIVE, appId);
175 }
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800176
alshabiba68eb962014-09-24 20:34:13 -0700177 log.info("Started with Application ID {}", appId.id());
alshabib030111e2014-09-15 15:56:42 -0700178 }
179
180 @Deactivate
181 public void deactivate() {
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700182 cfgService.unregisterProperties(getClass(), false);
alshabiba68eb962014-09-24 20:34:13 -0700183 flowRuleService.removeFlowRulesById(appId);
alshabib030111e2014-09-15 15:56:42 -0700184 packetService.removeProcessor(processor);
185 processor = null;
tomc370ebd2014-09-16 01:25:21 -0700186 log.info("Stopped");
alshabib030111e2014-09-15 15:56:42 -0700187 }
tomc370ebd2014-09-16 01:25:21 -0700188
tomc16656f2014-10-15 18:30:31 -0700189 @Modified
190 public void modified(ComponentContext context) {
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900191 readComponentConfiguration(context);
192 }
193
194 /**
195 * Extracts properties from the component configuration context.
196 *
197 * @param context the component context
198 */
199 private void readComponentConfiguration(ComponentContext context) {
200 Dictionary<?, ?> properties = context.getProperties();
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100201 boolean packetOutOnlyEnabled =
202 isPropertyEnabled(properties, "packetOutOnly");
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900203 if (packetOutOnly != packetOutOnlyEnabled) {
204 packetOutOnly = packetOutOnlyEnabled;
205 log.info("Configured. Packet-out only forwarding is {}",
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100206 packetOutOnly ? "enabled" : "disabled");
tomc16656f2014-10-15 18:30:31 -0700207 }
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100208 boolean packetOutOfppTableEnabled =
209 isPropertyEnabled(properties, "packetOutOfppTable");
210 if (packetOutOfppTable != packetOutOfppTableEnabled) {
211 packetOutOfppTable = packetOutOfppTableEnabled;
212 log.info("Configured. Forwarding using OFPP_TABLE port is {}",
213 packetOutOfppTable ? "enabled" : "disabled");
214 }
215 boolean ipv6ForwardingEnabled =
216 isPropertyEnabled(properties, "ipv6Forwarding");
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900217 if (ipv6Forwarding != ipv6ForwardingEnabled) {
218 ipv6Forwarding = ipv6ForwardingEnabled;
219 log.info("Configured. IPv6 forwarding is {}",
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100220 ipv6Forwarding ? "enabled" : "disabled");
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900221 }
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100222 boolean matchDstMacOnlyEnabled =
223 isPropertyEnabled(properties, "matchDstMacOnly");
224 if (matchDstMacOnly != matchDstMacOnlyEnabled) {
225 matchDstMacOnly = matchDstMacOnlyEnabled;
226 log.info("Configured. Match Dst MAC Only is {}",
227 matchDstMacOnly ? "enabled" : "disabled");
228 }
229 boolean matchVlanIdEnabled =
230 isPropertyEnabled(properties, "matchVlanId");
231 if (matchVlanId != matchVlanIdEnabled) {
232 matchVlanId = matchVlanIdEnabled;
233 log.info("Configured. Matching Vlan ID is {}",
234 matchVlanId ? "enabled" : "disabled");
235 }
236 boolean matchIpv4AddressEnabled =
237 isPropertyEnabled(properties, "matchIpv4Address");
238 if (matchIpv4Address != matchIpv4AddressEnabled) {
239 matchIpv4Address = matchIpv4AddressEnabled;
240 log.info("Configured. Matching IPv4 Addresses is {}",
241 matchIpv4Address ? "enabled" : "disabled");
242 }
243 boolean matchIpv4DscpEnabled =
244 isPropertyEnabled(properties, "matchIpv4Dscp");
245 if (matchIpv4Dscp != matchIpv4DscpEnabled) {
246 matchIpv4Dscp = matchIpv4DscpEnabled;
247 log.info("Configured. Matching IPv4 DSCP and ECN is {}",
248 matchIpv4Dscp ? "enabled" : "disabled");
249 }
250 boolean matchIpv6AddressEnabled =
251 isPropertyEnabled(properties, "matchIpv6Address");
252 if (matchIpv6Address != matchIpv6AddressEnabled) {
253 matchIpv6Address = matchIpv6AddressEnabled;
254 log.info("Configured. Matching IPv6 Addresses is {}",
255 matchIpv6Address ? "enabled" : "disabled");
256 }
257 boolean matchIpv6FlowLabelEnabled =
258 isPropertyEnabled(properties, "matchIpv6FlowLabel");
259 if (matchIpv6FlowLabel != matchIpv6FlowLabelEnabled) {
260 matchIpv6FlowLabel = matchIpv6FlowLabelEnabled;
261 log.info("Configured. Matching IPv6 FlowLabel is {}",
262 matchIpv6FlowLabel ? "enabled" : "disabled");
263 }
264 boolean matchTcpUdpPortsEnabled =
265 isPropertyEnabled(properties, "matchTcpUdpPorts");
266 if (matchTcpUdpPorts != matchTcpUdpPortsEnabled) {
267 matchTcpUdpPorts = matchTcpUdpPortsEnabled;
268 log.info("Configured. Matching TCP/UDP fields is {}",
269 matchTcpUdpPorts ? "enabled" : "disabled");
270 }
271 boolean matchIcmpFieldsEnabled =
272 isPropertyEnabled(properties, "matchIcmpFields");
273 if (matchIcmpFields != matchIcmpFieldsEnabled) {
274 matchIcmpFields = matchIcmpFieldsEnabled;
275 log.info("Configured. Matching ICMP (v4 and v6) fields is {}",
276 matchIcmpFields ? "enabled" : "disabled");
277 }
278 Integer flowTimeoutConfigured =
279 getIntegerProperty(properties, "flowTimeout");
280 if (flowTimeoutConfigured == null) {
281 log.info("Flow Timeout is not configured, default value is {}",
282 flowTimeout);
283 } else {
284 flowTimeout = flowTimeoutConfigured;
285 log.info("Configured. Flow Timeout is configured to {}",
286 flowTimeout, " seconds");
287 }
288 Integer flowPriorityConfigured =
289 getIntegerProperty(properties, "flowPriority");
290 if (flowPriorityConfigured == null) {
291 log.info("Flow Priority is not configured, default value is {}",
292 flowPriority);
293 } else {
294 flowPriority = flowPriorityConfigured;
295 log.info("Configured. Flow Priority is configured to {}",
296 flowPriority);
297 }
298 }
299
300 /**
301 * Get Integer property from the propertyName
302 * Return null if propertyName is not found.
303 *
304 * @param properties properties to be looked up
305 * @param propertyName the name of the property to look up
306 * @return value when the propertyName is defined or return null
307 */
308 private static Integer getIntegerProperty(Dictionary<?, ?> properties,
309 String propertyName) {
310 Integer value = null;
311 try {
312 String s = (String) properties.get(propertyName);
313 value = isNullOrEmpty(s) ? value : Integer.parseInt(s.trim());
Pavlin Radoslavovb9e50df2015-02-20 20:01:26 -0800314 } catch (NumberFormatException | ClassCastException e) {
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100315 value = null;
316 }
317 return value;
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900318 }
319
320 /**
321 * Check property name is defined and set to true.
322 *
323 * @param properties properties to be looked up
324 * @param propertyName the name of the property to look up
325 * @return true when the propertyName is defined and set to true
326 */
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100327 private static boolean isPropertyEnabled(Dictionary<?, ?> properties,
328 String propertyName) {
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900329 boolean enabled = false;
330 try {
331 String flag = (String) properties.get(propertyName);
332 if (flag != null) {
Ayaka Koshibe8851ed92015-01-22 12:07:24 -0800333 enabled = flag.trim().equals("true");
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900334 }
335 } catch (ClassCastException e) {
336 // No propertyName defined.
337 enabled = false;
338 }
339 return enabled;
tomc16656f2014-10-15 18:30:31 -0700340 }
tomc370ebd2014-09-16 01:25:21 -0700341
342 /**
343 * Packet processor responsible for forwarding packets along their paths.
344 */
345 private class ReactivePacketProcessor implements PacketProcessor {
346
347 @Override
348 public void process(PacketContext context) {
tomdc95b8a2014-09-17 08:07:26 -0700349 // Stop processing if the packet has been handled, since we
350 // can't do any more to it.
Thomas Vachuskabd7f4b32014-12-04 20:54:55 -0800351 if (context.isHandled()) {
alshabib7b2748f2014-09-16 20:21:11 -0700352 return;
353 }
tomdc95b8a2014-09-17 08:07:26 -0700354
tomc370ebd2014-09-16 01:25:21 -0700355 InboundPacket pkt = context.inPacket();
tom642b2262014-09-17 13:52:55 -0700356 Ethernet ethPkt = pkt.parsed();
alshabib6eb438a2014-10-01 16:39:37 -0700357
Jonathan Harte8600eb2015-01-12 10:30:45 -0800358 if (ethPkt == null) {
359 return;
360 }
361
Kunihiro Ishigurod37c9ca2014-12-31 16:05:40 +0900362 // Bail if this is deemed to be a control packet.
363 if (isControlPacket(ethPkt)) {
364 return;
365 }
366
367 // Skip IPv6 multicast packet when IPv6 forward is disabled.
368 if (!ipv6Forwarding && isIpv6Multicast(ethPkt)) {
Thomas Vachuska01a6ec02014-11-05 09:54:09 -0800369 return;
370 }
371
tom642b2262014-09-17 13:52:55 -0700372 HostId id = HostId.hostId(ethPkt.getDestinationMAC());
tomc370ebd2014-09-16 01:25:21 -0700373
Thomas Vachuskae1bcb0b2014-10-27 17:45:10 -0700374 // Do not process link-local addresses in any way.
375 if (id.mac().isLinkLocal()) {
376 return;
377 }
378
tomc370ebd2014-09-16 01:25:21 -0700379 // Do we know who this is for? If not, flood and bail.
380 Host dst = hostService.getHost(id);
381 if (dst == null) {
382 flood(context);
383 return;
384 }
385
386 // Are we on an edge switch that our destination is on? If so,
387 // simply forward out to the destination and bail.
388 if (pkt.receivedFrom().deviceId().equals(dst.location().deviceId())) {
alshabib6eb438a2014-10-01 16:39:37 -0700389 if (!context.inPacket().receivedFrom().port().equals(dst.location().port())) {
390 installRule(context, dst.location().port());
391 }
tomc370ebd2014-09-16 01:25:21 -0700392 return;
393 }
394
395 // Otherwise, get a set of paths that lead from here to the
396 // destination edge switch.
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100397 Set<Path> paths =
398 topologyService.getPaths(topologyService.currentTopology(),
399 pkt.receivedFrom().deviceId(),
400 dst.location().deviceId());
tomc370ebd2014-09-16 01:25:21 -0700401 if (paths.isEmpty()) {
402 // If there are no paths, flood and bail.
403 flood(context);
404 return;
405 }
406
407 // Otherwise, pick a path that does not lead back to where we
408 // came from; if no such path, flood and bail.
409 Path path = pickForwardPath(paths, pkt.receivedFrom().port());
410 if (path == null) {
tom642b2262014-09-17 13:52:55 -0700411 log.warn("Doh... don't know where to go... {} -> {} received on {}",
tomc16656f2014-10-15 18:30:31 -0700412 ethPkt.getSourceMAC(), ethPkt.getDestinationMAC(),
413 pkt.receivedFrom());
tomc370ebd2014-09-16 01:25:21 -0700414 flood(context);
415 return;
416 }
417
418 // Otherwise forward and be done with it.
alshabib7b2748f2014-09-16 20:21:11 -0700419 installRule(context, path.src().port());
tomc370ebd2014-09-16 01:25:21 -0700420 }
Thomas Vachuska01a6ec02014-11-05 09:54:09 -0800421
422 }
423
424 // Indicates whether this is a control packet, e.g. LLDP, BDDP
425 private boolean isControlPacket(Ethernet eth) {
426 short type = eth.getEtherType();
427 return type == Ethernet.TYPE_LLDP || type == Ethernet.TYPE_BSN;
tomc370ebd2014-09-16 01:25:21 -0700428 }
429
Thomas Vachuska5dd52f72014-11-28 19:27:45 -0800430 // Indicated whether this is an IPv6 multicast packet.
431 private boolean isIpv6Multicast(Ethernet eth) {
432 return eth.getEtherType() == Ethernet.TYPE_IPV6 && eth.isMulticast();
433 }
434
tomc370ebd2014-09-16 01:25:21 -0700435 // Selects a path from the given set that does not lead back to the
436 // specified port.
437 private Path pickForwardPath(Set<Path> paths, PortNumber notToPort) {
438 for (Path path : paths) {
439 if (!path.src().port().equals(notToPort)) {
440 return path;
441 }
442 }
443 return null;
444 }
445
tom642b2262014-09-17 13:52:55 -0700446 // Floods the specified packet if permissible.
tomc370ebd2014-09-16 01:25:21 -0700447 private void flood(PacketContext context) {
tomdc95b8a2014-09-17 08:07:26 -0700448 if (topologyService.isBroadcastPoint(topologyService.currentTopology(),
tomc16656f2014-10-15 18:30:31 -0700449 context.inPacket().receivedFrom())) {
tom642b2262014-09-17 13:52:55 -0700450 packetOut(context, PortNumber.FLOOD);
tomc370ebd2014-09-16 01:25:21 -0700451 } else {
452 context.block();
453 }
454 }
455
tom642b2262014-09-17 13:52:55 -0700456 // Sends a packet out the specified port.
457 private void packetOut(PacketContext context, PortNumber portNumber) {
alshabib010c31d2014-09-26 10:01:12 -0700458 context.treatmentBuilder().setOutput(portNumber);
alshabib7b2748f2014-09-16 20:21:11 -0700459 context.send();
460 }
461
462 // Install a rule forwarding the packet to the specified port.
463 private void installRule(PacketContext context, PortNumber portNumber) {
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100464 //
465 // We don't support (yet) buffer IDs in the Flow Service so
466 // packet out first.
467 //
468 Ethernet inPkt = context.inPacket().parsed();
469 TrafficSelector.Builder builder = DefaultTrafficSelector.builder();
470
471 // If PacketOutOnly or ARP packet than forward directly to output port
472 if (packetOutOnly || inPkt.getEtherType() == Ethernet.TYPE_ARP) {
473 packetOut(context, portNumber);
474 return;
475 }
476
477 //
478 // If matchDstMacOnly
479 // Create flows matching dstMac only
480 // Else
481 // Create flows with default matching and include configured fields
482 //
483 if (matchDstMacOnly) {
484 builder.matchEthDst(inPkt.getDestinationMAC());
485 } else {
486 builder.matchInPort(context.inPacket().receivedFrom().port())
Thomas Vachuskabd7f4b32014-12-04 20:54:55 -0800487 .matchEthSrc(inPkt.getSourceMAC())
488 .matchEthDst(inPkt.getDestinationMAC())
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100489 .matchEthType(inPkt.getEtherType());
alshabib7b2748f2014-09-16 20:21:11 -0700490
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100491 // If configured Match Vlan ID
492 if (matchVlanId && inPkt.getVlanID() != Ethernet.VLAN_UNTAGGED) {
493 builder.matchVlanId(VlanId.vlanId(inPkt.getVlanID()));
494 }
alshabib7b2748f2014-09-16 20:21:11 -0700495
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100496 //
497 // If configured and EtherType is IPv4 - Match IPv4 and
498 // TCP/UDP/ICMP fields
499 //
500 if (matchIpv4Address && inPkt.getEtherType() == Ethernet.TYPE_IPV4) {
501 IPv4 ipv4Packet = (IPv4) inPkt.getPayload();
502 byte ipv4Protocol = ipv4Packet.getProtocol();
503 Ip4Prefix matchIp4SrcPrefix =
504 Ip4Prefix.valueOf(ipv4Packet.getSourceAddress(),
505 Ip4Prefix.MAX_MASK_LENGTH);
506 Ip4Prefix matchIp4DstPrefix =
507 Ip4Prefix.valueOf(ipv4Packet.getDestinationAddress(),
508 Ip4Prefix.MAX_MASK_LENGTH);
509 builder.matchIPSrc(matchIp4SrcPrefix)
510 .matchIPDst(matchIp4DstPrefix)
511 .matchIPProtocol(ipv4Protocol);
alshabib6eb438a2014-10-01 16:39:37 -0700512
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100513 if (matchIpv4Dscp) {
Pavlin Radoslavovbf23c552015-02-20 14:20:30 -0800514 byte dscp = ipv4Packet.getDscp();
515 byte ecn = ipv4Packet.getEcn();
516 builder.matchIPDscp(dscp).matchIPEcn(ecn);
Dusan Pajin0d1d48f2015-02-20 16:05:11 +0100517 }
518
519 if (matchTcpUdpPorts && ipv4Protocol == IPv4.PROTOCOL_TCP) {
520 TCP tcpPacket = (TCP) ipv4Packet.getPayload();
521 builder.matchTcpSrc(tcpPacket.getSourcePort())
522 .matchTcpDst(tcpPacket.getDestinationPort());
523 }
524 if (matchTcpUdpPorts && ipv4Protocol == IPv4.PROTOCOL_UDP) {
525 UDP udpPacket = (UDP) ipv4Packet.getPayload();
526 builder.matchUdpSrc(udpPacket.getSourcePort())
527 .matchUdpDst(udpPacket.getDestinationPort());
528 }
529 if (matchIcmpFields && ipv4Protocol == IPv4.PROTOCOL_ICMP) {
530 ICMP icmpPacket = (ICMP) ipv4Packet.getPayload();
531 builder.matchIcmpType(icmpPacket.getIcmpType())
532 .matchIcmpCode(icmpPacket.getIcmpCode());
533 }
534 }
535
536 //
537 // If configured and EtherType is IPv6 - Match IPv6 and
538 // TCP/UDP/ICMP fields
539 //
540 if (matchIpv6Address && inPkt.getEtherType() == Ethernet.TYPE_IPV6) {
541 IPv6 ipv6Packet = (IPv6) inPkt.getPayload();
542 byte ipv6NextHeader = ipv6Packet.getNextHeader();
543 Ip6Prefix matchIp6SrcPrefix =
544 Ip6Prefix.valueOf(ipv6Packet.getSourceAddress(),
545 Ip6Prefix.MAX_MASK_LENGTH);
546 Ip6Prefix matchIp6DstPrefix =
547 Ip6Prefix.valueOf(ipv6Packet.getDestinationAddress(),
548 Ip6Prefix.MAX_MASK_LENGTH);
549 builder.matchIPv6Src(matchIp6SrcPrefix)
550 .matchIPv6Dst(matchIp6DstPrefix)
551 .matchIPProtocol(ipv6NextHeader);
552
553 if (matchIpv6FlowLabel) {
554 builder.matchIPv6FlowLabel(ipv6Packet.getFlowLabel());
555 }
556
557 if (matchTcpUdpPorts && ipv6NextHeader == IPv6.PROTOCOL_TCP) {
558 TCP tcpPacket = (TCP) ipv6Packet.getPayload();
559 builder.matchTcpSrc(tcpPacket.getSourcePort())
560 .matchTcpDst(tcpPacket.getDestinationPort());
561 }
562 if (matchTcpUdpPorts && ipv6NextHeader == IPv6.PROTOCOL_UDP) {
563 UDP udpPacket = (UDP) ipv6Packet.getPayload();
564 builder.matchUdpSrc(udpPacket.getSourcePort())
565 .matchUdpDst(udpPacket.getDestinationPort());
566 }
567 if (matchIcmpFields && ipv6NextHeader == IPv6.PROTOCOL_ICMP6) {
568 ICMP6 icmp6Packet = (ICMP6) ipv6Packet.getPayload();
569 builder.matchIcmpv6Type(icmp6Packet.getIcmpType())
570 .matchIcmpv6Code(icmp6Packet.getIcmpCode());
571 }
572 }
573 }
574 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
575 treat.setOutput(portNumber);
576
577 FlowRule f =
578 new DefaultFlowRule(context.inPacket().receivedFrom().deviceId(),
579 builder.build(), treat.build(), flowPriority,
580 appId, flowTimeout, false);
581
582 flowRuleService.applyFlowRules(f);
583
584 //
585 // If packetOutOfppTable
586 // Send packet back to the OpenFlow pipeline to match installed flow
587 // Else
588 // Send packet direction on the appropriate port
589 //
590 if (packetOutOfppTable) {
591 packetOut(context, PortNumber.TABLE);
592 } else {
593 packetOut(context, portNumber);
Thomas Vachuskabd7f4b32014-12-04 20:54:55 -0800594 }
tomc370ebd2014-09-16 01:25:21 -0700595 }
alshabib030111e2014-09-15 15:56:42 -0700596}