aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/apps/fwd/src/main/java/org/onosproject/fwd/ReactiveForwarding.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/apps/fwd/src/main/java/org/onosproject/fwd/ReactiveForwarding.java')
-rw-r--r--framework/src/onos/apps/fwd/src/main/java/org/onosproject/fwd/ReactiveForwarding.java844
1 files changed, 0 insertions, 844 deletions
diff --git a/framework/src/onos/apps/fwd/src/main/java/org/onosproject/fwd/ReactiveForwarding.java b/framework/src/onos/apps/fwd/src/main/java/org/onosproject/fwd/ReactiveForwarding.java
deleted file mode 100644
index 8540ba14..00000000
--- a/framework/src/onos/apps/fwd/src/main/java/org/onosproject/fwd/ReactiveForwarding.java
+++ /dev/null
@@ -1,844 +0,0 @@
-/*
- * Copyright 2014-2015 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.fwd;
-
-import com.google.common.collect.ImmutableSet;
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Deactivate;
-import org.apache.felix.scr.annotations.Modified;
-import org.apache.felix.scr.annotations.Property;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.ReferenceCardinality;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.ICMP;
-import org.onlab.packet.ICMP6;
-import org.onlab.packet.IPv4;
-import org.onlab.packet.IPv6;
-import org.onlab.packet.Ip4Prefix;
-import org.onlab.packet.Ip6Prefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.TCP;
-import org.onlab.packet.TpPort;
-import org.onlab.packet.UDP;
-import org.onlab.packet.VlanId;
-import org.onosproject.cfg.ComponentConfigService;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.core.CoreService;
-import org.onosproject.event.Event;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Host;
-import org.onosproject.net.HostId;
-import org.onosproject.net.Link;
-import org.onosproject.net.Path;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.flow.DefaultTrafficSelector;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.FlowEntry;
-import org.onosproject.net.flow.FlowRule;
-import org.onosproject.net.flow.FlowRuleService;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.flow.criteria.Criterion;
-import org.onosproject.net.flow.criteria.EthCriterion;
-import org.onosproject.net.flow.instructions.Instruction;
-import org.onosproject.net.flow.instructions.Instructions;
-import org.onosproject.net.flowobjective.DefaultForwardingObjective;
-import org.onosproject.net.flowobjective.FlowObjectiveService;
-import org.onosproject.net.flowobjective.ForwardingObjective;
-import org.onosproject.net.host.HostService;
-import org.onosproject.net.link.LinkEvent;
-import org.onosproject.net.packet.InboundPacket;
-import org.onosproject.net.packet.PacketContext;
-import org.onosproject.net.packet.PacketPriority;
-import org.onosproject.net.packet.PacketProcessor;
-import org.onosproject.net.packet.PacketService;
-import org.onosproject.net.topology.TopologyEvent;
-import org.onosproject.net.topology.TopologyListener;
-import org.onosproject.net.topology.TopologyService;
-import org.osgi.service.component.ComponentContext;
-import org.slf4j.Logger;
-
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-
-import static com.google.common.base.Strings.isNullOrEmpty;
-import static org.slf4j.LoggerFactory.getLogger;
-
-/**
- * Sample reactive forwarding application.
- */
-@Component(immediate = true)
-public class ReactiveForwarding {
-
- private static final int DEFAULT_TIMEOUT = 10;
- private static final int DEFAULT_PRIORITY = 10;
-
- private final Logger log = getLogger(getClass());
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected TopologyService topologyService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected PacketService packetService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected HostService hostService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected FlowRuleService flowRuleService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected FlowObjectiveService flowObjectiveService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected CoreService coreService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected ComponentConfigService cfgService;
-
- private ReactivePacketProcessor processor = new ReactivePacketProcessor();
-
- private ApplicationId appId;
-
- @Property(name = "packetOutOnly", boolValue = false,
- label = "Enable packet-out only forwarding; default is false")
- private boolean packetOutOnly = false;
-
- @Property(name = "packetOutOfppTable", boolValue = false,
- label = "Enable first packet forwarding using OFPP_TABLE port " +
- "instead of PacketOut with actual port; default is false")
- private boolean packetOutOfppTable = false;
-
- @Property(name = "flowTimeout", intValue = DEFAULT_TIMEOUT,
- label = "Configure Flow Timeout for installed flow rules; " +
- "default is 10 sec")
- private int flowTimeout = DEFAULT_TIMEOUT;
-
- @Property(name = "flowPriority", intValue = DEFAULT_PRIORITY,
- label = "Configure Flow Priority for installed flow rules; " +
- "default is 10")
- private int flowPriority = DEFAULT_PRIORITY;
-
- @Property(name = "ipv6Forwarding", boolValue = false,
- label = "Enable IPv6 forwarding; default is false")
- private boolean ipv6Forwarding = false;
-
- @Property(name = "matchDstMacOnly", boolValue = false,
- label = "Enable matching Dst Mac Only; default is false")
- private boolean matchDstMacOnly = false;
-
- @Property(name = "matchVlanId", boolValue = false,
- label = "Enable matching Vlan ID; default is false")
- private boolean matchVlanId = false;
-
- @Property(name = "matchIpv4Address", boolValue = false,
- label = "Enable matching IPv4 Addresses; default is false")
- private boolean matchIpv4Address = false;
-
- @Property(name = "matchIpv4Dscp", boolValue = false,
- label = "Enable matching IPv4 DSCP and ECN; default is false")
- private boolean matchIpv4Dscp = false;
-
- @Property(name = "matchIpv6Address", boolValue = false,
- label = "Enable matching IPv6 Addresses; default is false")
- private boolean matchIpv6Address = false;
-
- @Property(name = "matchIpv6FlowLabel", boolValue = false,
- label = "Enable matching IPv6 FlowLabel; default is false")
- private boolean matchIpv6FlowLabel = false;
-
- @Property(name = "matchTcpUdpPorts", boolValue = false,
- label = "Enable matching TCP/UDP ports; default is false")
- private boolean matchTcpUdpPorts = false;
-
- @Property(name = "matchIcmpFields", boolValue = false,
- label = "Enable matching ICMPv4 and ICMPv6 fields; " +
- "default is false")
- private boolean matchIcmpFields = false;
-
-
- @Property(name = "ignoreIPv4Multicast", boolValue = false,
- label = "Ignore (do not forward) IPv4 multicast packets; default is false")
- private boolean ignoreIpv4McastPackets = false;
-
- private final TopologyListener topologyListener = new InternalTopologyListener();
-
-
- @Activate
- public void activate(ComponentContext context) {
- cfgService.registerProperties(getClass());
- appId = coreService.registerApplication("org.onosproject.fwd");
-
- packetService.addProcessor(processor, PacketProcessor.director(2));
- topologyService.addListener(topologyListener);
- readComponentConfiguration(context);
- requestIntercepts();
-
- log.info("Started", appId.id());
- }
-
- @Deactivate
- public void deactivate() {
- cfgService.unregisterProperties(getClass(), false);
- withdrawIntercepts();
- flowRuleService.removeFlowRulesById(appId);
- packetService.removeProcessor(processor);
- topologyService.removeListener(topologyListener);
- processor = null;
- log.info("Stopped");
- }
-
- @Modified
- public void modified(ComponentContext context) {
- readComponentConfiguration(context);
- requestIntercepts();
- }
-
- /**
- * Request packet in via packet service.
- */
- private void requestIntercepts() {
- TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
- selector.matchEthType(Ethernet.TYPE_IPV4);
- packetService.requestPackets(selector.build(), PacketPriority.REACTIVE, appId);
- selector.matchEthType(Ethernet.TYPE_ARP);
- packetService.requestPackets(selector.build(), PacketPriority.REACTIVE, appId);
-
- selector.matchEthType(Ethernet.TYPE_IPV6);
- if (ipv6Forwarding) {
- packetService.requestPackets(selector.build(), PacketPriority.REACTIVE, appId);
- } else {
- packetService.cancelPackets(selector.build(), PacketPriority.REACTIVE, appId);
- }
- }
-
- /**
- * Cancel request for packet in via packet service.
- */
- private void withdrawIntercepts() {
- TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
- selector.matchEthType(Ethernet.TYPE_IPV4);
- packetService.cancelPackets(selector.build(), PacketPriority.REACTIVE, appId);
- selector.matchEthType(Ethernet.TYPE_ARP);
- packetService.cancelPackets(selector.build(), PacketPriority.REACTIVE, appId);
- selector.matchEthType(Ethernet.TYPE_IPV6);
- packetService.cancelPackets(selector.build(), PacketPriority.REACTIVE, appId);
- }
-
- /**
- * Extracts properties from the component configuration context.
- *
- * @param context the component context
- */
- private void readComponentConfiguration(ComponentContext context) {
- Dictionary<?, ?> properties = context.getProperties();
- boolean packetOutOnlyEnabled =
- isPropertyEnabled(properties, "packetOutOnly");
- if (packetOutOnly != packetOutOnlyEnabled) {
- packetOutOnly = packetOutOnlyEnabled;
- log.info("Configured. Packet-out only forwarding is {}",
- packetOutOnly ? "enabled" : "disabled");
- }
- boolean packetOutOfppTableEnabled =
- isPropertyEnabled(properties, "packetOutOfppTable");
- if (packetOutOfppTable != packetOutOfppTableEnabled) {
- packetOutOfppTable = packetOutOfppTableEnabled;
- log.info("Configured. Forwarding using OFPP_TABLE port is {}",
- packetOutOfppTable ? "enabled" : "disabled");
- }
- boolean ipv6ForwardingEnabled =
- isPropertyEnabled(properties, "ipv6Forwarding");
- if (ipv6Forwarding != ipv6ForwardingEnabled) {
- ipv6Forwarding = ipv6ForwardingEnabled;
- log.info("Configured. IPv6 forwarding is {}",
- ipv6Forwarding ? "enabled" : "disabled");
- }
- boolean matchDstMacOnlyEnabled =
- isPropertyEnabled(properties, "matchDstMacOnly");
- if (matchDstMacOnly != matchDstMacOnlyEnabled) {
- matchDstMacOnly = matchDstMacOnlyEnabled;
- log.info("Configured. Match Dst MAC Only is {}",
- matchDstMacOnly ? "enabled" : "disabled");
- }
- boolean matchVlanIdEnabled =
- isPropertyEnabled(properties, "matchVlanId");
- if (matchVlanId != matchVlanIdEnabled) {
- matchVlanId = matchVlanIdEnabled;
- log.info("Configured. Matching Vlan ID is {}",
- matchVlanId ? "enabled" : "disabled");
- }
- boolean matchIpv4AddressEnabled =
- isPropertyEnabled(properties, "matchIpv4Address");
- if (matchIpv4Address != matchIpv4AddressEnabled) {
- matchIpv4Address = matchIpv4AddressEnabled;
- log.info("Configured. Matching IPv4 Addresses is {}",
- matchIpv4Address ? "enabled" : "disabled");
- }
- boolean matchIpv4DscpEnabled =
- isPropertyEnabled(properties, "matchIpv4Dscp");
- if (matchIpv4Dscp != matchIpv4DscpEnabled) {
- matchIpv4Dscp = matchIpv4DscpEnabled;
- log.info("Configured. Matching IPv4 DSCP and ECN is {}",
- matchIpv4Dscp ? "enabled" : "disabled");
- }
- boolean matchIpv6AddressEnabled =
- isPropertyEnabled(properties, "matchIpv6Address");
- if (matchIpv6Address != matchIpv6AddressEnabled) {
- matchIpv6Address = matchIpv6AddressEnabled;
- log.info("Configured. Matching IPv6 Addresses is {}",
- matchIpv6Address ? "enabled" : "disabled");
- }
- boolean matchIpv6FlowLabelEnabled =
- isPropertyEnabled(properties, "matchIpv6FlowLabel");
- if (matchIpv6FlowLabel != matchIpv6FlowLabelEnabled) {
- matchIpv6FlowLabel = matchIpv6FlowLabelEnabled;
- log.info("Configured. Matching IPv6 FlowLabel is {}",
- matchIpv6FlowLabel ? "enabled" : "disabled");
- }
- boolean matchTcpUdpPortsEnabled =
- isPropertyEnabled(properties, "matchTcpUdpPorts");
- if (matchTcpUdpPorts != matchTcpUdpPortsEnabled) {
- matchTcpUdpPorts = matchTcpUdpPortsEnabled;
- log.info("Configured. Matching TCP/UDP fields is {}",
- matchTcpUdpPorts ? "enabled" : "disabled");
- }
- boolean matchIcmpFieldsEnabled =
- isPropertyEnabled(properties, "matchIcmpFields");
- if (matchIcmpFields != matchIcmpFieldsEnabled) {
- matchIcmpFields = matchIcmpFieldsEnabled;
- log.info("Configured. Matching ICMP (v4 and v6) fields is {}",
- matchIcmpFields ? "enabled" : "disabled");
- }
- Integer flowTimeoutConfigured =
- getIntegerProperty(properties, "flowTimeout");
- if (flowTimeoutConfigured == null) {
- log.info("Flow Timeout is not configured, default value is {}",
- flowTimeout);
- } else {
- flowTimeout = flowTimeoutConfigured;
- log.info("Configured. Flow Timeout is configured to {}",
- flowTimeout, " seconds");
- }
- Integer flowPriorityConfigured =
- getIntegerProperty(properties, "flowPriority");
- if (flowPriorityConfigured == null) {
- log.info("Flow Priority is not configured, default value is {}",
- flowPriority);
- } else {
- flowPriority = flowPriorityConfigured;
- log.info("Configured. Flow Priority is configured to {}",
- flowPriority);
- }
-
- boolean ignoreIpv4McastPacketsEnabled =
- isPropertyEnabled(properties, "ignoreIpv4McastPackets");
- if (ignoreIpv4McastPackets != ignoreIpv4McastPacketsEnabled) {
- ignoreIpv4McastPackets = ignoreIpv4McastPacketsEnabled;
- log.info("Configured. Ignore IPv4 multicast packets is {}",
- ignoreIpv4McastPackets ? "enabled" : "disabled");
- }
- }
-
- /**
- * Get Integer property from the propertyName
- * Return null if propertyName is not found.
- *
- * @param properties properties to be looked up
- * @param propertyName the name of the property to look up
- * @return value when the propertyName is defined or return null
- */
- private static Integer getIntegerProperty(Dictionary<?, ?> properties,
- String propertyName) {
- Integer value = null;
- try {
- String s = (String) properties.get(propertyName);
- value = isNullOrEmpty(s) ? value : Integer.parseInt(s.trim());
- } catch (NumberFormatException | ClassCastException e) {
- value = null;
- }
- return value;
- }
-
- /**
- * Check property name is defined and set to true.
- *
- * @param properties properties to be looked up
- * @param propertyName the name of the property to look up
- * @return true when the propertyName is defined and set to true
- */
- private static boolean isPropertyEnabled(Dictionary<?, ?> properties,
- String propertyName) {
- boolean enabled = false;
- try {
- String flag = (String) properties.get(propertyName);
- if (flag != null) {
- enabled = flag.trim().equals("true");
- }
- } catch (ClassCastException e) {
- // No propertyName defined.
- enabled = false;
- }
- return enabled;
- }
-
- /**
- * Packet processor responsible for forwarding packets along their paths.
- */
- private class ReactivePacketProcessor implements PacketProcessor {
-
- @Override
- public void process(PacketContext context) {
- // Stop processing if the packet has been handled, since we
- // can't do any more to it.
-
- if (context.isHandled()) {
- return;
- }
-
- InboundPacket pkt = context.inPacket();
- Ethernet ethPkt = pkt.parsed();
-
- if (ethPkt == null) {
- return;
- }
-
- // Bail if this is deemed to be a control packet.
- if (isControlPacket(ethPkt)) {
- return;
- }
-
- // Skip IPv6 multicast packet when IPv6 forward is disabled.
- if (!ipv6Forwarding && isIpv6Multicast(ethPkt)) {
- return;
- }
-
- HostId id = HostId.hostId(ethPkt.getDestinationMAC());
-
- // Do not process link-local addresses in any way.
- if (id.mac().isLinkLocal()) {
- return;
- }
-
- // Do not process IPv4 multicast packets, let mfwd handle them
- if (ignoreIpv4McastPackets && ethPkt.getEtherType() == Ethernet.TYPE_IPV4) {
- if (id.mac().isMulticast()) {
- return;
- }
- }
-
- // Do we know who this is for? If not, flood and bail.
- Host dst = hostService.getHost(id);
- if (dst == null) {
- flood(context);
- return;
- }
-
- // Are we on an edge switch that our destination is on? If so,
- // simply forward out to the destination and bail.
- if (pkt.receivedFrom().deviceId().equals(dst.location().deviceId())) {
- if (!context.inPacket().receivedFrom().port().equals(dst.location().port())) {
- installRule(context, dst.location().port());
- }
- return;
- }
-
- // Otherwise, get a set of paths that lead from here to the
- // destination edge switch.
- Set<Path> paths =
- topologyService.getPaths(topologyService.currentTopology(),
- pkt.receivedFrom().deviceId(),
- dst.location().deviceId());
- if (paths.isEmpty()) {
- // If there are no paths, flood and bail.
- flood(context);
- return;
- }
-
- // Otherwise, pick a path that does not lead back to where we
- // came from; if no such path, flood and bail.
- Path path = pickForwardPathIfPossible(paths, pkt.receivedFrom().port());
- if (path == null) {
- log.warn("Don't know where to go from here {} for {} -> {}",
- pkt.receivedFrom(), ethPkt.getSourceMAC(), ethPkt.getDestinationMAC());
- flood(context);
- return;
- }
-
- // Otherwise forward and be done with it.
- installRule(context, path.src().port());
- }
-
- }
-
- // Indicates whether this is a control packet, e.g. LLDP, BDDP
- private boolean isControlPacket(Ethernet eth) {
- short type = eth.getEtherType();
- return type == Ethernet.TYPE_LLDP || type == Ethernet.TYPE_BSN;
- }
-
- // Indicated whether this is an IPv6 multicast packet.
- private boolean isIpv6Multicast(Ethernet eth) {
- return eth.getEtherType() == Ethernet.TYPE_IPV6 && eth.isMulticast();
- }
-
- // Selects a path from the given set that does not lead back to the
- // specified port if possible.
- private Path pickForwardPathIfPossible(Set<Path> paths, PortNumber notToPort) {
- Path lastPath = null;
- for (Path path : paths) {
- lastPath = path;
- if (!path.src().port().equals(notToPort)) {
- return path;
- }
- }
- return lastPath;
- }
-
- // Floods the specified packet if permissible.
- private void flood(PacketContext context) {
- if (topologyService.isBroadcastPoint(topologyService.currentTopology(),
- context.inPacket().receivedFrom())) {
- packetOut(context, PortNumber.FLOOD);
- } else {
- context.block();
- }
- }
-
- // Sends a packet out the specified port.
- private void packetOut(PacketContext context, PortNumber portNumber) {
- context.treatmentBuilder().setOutput(portNumber);
- context.send();
- }
-
- // Install a rule forwarding the packet to the specified port.
- private void installRule(PacketContext context, PortNumber portNumber) {
- //
- // We don't support (yet) buffer IDs in the Flow Service so
- // packet out first.
- //
- Ethernet inPkt = context.inPacket().parsed();
- TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
-
- // If PacketOutOnly or ARP packet than forward directly to output port
- if (packetOutOnly || inPkt.getEtherType() == Ethernet.TYPE_ARP) {
- packetOut(context, portNumber);
- return;
- }
-
- //
- // If matchDstMacOnly
- // Create flows matching dstMac only
- // Else
- // Create flows with default matching and include configured fields
- //
- if (matchDstMacOnly) {
- selectorBuilder.matchEthDst(inPkt.getDestinationMAC());
- } else {
- selectorBuilder.matchInPort(context.inPacket().receivedFrom().port())
- .matchEthSrc(inPkt.getSourceMAC())
- .matchEthDst(inPkt.getDestinationMAC());
-
- // If configured Match Vlan ID
- if (matchVlanId && inPkt.getVlanID() != Ethernet.VLAN_UNTAGGED) {
- selectorBuilder.matchVlanId(VlanId.vlanId(inPkt.getVlanID()));
- }
-
- //
- // If configured and EtherType is IPv4 - Match IPv4 and
- // TCP/UDP/ICMP fields
- //
- if (matchIpv4Address && inPkt.getEtherType() == Ethernet.TYPE_IPV4) {
- IPv4 ipv4Packet = (IPv4) inPkt.getPayload();
- byte ipv4Protocol = ipv4Packet.getProtocol();
- Ip4Prefix matchIp4SrcPrefix =
- Ip4Prefix.valueOf(ipv4Packet.getSourceAddress(),
- Ip4Prefix.MAX_MASK_LENGTH);
- Ip4Prefix matchIp4DstPrefix =
- Ip4Prefix.valueOf(ipv4Packet.getDestinationAddress(),
- Ip4Prefix.MAX_MASK_LENGTH);
- selectorBuilder.matchEthType(Ethernet.TYPE_IPV4)
- .matchIPSrc(matchIp4SrcPrefix)
- .matchIPDst(matchIp4DstPrefix);
-
- if (matchIpv4Dscp) {
- byte dscp = ipv4Packet.getDscp();
- byte ecn = ipv4Packet.getEcn();
- selectorBuilder.matchIPDscp(dscp).matchIPEcn(ecn);
- }
-
- if (matchTcpUdpPorts && ipv4Protocol == IPv4.PROTOCOL_TCP) {
- TCP tcpPacket = (TCP) ipv4Packet.getPayload();
- selectorBuilder.matchIPProtocol(ipv4Protocol)
- .matchTcpSrc(TpPort.tpPort(tcpPacket.getSourcePort()))
- .matchTcpDst(TpPort.tpPort(tcpPacket.getDestinationPort()));
- }
- if (matchTcpUdpPorts && ipv4Protocol == IPv4.PROTOCOL_UDP) {
- UDP udpPacket = (UDP) ipv4Packet.getPayload();
- selectorBuilder.matchIPProtocol(ipv4Protocol)
- .matchUdpSrc(TpPort.tpPort(udpPacket.getSourcePort()))
- .matchUdpDst(TpPort.tpPort(udpPacket.getDestinationPort()));
- }
- if (matchIcmpFields && ipv4Protocol == IPv4.PROTOCOL_ICMP) {
- ICMP icmpPacket = (ICMP) ipv4Packet.getPayload();
- selectorBuilder.matchIPProtocol(ipv4Protocol)
- .matchIcmpType(icmpPacket.getIcmpType())
- .matchIcmpCode(icmpPacket.getIcmpCode());
- }
- }
-
- //
- // If configured and EtherType is IPv6 - Match IPv6 and
- // TCP/UDP/ICMP fields
- //
- if (matchIpv6Address && inPkt.getEtherType() == Ethernet.TYPE_IPV6) {
- IPv6 ipv6Packet = (IPv6) inPkt.getPayload();
- byte ipv6NextHeader = ipv6Packet.getNextHeader();
- Ip6Prefix matchIp6SrcPrefix =
- Ip6Prefix.valueOf(ipv6Packet.getSourceAddress(),
- Ip6Prefix.MAX_MASK_LENGTH);
- Ip6Prefix matchIp6DstPrefix =
- Ip6Prefix.valueOf(ipv6Packet.getDestinationAddress(),
- Ip6Prefix.MAX_MASK_LENGTH);
- selectorBuilder.matchEthType(Ethernet.TYPE_IPV6)
- .matchIPv6Src(matchIp6SrcPrefix)
- .matchIPv6Dst(matchIp6DstPrefix);
-
- if (matchIpv6FlowLabel) {
- selectorBuilder.matchIPv6FlowLabel(ipv6Packet.getFlowLabel());
- }
-
- if (matchTcpUdpPorts && ipv6NextHeader == IPv6.PROTOCOL_TCP) {
- TCP tcpPacket = (TCP) ipv6Packet.getPayload();
- selectorBuilder.matchIPProtocol(ipv6NextHeader)
- .matchTcpSrc(TpPort.tpPort(tcpPacket.getSourcePort()))
- .matchTcpDst(TpPort.tpPort(tcpPacket.getDestinationPort()));
- }
- if (matchTcpUdpPorts && ipv6NextHeader == IPv6.PROTOCOL_UDP) {
- UDP udpPacket = (UDP) ipv6Packet.getPayload();
- selectorBuilder.matchIPProtocol(ipv6NextHeader)
- .matchUdpSrc(TpPort.tpPort(udpPacket.getSourcePort()))
- .matchUdpDst(TpPort.tpPort(udpPacket.getDestinationPort()));
- }
- if (matchIcmpFields && ipv6NextHeader == IPv6.PROTOCOL_ICMP6) {
- ICMP6 icmp6Packet = (ICMP6) ipv6Packet.getPayload();
- selectorBuilder.matchIPProtocol(ipv6NextHeader)
- .matchIcmpv6Type(icmp6Packet.getIcmpType())
- .matchIcmpv6Code(icmp6Packet.getIcmpCode());
- }
- }
- }
- TrafficTreatment treatment = DefaultTrafficTreatment.builder()
- .setOutput(portNumber)
- .build();
-
- ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
- .withSelector(selectorBuilder.build())
- .withTreatment(treatment)
- .withPriority(flowPriority)
- .withFlag(ForwardingObjective.Flag.VERSATILE)
- .fromApp(appId)
- .makeTemporary(flowTimeout)
- .add();
-
- flowObjectiveService.forward(context.inPacket().receivedFrom().deviceId(),
- forwardingObjective);
-
- //
- // If packetOutOfppTable
- // Send packet back to the OpenFlow pipeline to match installed flow
- // Else
- // Send packet direction on the appropriate port
- //
- if (packetOutOfppTable) {
- packetOut(context, PortNumber.TABLE);
- } else {
- packetOut(context, portNumber);
- }
- }
-
- private class InternalTopologyListener implements TopologyListener {
- @Override
- public void event(TopologyEvent event) {
- List<Event> reasons = event.reasons();
- if (reasons != null) {
- reasons.forEach(re -> {
- if (re instanceof LinkEvent) {
- LinkEvent le = (LinkEvent) re;
- if (le.type() == LinkEvent.Type.LINK_REMOVED) {
- fixBlackhole(le.subject().src());
- }
- }
- });
- }
- }
- }
-
- private void fixBlackhole(ConnectPoint egress) {
- Set<FlowEntry> rules = getFlowRulesFrom(egress);
- Set<SrcDstPair> pairs = findSrcDstPairs(rules);
-
- Map<DeviceId, Set<Path>> srcPaths = new HashMap<>();
-
- for (SrcDstPair sd : pairs) {
- // get the edge deviceID for the src host
- Host srcHost = hostService.getHost(HostId.hostId(sd.src));
- Host dstHost = hostService.getHost(HostId.hostId(sd.dst));
- if (srcHost != null && dstHost != null) {
- DeviceId srcId = srcHost.location().deviceId();
- DeviceId dstId = dstHost.location().deviceId();
- log.trace("SRC ID is " + srcId + ", DST ID is " + dstId);
-
- cleanFlowRules(sd, egress.deviceId());
-
- Set<Path> shortestPaths = srcPaths.get(srcId);
- if (shortestPaths == null) {
- shortestPaths = topologyService.getPaths(topologyService.currentTopology(),
- egress.deviceId(), srcId);
- srcPaths.put(srcId, shortestPaths);
- }
- backTrackBadNodes(shortestPaths, dstId, sd);
- }
- }
- }
-
- // Backtracks from link down event to remove flows that lead to blackhole
- private void backTrackBadNodes(Set<Path> shortestPaths, DeviceId dstId, SrcDstPair sd) {
- for (Path p : shortestPaths) {
- List<Link> pathLinks = p.links();
- for (int i = 0; i < pathLinks.size(); i = i + 1) {
- Link curLink = pathLinks.get(i);
- DeviceId curDevice = curLink.src().deviceId();
-
- // skipping the first link because this link's src has already been pruned beforehand
- if (i != 0) {
- cleanFlowRules(sd, curDevice);
- }
-
- Set<Path> pathsFromCurDevice =
- topologyService.getPaths(topologyService.currentTopology(),
- curDevice, dstId);
- if (pickForwardPathIfPossible(pathsFromCurDevice, curLink.src().port()) != null) {
- break;
- } else {
- if (i + 1 == pathLinks.size()) {
- cleanFlowRules(sd, curLink.dst().deviceId());
- }
- }
- }
- }
- }
-
- // Removes flow rules off specified device with specific SrcDstPair
- private void cleanFlowRules(SrcDstPair pair, DeviceId id) {
- log.trace("Searching for flow rules to remove from: " + id);
- log.trace("Removing flows w/ SRC=" + pair.src + ", DST=" + pair.dst);
- for (FlowEntry r : flowRuleService.getFlowEntries(id)) {
- boolean matchesSrc = false, matchesDst = false;
- for (Instruction i : r.treatment().allInstructions()) {
- if (i.type() == Instruction.Type.OUTPUT) {
- // if the flow has matching src and dst
- for (Criterion cr : r.selector().criteria()) {
- if (cr.type() == Criterion.Type.ETH_DST) {
- if (((EthCriterion) cr).mac().equals(pair.dst)) {
- matchesDst = true;
- }
- } else if (cr.type() == Criterion.Type.ETH_SRC) {
- if (((EthCriterion) cr).mac().equals(pair.src)) {
- matchesSrc = true;
- }
- }
- }
- }
- }
- if (matchesDst && matchesSrc) {
- log.trace("Removed flow rule from device: " + id);
- flowRuleService.removeFlowRules((FlowRule) r);
- }
- }
-
- }
-
- // Returns a set of src/dst MAC pairs extracted from the specified set of flow entries
- private Set<SrcDstPair> findSrcDstPairs(Set<FlowEntry> rules) {
- ImmutableSet.Builder<SrcDstPair> builder = ImmutableSet.builder();
- for (FlowEntry r : rules) {
- MacAddress src = null, dst = null;
- for (Criterion cr : r.selector().criteria()) {
- if (cr.type() == Criterion.Type.ETH_DST) {
- dst = ((EthCriterion) cr).mac();
- } else if (cr.type() == Criterion.Type.ETH_SRC) {
- src = ((EthCriterion) cr).mac();
- }
- }
- builder.add(new SrcDstPair(src, dst));
- }
- return builder.build();
- }
-
- // Returns set of flow entries which were created by this application and
- // which egress from the specified connection port
- private Set<FlowEntry> getFlowRulesFrom(ConnectPoint egress) {
- ImmutableSet.Builder<FlowEntry> builder = ImmutableSet.builder();
- flowRuleService.getFlowEntries(egress.deviceId()).forEach(r -> {
- if (r.appId() == appId.id()) {
- r.treatment().allInstructions().forEach(i -> {
- if (i.type() == Instruction.Type.OUTPUT) {
- if (((Instructions.OutputInstruction) i).port().equals(egress.port())) {
- builder.add(r);
- }
- }
- });
- }
- });
-
- return builder.build();
- }
-
- // Wrapper class for a source and destination pair of MAC addresses
- private final class SrcDstPair {
- final MacAddress src;
- final MacAddress dst;
-
- private SrcDstPair(MacAddress src, MacAddress dst) {
- this.src = src;
- this.dst = dst;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- SrcDstPair that = (SrcDstPair) o;
- return Objects.equals(src, that.src) &&
- Objects.equals(dst, that.dst);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(src, dst);
- }
- }
-}