[CORD-46] Implement L2 switching in Segment Routing
DONE
- Update SpringOpenTTP to support bridging table emulation
- Populate low priority subnet broadcast entry for bridging table
- Move IP entry population to host event handler as well
- Update ArpHandler to handle intra-rack ARP forwarding/flooding
- Move TTL_OUT action from IP table to corresponding group
Since hardware does not support TTL_OUT in the IP table
- Populate entries to bridging table (MAC learning)
- Emulate src mac table
Not in this submission
- Emulate src-mac table behavior
- Pop vlan in the group instead of the flow
Change-Id: Ib69357c1889ccddaa4daa272d9f5843790ee1a3c
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
index 96c85ba..2c6412c 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
@@ -20,10 +20,10 @@
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
-import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficTreatment;
@@ -60,12 +60,21 @@
/**
* Processes incoming ARP packets.
+ *
* If it is an ARP request to router itself or known hosts,
* then it sends ARP response.
* If it is an ARP request to unknown hosts in its own subnet,
* then it flood the ARP request to the ports.
* If it is an ARP response, then set a flow rule for the host
* and forward any IP packets to the host in the packet buffer to the host.
+ * <p>
+ * Note: We handles all ARP packet in, even for those ARP packets between
+ * hosts in the same subnet.
+ * For an ARP packet with broadcast destination MAC,
+ * some switches pipelines will send it to the controller due to table miss,
+ * other swithches will flood the packets directly in the data plane without
+ * packet in.
+ * We can deal with both cases.
*
* @param pkt incoming packet
*/
@@ -86,29 +95,56 @@
if (arp.getOpCode() == ARP.OP_REQUEST) {
handleArpRequest(deviceId, connectPoint, ethernet);
} else {
- srManager.ipHandler.forwardPackets(deviceId, hostIpAddress);
+ handleArpReply(deviceId, connectPoint, ethernet);
}
}
private void handleArpRequest(DeviceId deviceId, ConnectPoint inPort, Ethernet payload) {
ARP arpRequest = (ARP) payload.getPayload();
+ VlanId vlanId = VlanId.vlanId(payload.getVlanID());
HostId targetHostId = HostId.hostId(MacAddress.valueOf(
- arpRequest.getTargetHardwareAddress()));
+ arpRequest.getTargetHardwareAddress()),
+ vlanId);
- // ARP request for router
+ // ARP request for router. Send ARP reply.
if (isArpReqForRouter(deviceId, arpRequest)) {
Ip4Address targetAddress = Ip4Address.valueOf(arpRequest.getTargetProtocolAddress());
-
- sendArpResponse(arpRequest, config.getRouterMacForAGatewayIp(targetAddress));
+ sendArpResponse(arpRequest, config.getRouterMacForAGatewayIp(targetAddress), vlanId);
} else {
Host targetHost = srManager.hostService.getHost(targetHostId);
- // ARP request for known hosts
+ // ARP request for known hosts. Send proxy ARP reply on behalf of the target.
if (targetHost != null) {
- sendArpResponse(arpRequest, targetHost.mac());
+ removeVlanAndForward(payload, targetHost.location());
+ // ARP request for unknown host in the subnet. Flood in the subnet.
+ } else {
+ removeVlanAndFlood(payload, inPort);
+ }
+ }
+ }
- // ARP request for unknown host in the subnet
- } else if (isArpReqForSubnet(deviceId, arpRequest)) {
- flood(payload, inPort);
+ private void handleArpReply(DeviceId deviceId, ConnectPoint inPort, Ethernet payload) {
+ ARP arpReply = (ARP) payload.getPayload();
+ VlanId vlanId = VlanId.vlanId(payload.getVlanID());
+ HostId targetHostId = HostId.hostId(MacAddress.valueOf(
+ arpReply.getTargetHardwareAddress()),
+ vlanId);
+
+ // ARP reply for router. Process all pending IP packets.
+ if (isArpReqForRouter(deviceId, arpReply)) {
+ Ip4Address hostIpAddress = Ip4Address.valueOf(arpReply.getSenderProtocolAddress());
+ srManager.ipHandler.forwardPackets(deviceId, hostIpAddress);
+ } else {
+ Host targetHost = srManager.hostService.getHost(targetHostId);
+ // ARP reply for known hosts. Forward to the host.
+ if (targetHost != null) {
+ removeVlanAndForward(payload, targetHost.location());
+ // ARP reply for unknown host, Flood in the subnet.
+ } else {
+ // Don't flood to non-edge ports
+ if (vlanId.equals(VlanId.vlanId(srManager.ASSIGNED_VLAN_NO_SUBNET))) {
+ return;
+ }
+ removeVlanAndFlood(payload, inPort);
}
}
}
@@ -126,14 +162,6 @@
return false;
}
- private boolean isArpReqForSubnet(DeviceId deviceId, ARP arpRequest) {
- return config.getSubnets(deviceId).stream()
- .anyMatch((prefix)->
- prefix.contains(Ip4Address.
- valueOf(arpRequest.
- getTargetProtocolAddress())));
- }
-
/**
* Sends an APR request for the target IP address to all ports except in-port.
*
@@ -170,11 +198,10 @@
.setSourceMACAddress(senderMacAddress)
.setEtherType(Ethernet.TYPE_ARP).setPayload(arpRequest);
- flood(eth, inPort);
+ removeVlanAndFlood(eth, inPort);
}
- private void sendArpResponse(ARP arpRequest, MacAddress targetMac) {
-
+ private void sendArpResponse(ARP arpRequest, MacAddress targetMac, VlanId vlanId) {
ARP arpReply = new ARP();
arpReply.setHardwareType(ARP.HW_TYPE_ETHERNET)
.setProtocolType(ARP.PROTO_TYPE_IP)
@@ -193,8 +220,9 @@
.setEtherType(Ethernet.TYPE_ARP).setPayload(arpReply);
- HostId dstId = HostId.hostId(MacAddress.valueOf(
- arpReply.getTargetHardwareAddress()));
+ HostId dstId = HostId.hostId(
+ MacAddress.valueOf(arpReply.getTargetHardwareAddress()),
+ vlanId);
Host dst = srManager.hostService.getHost(dstId);
if (dst == null) {
log.warn("Cannot send ARP response to unknown device");
@@ -209,19 +237,51 @@
srManager.packetService.emit(packet);
}
- private void flood(Ethernet request, ConnectPoint inPort) {
- TrafficTreatment.Builder builder;
- ByteBuffer buf = ByteBuffer.wrap(request.serialize());
+ /**
+ * Remove VLAN tag and flood to all ports in the same subnet.
+ *
+ * @param packet packet to be flooded
+ * @param inPort where the packet comes from
+ */
+ private void removeVlanAndFlood(Ethernet packet, ConnectPoint inPort) {
+ Ip4Address targetProtocolAddress = Ip4Address.valueOf(
+ ((ARP) packet.getPayload()).getTargetProtocolAddress()
+ );
- for (Port port: srManager.deviceService.getPorts(inPort.deviceId())) {
- if (!port.number().equals(inPort.port()) &&
- port.number().toLong() > 0) {
- builder = DefaultTrafficTreatment.builder();
- builder.setOutput(port.number());
- srManager.packetService.emit(new DefaultOutboundPacket(inPort.deviceId(),
- builder.build(), buf));
+ srManager.deviceConfiguration.getSubnetPortsMap(inPort.deviceId()).forEach((subnet, ports) -> {
+ if (subnet.contains(targetProtocolAddress)) {
+ ports.stream()
+ .filter(port -> port != inPort.port())
+ .forEach(port -> {
+ removeVlanAndForward(packet, new ConnectPoint(inPort.deviceId(), port));
+ });
}
- }
+ });
}
+ /**
+ * Remove VLAN tag and packet out to given port.
+ *
+ * Note: In current implementation, we expect all communication with
+ * end hosts within a subnet to be untagged.
+ * <p>
+ * For those pipelines that internally assigns a VLAN, the VLAN tag will be
+ * removed before egress.
+ * <p>
+ * For those pipelines that do not assign internal VLAN, the packet remains
+ * untagged.
+ *
+ * @param packet packet to be forwarded
+ * @param outPort where the packet should be forwarded
+ */
+ private void removeVlanAndForward(Ethernet packet, ConnectPoint outPort) {
+ packet.setEtherType(Ethernet.TYPE_ARP);
+ packet.setVlanID(Ethernet.VLAN_UNTAGGED);
+ ByteBuffer buf = ByteBuffer.wrap(packet.serialize());
+
+ TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
+ tbuilder.setOutput(outPort.port());
+ srManager.packetService.emit(new DefaultOutboundPacket(outPort.deviceId(),
+ tbuilder.build(), buf));
+ }
}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
index c4267eb..eb3b3fd 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
@@ -105,8 +105,17 @@
}
}
+ /**
+ * Sends an ICMP reply message.
+ *
+ * Note: we assume that packets sending from the edge switches to the hosts
+ * have untagged VLAN.
+ * @param icmpRequest the original ICMP request
+ * @param outport the output port where the ICMP reply should be sent to
+ */
private void sendICMPResponse(Ethernet icmpRequest, ConnectPoint outport) {
-
+ // Note: We assume that packets arrive at the edge switches have
+ // untagged VLAN.
Ethernet icmpReplyEth = new Ethernet();
IPv4 icmpRequestIpv4 = (IPv4) icmpRequest.getPayload();
@@ -129,7 +138,6 @@
icmpReplyEth.setEtherType(Ethernet.TYPE_IPV4);
icmpReplyEth.setDestinationMACAddress(icmpRequest.getSourceMACAddress());
icmpReplyEth.setSourceMACAddress(icmpRequest.getDestinationMACAddress());
- icmpReplyEth.setVlanID(icmpRequest.getVlanID());
Ip4Address destIpAddress = Ip4Address.valueOf(icmpReplyIpv4.getDestinationAddress());
Ip4Address destRouterAddress = config.getRouterIpAddressForASubnetHost(destIpAddress);
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
index f827403..bc3ce8c 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
@@ -55,7 +55,6 @@
import static com.google.common.base.Preconditions.checkNotNull;
public class RoutingRulePopulator {
-
private static final Logger log = LoggerFactory
.getLogger(RoutingRulePopulator.class);
@@ -105,13 +104,45 @@
*/
public void populateIpRuleForHost(DeviceId deviceId, Ip4Address hostIp,
MacAddress hostMac, PortNumber outPort) {
- MacAddress deviceMac;
+ log.debug("Populate IP table entry for host {} at {}:{}",
+ hostIp, deviceId, outPort);
+ ForwardingObjective.Builder fwdBuilder;
try {
- deviceMac = config.getDeviceMac(deviceId);
+ fwdBuilder = getForwardingObjectiveBuilder(
+ deviceId, hostIp, hostMac, outPort);
} catch (DeviceConfigNotFoundException e) {
log.warn(e.getMessage() + " Aborting populateIpRuleForHost.");
return;
}
+ srManager.flowObjectiveService.
+ forward(deviceId, fwdBuilder.add(new SRObjectiveContext(deviceId,
+ SRObjectiveContext.ObjectiveType.FORWARDING)));
+ rulePopulationCounter.incrementAndGet();
+ }
+
+ public void revokeIpRuleForHost(DeviceId deviceId, Ip4Address hostIp,
+ MacAddress hostMac, PortNumber outPort) {
+ log.debug("Revoke IP table entry for host {} at {}:{}",
+ hostIp, deviceId, outPort);
+ ForwardingObjective.Builder fwdBuilder;
+ try {
+ fwdBuilder = getForwardingObjectiveBuilder(
+ deviceId, hostIp, hostMac, outPort);
+ } catch (DeviceConfigNotFoundException e) {
+ log.warn(e.getMessage() + " Aborting revokeIpRuleForHost.");
+ return;
+ }
+ srManager.flowObjectiveService.
+ forward(deviceId, fwdBuilder.remove(new SRObjectiveContext(deviceId,
+ SRObjectiveContext.ObjectiveType.FORWARDING)));
+ }
+
+ private ForwardingObjective.Builder getForwardingObjectiveBuilder(
+ DeviceId deviceId, Ip4Address hostIp,
+ MacAddress hostMac, PortNumber outPort)
+ throws DeviceConfigNotFoundException {
+ MacAddress deviceMac;
+ deviceMac = config.getDeviceMac(deviceId);
TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
@@ -127,19 +158,10 @@
TrafficTreatment treatment = tbuilder.build();
TrafficSelector selector = sbuilder.build();
- ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
- .builder().fromApp(srManager.appId).makePermanent()
+ return DefaultForwardingObjective.builder()
+ .fromApp(srManager.appId).makePermanent()
.withSelector(selector).withTreatment(treatment)
.withPriority(100).withFlag(ForwardingObjective.Flag.SPECIFIC);
-
- log.debug("Installing IPv4 forwarding objective "
- + "for host {} in switch {}", hostIp, deviceId);
- srManager.flowObjectiveService.
- forward(deviceId,
- fwdBuilder.
- add(new SRObjectiveContext(deviceId,
- SRObjectiveContext.ObjectiveType.FORWARDING)));
- rulePopulationCounter.incrementAndGet();
}
/**
@@ -186,26 +208,25 @@
}
TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
- TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
-
sbuilder.matchIPDst(ipPrefix);
sbuilder.matchEthType(Ethernet.TYPE_IPV4);
+ TrafficSelector selector = sbuilder.build();
- NeighborSet ns = null;
+ TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
+ NeighborSet ns;
+ TrafficTreatment treatment;
// If the next hop is the same as the final destination, then MPLS label
// is not set.
if (nextHops.size() == 1 && nextHops.toArray()[0].equals(destSw)) {
- tbuilder.deferred().decNwTtl();
+ tbuilder.immediate().decNwTtl();
ns = new NeighborSet(nextHops);
+ treatment = tbuilder.build();
} else {
- tbuilder.deferred().copyTtlOut();
ns = new NeighborSet(nextHops, segmentId);
+ treatment = null;
}
- TrafficTreatment treatment = tbuilder.build();
- TrafficSelector selector = sbuilder.build();
-
if (srManager.getNextObjectiveId(deviceId, ns) <= 0) {
log.warn("No next objective in {} for ns: {}", deviceId, ns);
return false;
@@ -216,10 +237,12 @@
.fromApp(srManager.appId)
.makePermanent()
.nextStep(srManager.getNextObjectiveId(deviceId, ns))
- .withTreatment(treatment)
.withSelector(selector)
.withPriority(100)
.withFlag(ForwardingObjective.Flag.SPECIFIC);
+ if (treatment != null) {
+ fwdBuilder.withTreatment(treatment);
+ }
log.debug("Installing IPv4 forwarding objective "
+ "for router IP/subnet {} in switch {}",
ipPrefix,
@@ -423,8 +446,6 @@
? VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET)
: srManager.getSubnetAssignedVlanId(deviceId, portSubnet);
-
-
FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
fob.withKey(Criteria.matchInPort(port.number()))
.addCondition(Criteria.matchEthDst(deviceMac))
@@ -469,14 +490,14 @@
Set<Ip4Address> allIps = new HashSet<Ip4Address>(config.getPortIPs(deviceId));
allIps.add(routerIp);
for (Ip4Address ipaddr : allIps) {
- TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
- TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
- selector.matchEthType(Ethernet.TYPE_IPV4);
- selector.matchIPDst(IpPrefix.valueOf(ipaddr,
+ TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
+ sbuilder.matchEthType(Ethernet.TYPE_IPV4);
+ sbuilder.matchIPDst(IpPrefix.valueOf(ipaddr,
IpPrefix.MAX_INET_MASK_LENGTH));
- treatment.setOutput(PortNumber.CONTROLLER);
- puntIp.withSelector(selector.build());
- puntIp.withTreatment(treatment.build());
+ tbuilder.setOutput(PortNumber.CONTROLLER);
+ puntIp.withSelector(sbuilder.build());
+ puntIp.withTreatment(tbuilder.build());
puntIp.withFlag(Flag.VERSATILE)
.withPriority(HIGHEST_PRIORITY)
.makePermanent()
@@ -489,6 +510,48 @@
}
}
+ /**
+ * Populates a forwarding objective to send packets that miss other high
+ * priority Bridging Table entries to a group that contains all ports of
+ * its subnet.
+ *
+ * Note: We assume that packets sending from the edge switches to the hosts
+ * have untagged VLAN.
+ * The VLAN tag will be popped later in the flooding group.
+ *
+ * @param deviceId switch ID to set the rules
+ */
+ public void populateSubnetBroadcastRule(DeviceId deviceId) {
+ config.getSubnets(deviceId).forEach(subnet -> {
+ int nextId = srManager.getSubnetNextObjectiveId(deviceId, subnet);
+ VlanId vlanId = srManager.getSubnetAssignedVlanId(deviceId, subnet);
+
+ /* Driver should treat objective with MacAddress.NONE as the
+ * subnet broadcast rule
+ */
+ TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
+ sbuilder.matchVlanId(vlanId);
+ sbuilder.matchEthDst(MacAddress.NONE);
+
+ ForwardingObjective.Builder fob = DefaultForwardingObjective.builder();
+ fob.withFlag(Flag.SPECIFIC)
+ .withSelector(sbuilder.build())
+ .nextStep(nextId)
+ .withPriority(5)
+ .fromApp(srManager.appId)
+ .makePermanent();
+
+ srManager.flowObjectiveService.forward(
+ deviceId,
+ fob.add(new SRObjectiveContext(
+ deviceId,
+ SRObjectiveContext.ObjectiveType.FORWARDING)
+ )
+ );
+ });
+ }
+
+
private PortNumber selectOnePort(DeviceId srcId, Set<DeviceId> destIds) {
Set<Link> links = srManager.linkService.getDeviceLinks(srcId);
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index 787f934..84fe516 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -22,6 +22,7 @@
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.packet.Ethernet;
+import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
@@ -33,11 +34,23 @@
import org.onosproject.core.CoreService;
import org.onosproject.event.Event;
import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.PortNumber;
import org.onosproject.net.config.ConfigFactory;
import org.onosproject.net.config.NetworkConfigEvent;
import org.onosproject.net.config.NetworkConfigRegistry;
import org.onosproject.net.config.NetworkConfigListener;
import org.onosproject.net.config.basics.SubjectFactories;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.net.flowobjective.ObjectiveContext;
+import org.onosproject.net.flowobjective.ObjectiveError;
+import org.onosproject.net.host.HostEvent;
+import org.onosproject.net.host.HostListener;
import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
import org.onosproject.segmentrouting.config.DeviceConfiguration;
import org.onosproject.segmentrouting.config.SegmentRoutingConfig;
@@ -139,11 +152,13 @@
private static ScheduledFuture<?> eventHandlerFuture = null;
private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
- private Map<DeviceId, DefaultGroupHandler> groupHandlerMap = new ConcurrentHashMap<DeviceId, DefaultGroupHandler>();
+ private Map<DeviceId, DefaultGroupHandler> groupHandlerMap =
+ new ConcurrentHashMap<DeviceId, DefaultGroupHandler>();
// Per device next objective ID store with (device id + neighbor set) as key
- private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
- Integer> nsNextObjStore = null;
- private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null;
+ private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
+ nsNextObjStore = null;
+ private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
+ subnetNextObjStore = null;
private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
private EventuallyConsistentMap<String, Policy> policyStore = null;
// Per device, per-subnet assigned-vlans store, with (device id + subnet
@@ -170,6 +185,8 @@
}
};
+ private final HostListener hostListener = new InternalHostListener();
+
private Object threadSchedulerLock = new Object();
private static int numOfEventsQueued = 0;
private static int numOfEventsExecuted = 0;
@@ -259,6 +276,8 @@
cfgService.addListener(cfgListener);
cfgService.registerConfigFactory(cfgFactory);
+ hostService.addListener(hostListener);
+
processor = new InternalPacketProcessor();
linkListener = new InternalLinkListener();
deviceListener = new InternalDeviceListener();
@@ -637,6 +656,7 @@
if (mastershipService.isLocalMaster(device.id())) {
DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
groupHandler.createGroupsFromSubnetConfig();
+ routingRulePopulator.populateSubnetBroadcastRule(device.id());
}
}
@@ -703,6 +723,7 @@
if (mastershipService.isLocalMaster(device.id())) {
DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
groupHandler.createGroupsFromSubnetConfig();
+ routingRulePopulator.populateSubnetBroadcastRule(device.id());
}
}
@@ -723,4 +744,205 @@
}
}
}
+
+ private class InternalHostListener implements HostListener {
+ private ForwardingObjective.Builder getForwardingObjectiveBuilder(
+ MacAddress mac, VlanId vlanId, PortNumber port) {
+ TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
+ sbuilder.matchEthDst(mac);
+ sbuilder.matchVlanId(vlanId);
+
+ TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
+ // TODO Move popVlan from flow action to group action
+ tbuilder.immediate().popVlan();
+ tbuilder.immediate().setOutput(port);
+
+ return DefaultForwardingObjective.builder()
+ .withFlag(ForwardingObjective.Flag.SPECIFIC)
+ .withSelector(sbuilder.build())
+ .withTreatment(tbuilder.build())
+ .withPriority(100)
+ .fromApp(appId)
+ .makePermanent();
+ }
+
+ private void processHostAddedEvent(HostEvent event) {
+ MacAddress mac = event.subject().mac();
+ VlanId vlanId = event.subject().vlan();
+ DeviceId deviceId = event.subject().location().deviceId();
+ PortNumber port = event.subject().location().port();
+ Set<IpAddress> ips = event.subject().ipAddresses();
+ log.debug("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
+
+ // TODO Move bridging table population to a separate class
+ // Populate bridging table entry
+ ForwardingObjective.Builder fob =
+ getForwardingObjectiveBuilder(mac, vlanId, port);
+ flowObjectiveService.forward(deviceId, fob.add(
+ new BridgingTableObjectiveContext(mac, vlanId)
+ ));
+
+ // Populate IP table entry
+ ips.forEach(ip -> {
+ if (ip.isIp4()) {
+ routingRulePopulator.populateIpRuleForHost(
+ deviceId, ip.getIp4Address(), mac, port);
+ }
+ });
+ }
+
+ private void processHostRemoveEvent(HostEvent event) {
+ MacAddress mac = event.subject().mac();
+ VlanId vlanId = event.subject().vlan();
+ DeviceId deviceId = event.subject().location().deviceId();
+ PortNumber port = event.subject().location().port();
+ Set<IpAddress> ips = event.subject().ipAddresses();
+ log.debug("Host {}/{} is removed from {}:{}", mac, vlanId, deviceId, port);
+
+ // Revoke bridging table entry
+ ForwardingObjective.Builder fob =
+ getForwardingObjectiveBuilder(mac, vlanId, port);
+ flowObjectiveService.forward(deviceId, fob.remove(
+ new BridgingTableObjectiveContext(mac, vlanId)
+ ));
+
+ // Revoke IP table entry
+ ips.forEach(ip -> {
+ if (ip.isIp4()) {
+ routingRulePopulator.revokeIpRuleForHost(
+ deviceId, ip.getIp4Address(), mac, port);
+ }
+ });
+ }
+
+ private void processHostMovedEvent(HostEvent event) {
+ MacAddress mac = event.subject().mac();
+ VlanId vlanId = event.subject().vlan();
+ DeviceId prevDeviceId = event.prevSubject().location().deviceId();
+ PortNumber prevPort = event.prevSubject().location().port();
+ Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
+ DeviceId newDeviceId = event.subject().location().deviceId();
+ PortNumber newPort = event.subject().location().port();
+ Set<IpAddress> newIps = event.subject().ipAddresses();
+ log.debug("Host {}/{} is moved from {}:{} to {}:{}",
+ mac, vlanId, prevDeviceId, prevPort, newDeviceId, newPort);
+
+ // Revoke previous bridging table entry
+ ForwardingObjective.Builder prevFob =
+ getForwardingObjectiveBuilder(mac, vlanId, prevPort);
+ flowObjectiveService.forward(prevDeviceId, prevFob.remove(
+ new BridgingTableObjectiveContext(mac, vlanId)
+ ));
+
+ // Revoke previous IP table entry
+ prevIps.forEach(ip -> {
+ if (ip.isIp4()) {
+ routingRulePopulator.revokeIpRuleForHost(
+ prevDeviceId, ip.getIp4Address(), mac, prevPort);
+ }
+ });
+
+ // Populate new bridging table entry
+ ForwardingObjective.Builder newFob =
+ getForwardingObjectiveBuilder(mac, vlanId, prevPort);
+ flowObjectiveService.forward(newDeviceId, newFob.add(
+ new BridgingTableObjectiveContext(mac, vlanId)
+ ));
+
+ // Populate new IP table entry
+ newIps.forEach(ip -> {
+ if (ip.isIp4()) {
+ routingRulePopulator.populateIpRuleForHost(
+ newDeviceId, ip.getIp4Address(), mac, newPort);
+ }
+ });
+ }
+
+ private void processHostUpdatedEvent(HostEvent event) {
+ MacAddress mac = event.subject().mac();
+ VlanId vlanId = event.subject().vlan();
+ DeviceId prevDeviceId = event.prevSubject().location().deviceId();
+ PortNumber prevPort = event.prevSubject().location().port();
+ Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
+ DeviceId newDeviceId = event.subject().location().deviceId();
+ PortNumber newPort = event.subject().location().port();
+ Set<IpAddress> newIps = event.subject().ipAddresses();
+ log.debug("Host {}/{} is updated", mac, vlanId);
+
+ // Revoke previous IP table entry
+ prevIps.forEach(ip -> {
+ if (ip.isIp4()) {
+ routingRulePopulator.revokeIpRuleForHost(
+ prevDeviceId, ip.getIp4Address(), mac, prevPort);
+ }
+ });
+
+ // Populate new IP table entry
+ newIps.forEach(ip -> {
+ if (ip.isIp4()) {
+ routingRulePopulator.populateIpRuleForHost(
+ newDeviceId, ip.getIp4Address(), mac, newPort);
+ }
+ });
+ }
+
+ @Override
+ public void event(HostEvent event) {
+ // Do not proceed without mastership
+ DeviceId deviceId = event.subject().location().deviceId();
+ if (!mastershipService.isLocalMaster(deviceId)) {
+ return;
+ }
+
+ switch (event.type()) {
+ case HOST_ADDED:
+ processHostAddedEvent(event);
+ break;
+ case HOST_MOVED:
+ processHostMovedEvent(event);
+ break;
+ case HOST_REMOVED:
+ processHostRemoveEvent(event);
+ break;
+ case HOST_UPDATED:
+ processHostUpdatedEvent(event);
+ break;
+ default:
+ log.warn("Unsupported host event type: {}", event.type());
+ break;
+ }
+ }
+ }
+
+ private static class BridgingTableObjectiveContext implements ObjectiveContext {
+ final MacAddress mac;
+ final VlanId vlanId;
+
+ BridgingTableObjectiveContext(MacAddress mac, VlanId vlanId) {
+ this.mac = mac;
+ this.vlanId = vlanId;
+ }
+
+ @Override
+ public void onSuccess(Objective objective) {
+ if (objective.op() == Objective.Operation.ADD) {
+ log.debug("Successfully populate bridging table entry for {}/{}",
+ mac, vlanId);
+ } else {
+ log.debug("Successfully revoke bridging table entry for {}/{}",
+ mac, vlanId);
+ }
+ }
+
+ @Override
+ public void onError(Objective objective, ObjectiveError error) {
+ if (objective.op() == Objective.Operation.ADD) {
+ log.debug("Fail to populate bridging table entry for {}/{}. {}",
+ mac, vlanId, error);
+ } else {
+ log.debug("Fail to revoke bridging table entry for {}/{}. {}",
+ mac, vlanId, error);
+ }
+ }
+ }
}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
index 55b556e..b394db5 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
@@ -224,8 +224,8 @@
.setEthSrc(nodeMacAddr);
if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
tBuilder.pushMpls()
- .setMpls(MplsLabel.
- mplsLabel(ns.getEdgeLabel()));
+ .copyTtlOut()
+ .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
}
Integer nextId = nsNextObjStore.
@@ -292,8 +292,9 @@
.setEthDst(dstMac)
.setEthSrc(nodeMacAddr);
if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
- tBuilder.pushMpls().setMpls(MplsLabel.mplsLabel(ns
- .getEdgeLabel()));
+ tBuilder.pushMpls()
+ .copyTtlOut()
+ .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
}
Integer nextId = nsNextObjStore.
@@ -536,8 +537,9 @@
.setEthDst(deviceMac)
.setEthSrc(nodeMacAddr);
if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
- tBuilder.pushMpls().setMpls(MplsLabel.mplsLabel(ns
- .getEdgeLabel()));
+ tBuilder.pushMpls()
+ .copyTtlOut()
+ .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
}
nextObjBuilder.addTreatment(tBuilder.build());
}
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
index 31297ff..b554106 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
@@ -25,6 +25,7 @@
import org.onlab.osgi.ServiceDirectory;
import org.onlab.packet.Ethernet;
+import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onlab.util.KryoNamespace;
import org.onosproject.core.ApplicationId;
@@ -54,6 +55,7 @@
import org.onosproject.net.flow.criteria.VlanIdCriterion;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
import org.onosproject.net.flowobjective.FilteringObjective;
import org.onosproject.net.flowobjective.FlowObjectiveStore;
import org.onosproject.net.flowobjective.ForwardingObjective;
@@ -94,7 +96,9 @@
private static final int TABLE_TMAC = 1;
private static final int TABLE_IPV4_UNICAST = 2;
private static final int TABLE_MPLS = 3;
+ private static final int TABLE_DMAC = 4;
private static final int TABLE_ACL = 5;
+ private static final int TABLE_SMAC = 6;
/**
* Set the default values. These variables will get overwritten based on the
@@ -104,7 +108,9 @@
protected int tmacTableId = TABLE_TMAC;
protected int ipv4UnicastTableId = TABLE_IPV4_UNICAST;
protected int mplsTableId = TABLE_MPLS;
+ protected int dstMacTableId = TABLE_DMAC;
protected int aclTableId = TABLE_ACL;
+ protected int srcMacTableId = TABLE_SMAC;
protected final Logger log = getLogger(getClass());
@@ -448,12 +454,14 @@
fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) {
OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0);
if (o.port() == PortNumber.CONTROLLER) {
- log.warn("Punts to the controller are handled by misses in"
- + " the TMAC, IP and MPLS tables.");
- return Collections.emptySet();
+ treatmentBuilder.punt();
+ treatment = treatmentBuilder.build();
+ } else {
+ treatment = fwd.treatment();
}
+ } else {
+ treatment = fwd.treatment();
}
- treatment = fwd.treatment();
} else {
log.warn("VERSATILE forwarding objective needs next objective ID "
+ "or treatment.");
@@ -475,19 +483,52 @@
return Collections.singletonList(ruleBuilder.build());
}
- protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
- log.debug("Processing specific");
+ private boolean isSupportedEthTypeObjective(ForwardingObjective fwd) {
TrafficSelector selector = fwd.selector();
EthTypeCriterion ethType = (EthTypeCriterion) selector
.getCriterion(Criterion.Type.ETH_TYPE);
if ((ethType == null) ||
- (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
- (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) {
+ ((ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
+ (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST))) {
+ return false;
+ }
+ return true;
+ }
+
+ private boolean isSupportedEthDstObjective(ForwardingObjective fwd) {
+ TrafficSelector selector = fwd.selector();
+ EthCriterion ethDst = (EthCriterion) selector
+ .getCriterion(Criterion.Type.ETH_DST);
+ VlanIdCriterion vlanId = (VlanIdCriterion) selector
+ .getCriterion(Criterion.Type.VLAN_VID);
+ if (ethDst == null && vlanId == null) {
+ return false;
+ }
+ return true;
+ }
+
+ protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
+ log.debug("Processing specific");
+ boolean isEthTypeObj = isSupportedEthTypeObjective(fwd);
+ boolean isEthDstObj = isSupportedEthDstObjective(fwd);
+
+ if (isEthTypeObj) {
+ return processEthTypeSpecificObjective(fwd);
+ } else if (isEthDstObj) {
+ return processEthDstSpecificObjective(fwd);
+ } else {
log.warn("processSpecific: Unsupported "
+ "forwarding objective criteraia");
fail(fwd, ObjectiveError.UNSUPPORTED);
return Collections.emptySet();
}
+ }
+
+ protected Collection<FlowRule>
+ processEthTypeSpecificObjective(ForwardingObjective fwd) {
+ TrafficSelector selector = fwd.selector();
+ EthTypeCriterion ethType = (EthTypeCriterion) selector
+ .getCriterion(Criterion.Type.ETH_TYPE);
TrafficSelector.Builder filteredSelectorBuilder =
DefaultTrafficSelector.builder();
@@ -565,59 +606,167 @@
}
- protected List<FlowRule> processEthDstFilter(Criterion c,
- FilteringObjective filt,
- ApplicationId applicationId) {
+ protected Collection<FlowRule>
+ processEthDstSpecificObjective(ForwardingObjective fwd) {
List<FlowRule> rules = new ArrayList<>();
- EthCriterion e = (EthCriterion) c;
+
+ // Build filtered selector
+ TrafficSelector selector = fwd.selector();
+ EthCriterion ethCriterion = (EthCriterion) selector
+ .getCriterion(Criterion.Type.ETH_DST);
+ VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
+ .getCriterion(Criterion.Type.VLAN_VID);
+ TrafficSelector.Builder filteredSelectorBuilder =
+ DefaultTrafficSelector.builder();
+ // Do not match MacAddress for subnet broadcast entry
+ if (!ethCriterion.mac().equals(MacAddress.NONE)) {
+ filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
+ }
+ filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
+ TrafficSelector filteredSelector = filteredSelectorBuilder.build();
+
+ // Build filtered treatment
+ TrafficTreatment.Builder treatmentBuilder =
+ DefaultTrafficTreatment.builder();
+ if (fwd.treatment() != null) {
+ treatmentBuilder.deferred();
+ fwd.treatment().allInstructions().forEach(treatmentBuilder::add);
+ }
+ if (fwd.nextId() != null) {
+ NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
+ if (next != null) {
+ GroupKey key = appKryo.deserialize(next.data());
+ Group group = groupService.getGroup(deviceId, key);
+ if (group != null) {
+ treatmentBuilder.deferred().group(group.id());
+ } else {
+ log.warn("Group Missing");
+ fail(fwd, ObjectiveError.GROUPMISSING);
+ return Collections.emptySet();
+ }
+ }
+ }
+ treatmentBuilder.immediate().transition(aclTableId);
+ TrafficTreatment filteredTreatment = treatmentBuilder.build();
+
+ // Build bridging table entries
+ FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
+ flowRuleBuilder.fromApp(fwd.appId())
+ .withPriority(fwd.priority())
+ .forDevice(deviceId)
+ .withSelector(filteredSelector)
+ .withTreatment(filteredTreatment)
+ .forTable(dstMacTableId);
+ if (fwd.permanent()) {
+ flowRuleBuilder.makePermanent();
+ } else {
+ flowRuleBuilder.makeTemporary(fwd.timeout());
+ }
+ rules.add(flowRuleBuilder.build());
+
+ /*
+ // TODO Emulate source MAC table behavior
+ // Do not install source MAC table entry for subnet broadcast
+ if (!ethCriterion.mac().equals(MacAddress.NONE)) {
+ // Build filtered selector
+ selector = fwd.selector();
+ ethCriterion = (EthCriterion) selector.getCriterion(Criterion.Type.ETH_DST);
+ filteredSelectorBuilder = DefaultTrafficSelector.builder();
+ filteredSelectorBuilder.matchEthSrc(ethCriterion.mac());
+ filteredSelector = filteredSelectorBuilder.build();
+
+ // Build empty treatment. Apply existing instruction if match.
+ treatmentBuilder = DefaultTrafficTreatment.builder();
+ filteredTreatment = treatmentBuilder.build();
+
+ // Build bridging table entries
+ flowRuleBuilder = DefaultFlowRule.builder();
+ flowRuleBuilder.fromApp(fwd.appId())
+ .withPriority(fwd.priority())
+ .forDevice(deviceId)
+ .withSelector(filteredSelector)
+ .withTreatment(filteredTreatment)
+ .forTable(srcMacTableId)
+ .makePermanent();
+ rules.add(flowRuleBuilder.build());
+ }
+ */
+
+ return rules;
+ }
+
+ protected List<FlowRule> processEthDstFilter(EthCriterion ethCriterion,
+ VlanIdCriterion vlanIdCriterion,
+ FilteringObjective filt,
+ VlanId assignedVlan,
+ ApplicationId applicationId) {
+ //handling untagged packets via assigned VLAN
+ if (vlanIdCriterion.vlanId() == VlanId.NONE) {
+ vlanIdCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
+ }
+
+ /*
+ * Note: CpqD switches do not handle MPLS-related operation properly
+ * for a packet with VLAN tag. We pop VLAN here as a workaround.
+ * Side effect: HostService learns redundant hosts with same MAC but
+ * different VLAN. No known side effect on the network reachability.
+ */
+ List<FlowRule> rules = new ArrayList<>();
TrafficSelector.Builder selectorIp = DefaultTrafficSelector
.builder();
TrafficTreatment.Builder treatmentIp = DefaultTrafficTreatment
.builder();
- selectorIp.matchEthDst(e.mac());
+ selectorIp.matchEthDst(ethCriterion.mac());
selectorIp.matchEthType(Ethernet.TYPE_IPV4);
+ selectorIp.matchVlanId(vlanIdCriterion.vlanId());
+ treatmentIp.popVlan();
treatmentIp.transition(ipv4UnicastTableId);
FlowRule ruleIp = DefaultFlowRule.builder().forDevice(deviceId)
.withSelector(selectorIp.build())
.withTreatment(treatmentIp.build())
.withPriority(filt.priority()).fromApp(applicationId)
.makePermanent().forTable(tmacTableId).build();
- log.debug("adding IP ETH rule for MAC: {}", e.mac());
+ log.debug("adding IP ETH rule for MAC: {}", ethCriterion.mac());
rules.add(ruleIp);
TrafficSelector.Builder selectorMpls = DefaultTrafficSelector
.builder();
TrafficTreatment.Builder treatmentMpls = DefaultTrafficTreatment
.builder();
- selectorMpls.matchEthDst(e.mac());
+ selectorMpls.matchEthDst(ethCriterion.mac());
selectorMpls.matchEthType(Ethernet.MPLS_UNICAST);
+ selectorMpls.matchVlanId(vlanIdCriterion.vlanId());
+ treatmentMpls.popVlan();
treatmentMpls.transition(mplsTableId);
FlowRule ruleMpls = DefaultFlowRule.builder()
.forDevice(deviceId).withSelector(selectorMpls.build())
.withTreatment(treatmentMpls.build())
.withPriority(filt.priority()).fromApp(applicationId)
.makePermanent().forTable(tmacTableId).build();
- log.debug("adding MPLS ETH rule for MAC: {}", e.mac());
+ log.debug("adding MPLS ETH rule for MAC: {}", ethCriterion.mac());
rules.add(ruleMpls);
return rules;
}
- protected List<FlowRule> processVlanIdFilter(Criterion c,
+ protected List<FlowRule> processVlanIdFilter(VlanIdCriterion vlanIdCriterion,
FilteringObjective filt,
+ VlanId assignedVlan,
ApplicationId applicationId) {
List<FlowRule> rules = new ArrayList<>();
- VlanIdCriterion v = (VlanIdCriterion) c;
- log.debug("adding rule for VLAN: {}", v.vlanId());
+ log.debug("adding rule for VLAN: {}", vlanIdCriterion.vlanId());
TrafficSelector.Builder selector = DefaultTrafficSelector
.builder();
TrafficTreatment.Builder treatment = DefaultTrafficTreatment
.builder();
PortCriterion p = (PortCriterion) filt.key();
- if (v.vlanId() != VlanId.NONE) {
- selector.matchVlanId(v.vlanId());
+ if (vlanIdCriterion.vlanId() != VlanId.NONE) {
+ selector.matchVlanId(vlanIdCriterion.vlanId());
selector.matchInPort(p.port());
treatment.deferred().popVlan();
+ } else {
+ selector.matchInPort(p.port());
+ treatment.immediate().pushVlan().setVlanId(assignedVlan);
}
treatment.transition(tmacTableId);
FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId)
@@ -641,30 +790,79 @@
fail(filt, ObjectiveError.UNKNOWN);
return;
}
+
+ EthCriterion ethCriterion = null;
+ VlanIdCriterion vlanIdCriterion = null;
+
// convert filtering conditions for switch-intfs into flowrules
FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
- for (Criterion c : filt.conditions()) {
- if (c.type() == Criterion.Type.ETH_DST) {
- for (FlowRule rule : processEthDstFilter(c,
- filt,
- applicationId)) {
- ops = install ? ops.add(rule) : ops.remove(rule);
- }
- } else if (c.type() == Criterion.Type.VLAN_VID) {
- for (FlowRule rule : processVlanIdFilter(c,
- filt,
- applicationId)) {
- ops = install ? ops.add(rule) : ops.remove(rule);
- }
- } else if (c.type() == Criterion.Type.IPV4_DST) {
+
+ for (Criterion criterion : filt.conditions()) {
+ if (criterion.type() == Criterion.Type.ETH_DST) {
+ ethCriterion = (EthCriterion) criterion;
+ } else if (criterion.type() == Criterion.Type.VLAN_VID) {
+ vlanIdCriterion = (VlanIdCriterion) criterion;
+ } else if (criterion.type() == Criterion.Type.IPV4_DST) {
log.debug("driver does not process IP filtering rules as it " +
"sends all misses in the IP table to the controller");
} else {
log.warn("Driver does not currently process filtering condition"
- + " of type: {}", c.type());
+ + " of type: {}", criterion.type());
fail(filt, ObjectiveError.UNSUPPORTED);
}
}
+
+ VlanId assignedVlan = null;
+ if (vlanIdCriterion != null && vlanIdCriterion.vlanId() == VlanId.NONE) {
+ // Assign a VLAN ID to untagged packets
+ if (filt.meta() == null) {
+ log.error("Missing metadata in filtering objective required "
+ + "for vlan assignment in dev {}", deviceId);
+ fail(filt, ObjectiveError.BADPARAMS);
+ return;
+ }
+ for (Instruction i : filt.meta().allInstructions()) {
+ if (i instanceof ModVlanIdInstruction) {
+ assignedVlan = ((ModVlanIdInstruction) i).vlanId();
+ }
+ }
+ if (assignedVlan == null) {
+ log.error("Driver requires an assigned vlan-id to tag incoming "
+ + "untagged packets. Not processing vlan filters on "
+ + "device {}", deviceId);
+ fail(filt, ObjectiveError.BADPARAMS);
+ return;
+ }
+ }
+
+ if (ethCriterion == null) {
+ log.debug("filtering objective missing dstMac, cannot program TMAC table");
+ } else {
+ for (FlowRule tmacRule : processEthDstFilter(ethCriterion,
+ vlanIdCriterion,
+ filt,
+ assignedVlan,
+ applicationId)) {
+ log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}",
+ tmacRule, deviceId);
+ ops = install ? ops.add(tmacRule) : ops.remove(tmacRule);
+ }
+ }
+
+ if (ethCriterion == null || vlanIdCriterion == null) {
+ log.debug("filtering objective missing dstMac or vlan, cannot program"
+ + "Vlan Table");
+ } else {
+ for (FlowRule vlanRule : processVlanIdFilter(vlanIdCriterion,
+ filt,
+ assignedVlan,
+ applicationId)) {
+ log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}",
+ vlanRule, deviceId);
+ ops = install ? ops.add(vlanRule) : ops.remove(vlanRule);
+ }
+ }
+
// apply filtering flow rules
flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
@Override
@@ -686,10 +884,10 @@
protected void setTableMissEntries() {
// set all table-miss-entries
populateTableMissEntry(vlanTableId, true, false, false, -1);
- populateTableMissEntry(tmacTableId, true, false, false, -1);
- populateTableMissEntry(ipv4UnicastTableId, false, true, true,
- aclTableId);
+ populateTableMissEntry(tmacTableId, false, false, true, dstMacTableId);
+ populateTableMissEntry(ipv4UnicastTableId, false, true, true, aclTableId);
populateTableMissEntry(mplsTableId, false, true, true, aclTableId);
+ populateTableMissEntry(dstMacTableId, false, false, true, aclTableId);
populateTableMissEntry(aclTableId, false, false, false, -1);
}
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTPDell.java b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTPDell.java
index 3267d550..91f2679 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTPDell.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTPDell.java
@@ -21,6 +21,7 @@
import org.onlab.packet.Ethernet;
import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.behaviour.NextGroup;
import org.onosproject.net.flow.DefaultFlowRule;
@@ -34,6 +35,7 @@
import org.onosproject.net.flow.criteria.EthTypeCriterion;
import org.onosproject.net.flow.criteria.IPCriterion;
import org.onosproject.net.flow.criteria.MplsCriterion;
+import org.onosproject.net.flow.criteria.VlanIdCriterion;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flowobjective.FilteringObjective;
import org.onosproject.net.flowobjective.ForwardingObjective;
@@ -175,12 +177,13 @@
//Dell switches need ETH_DST based match condition in all IP table entries.
//So while processing the ETH_DST based filtering objective, store
//the device MAC to be used locally to use it while pushing the IP rules.
- protected List<FlowRule> processEthDstFilter(Criterion c,
+ protected List<FlowRule> processEthDstFilter(EthCriterion ethCriterion,
+ VlanIdCriterion vlanIdCriterion,
FilteringObjective filt,
+ VlanId assignedVlan,
ApplicationId applicationId) {
// Store device termination Mac to be used in IP flow entries
- EthCriterion e = (EthCriterion) c;
- deviceTMac = e.mac();
+ deviceTMac = ethCriterion.mac();
log.debug("For now not adding any TMAC rules "
+ "into Dell switches as it is ignoring");
@@ -189,8 +192,9 @@
}
@Override
- protected List<FlowRule> processVlanIdFilter(Criterion c,
+ protected List<FlowRule> processVlanIdFilter(VlanIdCriterion vlanIdCriterion,
FilteringObjective filt,
+ VlanId assignedVlan,
ApplicationId applicationId) {
log.debug("For now not adding any VLAN rules "
+ "into Dell switches as it is ignoring");