Saurav Das
Committed by Gerrit Code Review

CORD-367 L2 bridging and L3 routing support with internal VLANs in OF-DPA.

Also includes:
     All forwarding in app is now via nextObjectives (not treatments) - Spring Open driver converts
     non-ECMP forwarding to flow-actions, while OF-DPA driver continues to use groups.
     Convert 'setMeta' methods to 'withMeta' in Flow Objectives API.
     Bug fix in Flow Objective Manager - set of PendingNext is now threadsafe.
     Bug fix in ArpHandler - now recognizes routerIp in addition to gatewayIps
     Removed a bunch of testcode
     Added group count in CLI

Change-Id: Id3b879c5dda78151ca0ec359179f1604066d39fc
Showing 20 changed files with 761 additions and 608 deletions
...@@ -107,7 +107,7 @@ public class ArpHandler { ...@@ -107,7 +107,7 @@ public class ArpHandler {
107 vlanId); 107 vlanId);
108 108
109 // ARP request for router. Send ARP reply. 109 // ARP request for router. Send ARP reply.
110 - if (isArpReqForRouter(deviceId, arpRequest)) { 110 + if (isArpForRouter(deviceId, arpRequest)) {
111 Ip4Address targetAddress = Ip4Address.valueOf(arpRequest.getTargetProtocolAddress()); 111 Ip4Address targetAddress = Ip4Address.valueOf(arpRequest.getTargetProtocolAddress());
112 sendArpResponse(arpRequest, config.getRouterMacForAGatewayIp(targetAddress), vlanId); 112 sendArpResponse(arpRequest, config.getRouterMacForAGatewayIp(targetAddress), vlanId);
113 } else { 113 } else {
...@@ -130,7 +130,7 @@ public class ArpHandler { ...@@ -130,7 +130,7 @@ public class ArpHandler {
130 vlanId); 130 vlanId);
131 131
132 // ARP reply for router. Process all pending IP packets. 132 // ARP reply for router. Process all pending IP packets.
133 - if (isArpReqForRouter(deviceId, arpReply)) { 133 + if (isArpForRouter(deviceId, arpReply)) {
134 Ip4Address hostIpAddress = Ip4Address.valueOf(arpReply.getSenderProtocolAddress()); 134 Ip4Address hostIpAddress = Ip4Address.valueOf(arpReply.getSenderProtocolAddress());
135 srManager.ipHandler.forwardPackets(deviceId, hostIpAddress); 135 srManager.ipHandler.forwardPackets(deviceId, hostIpAddress);
136 } else { 136 } else {
...@@ -141,7 +141,8 @@ public class ArpHandler { ...@@ -141,7 +141,8 @@ public class ArpHandler {
141 // ARP reply for unknown host, Flood in the subnet. 141 // ARP reply for unknown host, Flood in the subnet.
142 } else { 142 } else {
143 // Don't flood to non-edge ports 143 // Don't flood to non-edge ports
144 - if (vlanId.equals(VlanId.vlanId(srManager.ASSIGNED_VLAN_NO_SUBNET))) { 144 + if (vlanId.equals(
145 + VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET))) {
145 return; 146 return;
146 } 147 }
147 removeVlanAndFlood(payload, inPort); 148 removeVlanAndFlood(payload, inPort);
...@@ -150,14 +151,21 @@ public class ArpHandler { ...@@ -150,14 +151,21 @@ public class ArpHandler {
150 } 151 }
151 152
152 153
153 - private boolean isArpReqForRouter(DeviceId deviceId, ARP arpRequest) { 154 + private boolean isArpForRouter(DeviceId deviceId, ARP arpMsg) {
154 - Set<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId); 155 + Ip4Address targetProtocolAddress = Ip4Address.valueOf(
155 - if (gatewayIpAddresses != null) { 156 + arpMsg.getTargetProtocolAddress());
156 - Ip4Address targetProtocolAddress = Ip4Address.valueOf(arpRequest 157 + Set<Ip4Address> gatewayIpAddresses = null;
157 - .getTargetProtocolAddress()); 158 + try {
158 - if (gatewayIpAddresses.contains(targetProtocolAddress)) { 159 + if (targetProtocolAddress.equals(config.getRouterIp(deviceId))) {
159 return true; 160 return true;
160 } 161 }
162 + gatewayIpAddresses = config.getPortIPs(deviceId);
163 + } catch (DeviceConfigNotFoundException e) {
164 + log.warn(e.getMessage() + " Aborting check for router IP in processing arp");
165 + }
166 + if (gatewayIpAddresses != null &&
167 + gatewayIpAddresses.contains(targetProtocolAddress)) {
168 + return true;
161 } 169 }
162 return false; 170 return false;
163 } 171 }
......
...@@ -88,10 +88,10 @@ public class IcmpHandler { ...@@ -88,10 +88,10 @@ public class IcmpHandler {
88 (destinationAddress.equals(routerIpAddress) || 88 (destinationAddress.equals(routerIpAddress) ||
89 gatewayIpAddresses.contains(destinationAddress))) { 89 gatewayIpAddresses.contains(destinationAddress))) {
90 sendICMPResponse(ethernet, connectPoint); 90 sendICMPResponse(ethernet, connectPoint);
91 - // TODO: do we need to set the flow rule again ??
92 91
93 // ICMP for any known host 92 // ICMP for any known host
94 } else if (!srManager.hostService.getHostsByIp(destinationAddress).isEmpty()) { 93 } else if (!srManager.hostService.getHostsByIp(destinationAddress).isEmpty()) {
94 + // TODO: known host packet should not be coming to controller - resend flows?
95 srManager.ipHandler.forwardPackets(deviceId, destinationAddress); 95 srManager.ipHandler.forwardPackets(deviceId, destinationAddress);
96 96
97 // ICMP for an unknown host in the subnet of the router 97 // ICMP for an unknown host in the subnet of the router
......
...@@ -98,7 +98,7 @@ public class IpHandler { ...@@ -98,7 +98,7 @@ public class IpHandler {
98 */ 98 */
99 public void addToPacketBuffer(IPv4 ipPacket) { 99 public void addToPacketBuffer(IPv4 ipPacket) {
100 100
101 - // Better not buffer TPC packets due to out-of-order packet transfer 101 + // Better not buffer TCP packets due to out-of-order packet transfer
102 if (ipPacket.getProtocol() == IPv4.PROTOCOL_TCP) { 102 if (ipPacket.getProtocol() == IPv4.PROTOCOL_TCP) {
103 return; 103 return;
104 } 104 }
......
...@@ -147,20 +147,34 @@ public class RoutingRulePopulator { ...@@ -147,20 +147,34 @@ public class RoutingRulePopulator {
147 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder(); 147 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
148 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder(); 148 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
149 149
150 - sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, IpPrefix.MAX_INET_MASK_LENGTH));
151 sbuilder.matchEthType(Ethernet.TYPE_IPV4); 150 sbuilder.matchEthType(Ethernet.TYPE_IPV4);
151 + sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, IpPrefix.MAX_INET_MASK_LENGTH));
152 + TrafficSelector selector = sbuilder.build();
152 153
153 tbuilder.deferred() 154 tbuilder.deferred()
154 .setEthDst(hostMac) 155 .setEthDst(hostMac)
155 .setEthSrc(deviceMac) 156 .setEthSrc(deviceMac)
156 .setOutput(outPort); 157 .setOutput(outPort);
157 -
158 TrafficTreatment treatment = tbuilder.build(); 158 TrafficTreatment treatment = tbuilder.build();
159 - TrafficSelector selector = sbuilder.build(); 159 +
160 + // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
161 + // for switch pipelines that need it, provide outgoing vlan as metadata
162 + VlanId outvlan = null;
163 + Ip4Prefix subnet = srManager.deviceConfiguration.getPortSubnet(deviceId, outPort);
164 + if (subnet == null) {
165 + outvlan = VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET);
166 + } else {
167 + outvlan = srManager.getSubnetAssignedVlanId(deviceId, subnet);
168 + }
169 + TrafficSelector meta = DefaultTrafficSelector.builder()
170 + .matchVlanId(outvlan).build();
171 + int portNextObjId = srManager.getPortNextObjectiveId(deviceId, outPort,
172 + treatment, meta);
160 173
161 return DefaultForwardingObjective.builder() 174 return DefaultForwardingObjective.builder()
175 + .withSelector(selector)
176 + .nextStep(portNextObjId)
162 .fromApp(srManager.appId).makePermanent() 177 .fromApp(srManager.appId).makePermanent()
163 - .withSelector(selector).withTreatment(treatment)
164 .withPriority(100).withFlag(ForwardingObjective.Flag.SPECIFIC); 178 .withPriority(100).withFlag(ForwardingObjective.Flag.SPECIFIC);
165 } 179 }
166 180
...@@ -454,7 +468,7 @@ public class RoutingRulePopulator { ...@@ -454,7 +468,7 @@ public class RoutingRulePopulator {
454 if (srManager.mastershipService.isLocalMaster(deviceId)) { 468 if (srManager.mastershipService.isLocalMaster(deviceId)) {
455 TrafficTreatment tt = DefaultTrafficTreatment.builder() 469 TrafficTreatment tt = DefaultTrafficTreatment.builder()
456 .pushVlan().setVlanId(assignedVlan).build(); 470 .pushVlan().setVlanId(assignedVlan).build();
457 - fob.setMeta(tt); 471 + fob.withMeta(tt);
458 } 472 }
459 fob.permit().fromApp(srManager.appId); 473 fob.permit().fromApp(srManager.appId);
460 srManager.flowObjectiveService. 474 srManager.flowObjectiveService.
...@@ -559,6 +573,12 @@ public class RoutingRulePopulator { ...@@ -559,6 +573,12 @@ public class RoutingRulePopulator {
559 int nextId = srManager.getSubnetNextObjectiveId(deviceId, subnet); 573 int nextId = srManager.getSubnetNextObjectiveId(deviceId, subnet);
560 VlanId vlanId = srManager.getSubnetAssignedVlanId(deviceId, subnet); 574 VlanId vlanId = srManager.getSubnetAssignedVlanId(deviceId, subnet);
561 575
576 + if (nextId < 0 || vlanId == null) {
577 + log.error("Cannot install subnet broadcast rule in dev:{} due"
578 + + "to vlanId:{} or nextId:{}", vlanId, nextId);
579 + return;
580 + }
581 +
562 /* Driver should treat objective with MacAddress.NONE as the 582 /* Driver should treat objective with MacAddress.NONE as the
563 * subnet broadcast rule 583 * subnet broadcast rule
564 */ 584 */
......
...@@ -57,6 +57,7 @@ import org.onosproject.segmentrouting.config.SegmentRoutingConfig; ...@@ -57,6 +57,7 @@ import org.onosproject.segmentrouting.config.SegmentRoutingConfig;
57 import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler; 57 import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
58 import org.onosproject.segmentrouting.grouphandler.NeighborSet; 58 import org.onosproject.segmentrouting.grouphandler.NeighborSet;
59 import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey; 59 import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
60 +import org.onosproject.segmentrouting.grouphandler.PortNextObjectiveStoreKey;
60 import org.onosproject.mastership.MastershipService; 61 import org.onosproject.mastership.MastershipService;
61 import org.onosproject.net.Device; 62 import org.onosproject.net.Device;
62 import org.onosproject.net.DeviceId; 63 import org.onosproject.net.DeviceId;
...@@ -97,7 +98,6 @@ import java.util.concurrent.ScheduledExecutorService; ...@@ -97,7 +98,6 @@ import java.util.concurrent.ScheduledExecutorService;
97 import java.util.concurrent.ScheduledFuture; 98 import java.util.concurrent.ScheduledFuture;
98 import java.util.concurrent.TimeUnit; 99 import java.util.concurrent.TimeUnit;
99 100
100 -@SuppressWarnings("ALL")
101 @Service 101 @Service
102 @Component(immediate = true) 102 @Component(immediate = true)
103 public class SegmentRoutingManager implements SegmentRoutingService { 103 public class SegmentRoutingManager implements SegmentRoutingService {
...@@ -150,21 +150,27 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -150,21 +150,27 @@ public class SegmentRoutingManager implements SegmentRoutingService {
150 private ScheduledExecutorService executorService = Executors 150 private ScheduledExecutorService executorService = Executors
151 .newScheduledThreadPool(1); 151 .newScheduledThreadPool(1);
152 152
153 + @SuppressWarnings("unused")
153 private static ScheduledFuture<?> eventHandlerFuture = null; 154 private static ScheduledFuture<?> eventHandlerFuture = null;
155 + @SuppressWarnings("rawtypes")
154 private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>(); 156 private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
155 private Map<DeviceId, DefaultGroupHandler> groupHandlerMap = 157 private Map<DeviceId, DefaultGroupHandler> groupHandlerMap =
156 new ConcurrentHashMap<DeviceId, DefaultGroupHandler>(); 158 new ConcurrentHashMap<DeviceId, DefaultGroupHandler>();
157 // Per device next objective ID store with (device id + neighbor set) as key 159 // Per device next objective ID store with (device id + neighbor set) as key
158 private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer> 160 private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
159 nsNextObjStore = null; 161 nsNextObjStore = null;
162 + // Per device next objective ID store with (device id + subnet) as key
160 private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer> 163 private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
161 subnetNextObjStore = null; 164 subnetNextObjStore = null;
162 - private EventuallyConsistentMap<String, Tunnel> tunnelStore = null; 165 + // Per device next objective ID store with (device id + port) as key
163 - private EventuallyConsistentMap<String, Policy> policyStore = null; 166 + private EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
167 + portNextObjStore = null;
164 // Per device, per-subnet assigned-vlans store, with (device id + subnet 168 // Per device, per-subnet assigned-vlans store, with (device id + subnet
165 // IPv4 prefix) as key 169 // IPv4 prefix) as key
166 private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId> 170 private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
167 subnetVidStore = null; 171 subnetVidStore = null;
172 + private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
173 + private EventuallyConsistentMap<String, Policy> policyStore = null;
168 174
169 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 175 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
170 protected StorageService storageService; 176 protected StorageService storageService;
...@@ -175,6 +181,7 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -175,6 +181,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
175 private final InternalConfigListener cfgListener = 181 private final InternalConfigListener cfgListener =
176 new InternalConfigListener(this); 182 new InternalConfigListener(this);
177 183
184 + @SuppressWarnings({ "unchecked", "rawtypes" })
178 private final ConfigFactory cfgFactory = 185 private final ConfigFactory cfgFactory =
179 new ConfigFactory(SubjectFactories.DEVICE_SUBJECT_FACTORY, 186 new ConfigFactory(SubjectFactories.DEVICE_SUBJECT_FACTORY,
180 SegmentRoutingConfig.class, 187 SegmentRoutingConfig.class,
...@@ -228,7 +235,6 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -228,7 +235,6 @@ public class SegmentRoutingManager implements SegmentRoutingService {
228 log.debug("Creating EC map nsnextobjectivestore"); 235 log.debug("Creating EC map nsnextobjectivestore");
229 EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer> 236 EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
230 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder(); 237 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
231 -
232 nsNextObjStore = nsNextObjMapBuilder 238 nsNextObjStore = nsNextObjMapBuilder
233 .withName("nsnextobjectivestore") 239 .withName("nsnextobjectivestore")
234 .withSerializer(kryoBuilder) 240 .withSerializer(kryoBuilder)
...@@ -239,16 +245,23 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -239,16 +245,23 @@ public class SegmentRoutingManager implements SegmentRoutingService {
239 log.debug("Creating EC map subnetnextobjectivestore"); 245 log.debug("Creating EC map subnetnextobjectivestore");
240 EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer> 246 EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
241 subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder(); 247 subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
242 -
243 subnetNextObjStore = subnetNextObjMapBuilder 248 subnetNextObjStore = subnetNextObjMapBuilder
244 .withName("subnetnextobjectivestore") 249 .withName("subnetnextobjectivestore")
245 .withSerializer(kryoBuilder) 250 .withSerializer(kryoBuilder)
246 .withTimestampProvider((k, v) -> new WallClockTimestamp()) 251 .withTimestampProvider((k, v) -> new WallClockTimestamp())
247 .build(); 252 .build();
248 253
254 + log.debug("Creating EC map subnetnextobjectivestore");
255 + EventuallyConsistentMapBuilder<PortNextObjectiveStoreKey, Integer>
256 + portNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
257 + portNextObjStore = portNextObjMapBuilder
258 + .withName("portnextobjectivestore")
259 + .withSerializer(kryoBuilder)
260 + .withTimestampProvider((k, v) -> new WallClockTimestamp())
261 + .build();
262 +
249 EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder = 263 EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
250 storageService.eventuallyConsistentMapBuilder(); 264 storageService.eventuallyConsistentMapBuilder();
251 -
252 tunnelStore = tunnelMapBuilder 265 tunnelStore = tunnelMapBuilder
253 .withName("tunnelstore") 266 .withName("tunnelstore")
254 .withSerializer(kryoBuilder) 267 .withSerializer(kryoBuilder)
...@@ -257,7 +270,6 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -257,7 +270,6 @@ public class SegmentRoutingManager implements SegmentRoutingService {
257 270
258 EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder = 271 EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
259 storageService.eventuallyConsistentMapBuilder(); 272 storageService.eventuallyConsistentMapBuilder();
260 -
261 policyStore = policyMapBuilder 273 policyStore = policyMapBuilder
262 .withName("policystore") 274 .withName("policystore")
263 .withSerializer(kryoBuilder) 275 .withSerializer(kryoBuilder)
...@@ -266,7 +278,6 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -266,7 +278,6 @@ public class SegmentRoutingManager implements SegmentRoutingService {
266 278
267 EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId> 279 EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
268 subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder(); 280 subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
269 -
270 subnetVidStore = subnetVidStoreMapBuilder 281 subnetVidStore = subnetVidStoreMapBuilder
271 .withName("subnetvidstore") 282 .withName("subnetvidstore")
272 .withSerializer(kryoBuilder) 283 .withSerializer(kryoBuilder)
...@@ -425,8 +436,7 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -425,8 +436,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
425 /** 436 /**
426 * Returns the next objective ID for the given NeighborSet. 437 * Returns the next objective ID for the given NeighborSet.
427 * If the nextObjective does not exist, a new one is created and 438 * If the nextObjective does not exist, a new one is created and
428 - * it's id is returned. 439 + * its id is returned.
429 - * TODO move the side-effect creation of a Next Objective into a new method
430 * 440 *
431 * @param deviceId Device ID 441 * @param deviceId Device ID
432 * @param ns NegighborSet 442 * @param ns NegighborSet
...@@ -441,18 +451,19 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -441,18 +451,19 @@ public class SegmentRoutingManager implements SegmentRoutingService {
441 return groupHandlerMap 451 return groupHandlerMap
442 .get(deviceId).getNextObjectiveId(ns, meta); 452 .get(deviceId).getNextObjectiveId(ns, meta);
443 } else { 453 } else {
444 - log.warn("getNextObjectiveId query in device {} not found", deviceId); 454 + log.warn("getNextObjectiveId query - groupHandler for device {} "
455 + + "not found", deviceId);
445 return -1; 456 return -1;
446 } 457 }
447 } 458 }
448 459
449 /** 460 /**
450 - * Returns the next objective ID for the Subnet given. If the nextObjectiveID does not exist, 461 + * Returns the next objective ID for the given subnet prefix. It is expected
451 - * a new one is created and returned. 462 + * that the next-objective has been pre-created from configuration.
452 * 463 *
453 * @param deviceId Device ID 464 * @param deviceId Device ID
454 * @param prefix Subnet 465 * @param prefix Subnet
455 - * @return next objective ID 466 + * @return next objective ID or -1 if it was not found
456 */ 467 */
457 public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) { 468 public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
458 if (groupHandlerMap.get(deviceId) != null) { 469 if (groupHandlerMap.get(deviceId) != null) {
...@@ -460,7 +471,33 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -460,7 +471,33 @@ public class SegmentRoutingManager implements SegmentRoutingService {
460 return groupHandlerMap 471 return groupHandlerMap
461 .get(deviceId).getSubnetNextObjectiveId(prefix); 472 .get(deviceId).getSubnetNextObjectiveId(prefix);
462 } else { 473 } else {
463 - log.warn("getSubnetNextObjectiveId query in device {} not found", deviceId); 474 + log.warn("getSubnetNextObjectiveId query - groupHandler for "
475 + + "device {} not found", deviceId);
476 + return -1;
477 + }
478 + }
479 +
480 + /**
481 + * Returns the next objective ID for the given portNumber, given the treatment.
482 + * There could be multiple different treatments to the same outport, which
483 + * would result in different objectives. If the next object
484 + * does not exist, a new one is created and its id is returned.
485 + *
486 + * @param deviceId Device ID
487 + * @param portNum port number on device for which NextObjective is queried
488 + * @param treatment the actions to apply on the packets (should include outport)
489 + * @param meta metadata passed into the creation of a Next Objective if necessary
490 + * @return next objective ID or -1 if it was not found
491 + */
492 + public int getPortNextObjectiveId(DeviceId deviceId, PortNumber portNum,
493 + TrafficTreatment treatment,
494 + TrafficSelector meta) {
495 + DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
496 + if (ghdlr != null) {
497 + return ghdlr.getPortNextObjectiveId(portNum, treatment, meta);
498 + } else {
499 + log.warn("getPortNextObjectiveId query - groupHandler for device {}"
500 + + " not found", deviceId);
464 return -1; 501 return -1;
465 } 502 }
466 } 503 }
...@@ -475,7 +512,7 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -475,7 +512,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
475 512
476 InboundPacket pkt = context.inPacket(); 513 InboundPacket pkt = context.inPacket();
477 Ethernet ethernet = pkt.parsed(); 514 Ethernet ethernet = pkt.parsed();
478 - 515 + log.trace("Rcvd pktin: {}", ethernet);
479 if (ethernet.getEtherType() == Ethernet.TYPE_ARP) { 516 if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
480 arpHandler.processPacketIn(pkt); 517 arpHandler.processPacketIn(pkt);
481 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) { 518 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
...@@ -517,6 +554,7 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -517,6 +554,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
517 } 554 }
518 } 555 }
519 556
557 + @SuppressWarnings("rawtypes")
520 private void scheduleEventHandlerIfNotScheduled(Event event) { 558 private void scheduleEventHandlerIfNotScheduled(Event event) {
521 synchronized (threadSchedulerLock) { 559 synchronized (threadSchedulerLock) {
522 eventQueue.add(event); 560 eventQueue.add(event);
...@@ -539,6 +577,7 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -539,6 +577,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
539 public void run() { 577 public void run() {
540 try { 578 try {
541 while (true) { 579 while (true) {
580 + @SuppressWarnings("rawtypes")
542 Event event = null; 581 Event event = null;
543 synchronized (threadSchedulerLock) { 582 synchronized (threadSchedulerLock) {
544 if (!eventQueue.isEmpty()) { 583 if (!eventQueue.isEmpty()) {
...@@ -647,7 +686,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -647,7 +686,8 @@ public class SegmentRoutingManager implements SegmentRoutingService {
647 linkService, 686 linkService,
648 flowObjectiveService, 687 flowObjectiveService,
649 nsNextObjStore, 688 nsNextObjStore,
650 - subnetNextObjStore); 689 + subnetNextObjStore,
690 + portNextObjStore);
651 } catch (DeviceConfigNotFoundException e) { 691 } catch (DeviceConfigNotFoundException e) {
652 log.warn(e.getMessage() + " Aborting processDeviceAdded."); 692 log.warn(e.getMessage() + " Aborting processDeviceAdded.");
653 return; 693 return;
...@@ -714,7 +754,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -714,7 +754,8 @@ public class SegmentRoutingManager implements SegmentRoutingService {
714 linkService, 754 linkService,
715 flowObjectiveService, 755 flowObjectiveService,
716 nsNextObjStore, 756 nsNextObjStore,
717 - subnetNextObjStore); 757 + subnetNextObjStore,
758 + portNextObjStore);
718 } catch (DeviceConfigNotFoundException e) { 759 } catch (DeviceConfigNotFoundException e) {
719 log.warn(e.getMessage() + " Aborting configureNetwork."); 760 log.warn(e.getMessage() + " Aborting configureNetwork.");
720 return; 761 return;
...@@ -766,7 +807,7 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -766,7 +807,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
766 807
767 // Populate bridging table entry 808 // Populate bridging table entry
768 ForwardingObjective.Builder fob = 809 ForwardingObjective.Builder fob =
769 - getForwardingObjectiveBuilder(mac, vlanId, port); 810 + getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
770 flowObjectiveService.forward(deviceId, fob.add( 811 flowObjectiveService.forward(deviceId, fob.add(
771 new BridgingTableObjectiveContext(mac, vlanId) 812 new BridgingTableObjectiveContext(mac, vlanId)
772 )); 813 ));
...@@ -782,20 +823,37 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -782,20 +823,37 @@ public class SegmentRoutingManager implements SegmentRoutingService {
782 } 823 }
783 824
784 private ForwardingObjective.Builder getForwardingObjectiveBuilder( 825 private ForwardingObjective.Builder getForwardingObjectiveBuilder(
785 - MacAddress mac, VlanId vlanId, PortNumber port) { 826 + DeviceId deviceId, MacAddress mac, VlanId vlanId,
827 + PortNumber outport) {
828 + // match rule
786 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder(); 829 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
787 sbuilder.matchEthDst(mac); 830 sbuilder.matchEthDst(mac);
788 sbuilder.matchVlanId(vlanId); 831 sbuilder.matchVlanId(vlanId);
789 832
790 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder(); 833 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
791 - // TODO Move popVlan from flow action to group action
792 tbuilder.immediate().popVlan(); 834 tbuilder.immediate().popVlan();
793 - tbuilder.immediate().setOutput(port); 835 + tbuilder.immediate().setOutput(outport);
836 +
837 + // for switch pipelines that need it, provide outgoing vlan as metadata
838 + VlanId outvlan = null;
839 + Ip4Prefix subnet = deviceConfiguration.getPortSubnet(deviceId, outport);
840 + if (subnet == null) {
841 + outvlan = VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET);
842 + } else {
843 + outvlan = getSubnetAssignedVlanId(deviceId, subnet);
844 + }
845 + TrafficSelector meta = DefaultTrafficSelector.builder()
846 + .matchVlanId(outvlan).build();
847 +
848 + // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
849 + int portNextObjId = getPortNextObjectiveId(deviceId, outport,
850 + tbuilder.build(),
851 + meta);
794 852
795 return DefaultForwardingObjective.builder() 853 return DefaultForwardingObjective.builder()
796 .withFlag(ForwardingObjective.Flag.SPECIFIC) 854 .withFlag(ForwardingObjective.Flag.SPECIFIC)
797 .withSelector(sbuilder.build()) 855 .withSelector(sbuilder.build())
798 - .withTreatment(tbuilder.build()) 856 + .nextStep(portNextObjId)
799 .withPriority(100) 857 .withPriority(100)
800 .fromApp(appId) 858 .fromApp(appId)
801 .makePermanent(); 859 .makePermanent();
...@@ -807,11 +865,13 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -807,11 +865,13 @@ public class SegmentRoutingManager implements SegmentRoutingService {
807 DeviceId deviceId = event.subject().location().deviceId(); 865 DeviceId deviceId = event.subject().location().deviceId();
808 PortNumber port = event.subject().location().port(); 866 PortNumber port = event.subject().location().port();
809 Set<IpAddress> ips = event.subject().ipAddresses(); 867 Set<IpAddress> ips = event.subject().ipAddresses();
810 - log.debug("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port); 868 + log.info("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
811 869
812 // Populate bridging table entry 870 // Populate bridging table entry
871 + log.debug("Populate L2 table entry for host {} at {}:{}",
872 + mac, deviceId, port);
813 ForwardingObjective.Builder fob = 873 ForwardingObjective.Builder fob =
814 - getForwardingObjectiveBuilder(mac, vlanId, port); 874 + getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
815 flowObjectiveService.forward(deviceId, fob.add( 875 flowObjectiveService.forward(deviceId, fob.add(
816 new BridgingTableObjectiveContext(mac, vlanId) 876 new BridgingTableObjectiveContext(mac, vlanId)
817 )); 877 ));
...@@ -835,7 +895,7 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -835,7 +895,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
835 895
836 // Revoke bridging table entry 896 // Revoke bridging table entry
837 ForwardingObjective.Builder fob = 897 ForwardingObjective.Builder fob =
838 - getForwardingObjectiveBuilder(mac, vlanId, port); 898 + getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
839 flowObjectiveService.forward(deviceId, fob.remove( 899 flowObjectiveService.forward(deviceId, fob.remove(
840 new BridgingTableObjectiveContext(mac, vlanId) 900 new BridgingTableObjectiveContext(mac, vlanId)
841 )); 901 ));
...@@ -863,7 +923,7 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -863,7 +923,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
863 923
864 // Revoke previous bridging table entry 924 // Revoke previous bridging table entry
865 ForwardingObjective.Builder prevFob = 925 ForwardingObjective.Builder prevFob =
866 - getForwardingObjectiveBuilder(mac, vlanId, prevPort); 926 + getForwardingObjectiveBuilder(prevDeviceId, mac, vlanId, prevPort);
867 flowObjectiveService.forward(prevDeviceId, prevFob.remove( 927 flowObjectiveService.forward(prevDeviceId, prevFob.remove(
868 new BridgingTableObjectiveContext(mac, vlanId) 928 new BridgingTableObjectiveContext(mac, vlanId)
869 )); 929 ));
...@@ -878,7 +938,7 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -878,7 +938,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
878 938
879 // Populate new bridging table entry 939 // Populate new bridging table entry
880 ForwardingObjective.Builder newFob = 940 ForwardingObjective.Builder newFob =
881 - getForwardingObjectiveBuilder(mac, vlanId, prevPort); 941 + getForwardingObjectiveBuilder(newDeviceId, mac, vlanId, newPort);
882 flowObjectiveService.forward(newDeviceId, newFob.add( 942 flowObjectiveService.forward(newDeviceId, newFob.add(
883 new BridgingTableObjectiveContext(mac, vlanId) 943 new BridgingTableObjectiveContext(mac, vlanId)
884 )); 944 ));
......
...@@ -56,9 +56,11 @@ public class DefaultEdgeGroupHandler extends DefaultGroupHandler { ...@@ -56,9 +56,11 @@ public class DefaultEdgeGroupHandler extends DefaultGroupHandler {
56 NeighborSetNextObjectiveStoreKey, 56 NeighborSetNextObjectiveStoreKey,
57 Integer> nsNextObjStore, 57 Integer> nsNextObjStore,
58 EventuallyConsistentMap<SubnetNextObjectiveStoreKey, 58 EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
59 - Integer> subnetNextObjStore) { 59 + Integer> subnetNextObjStore,
60 + EventuallyConsistentMap<PortNextObjectiveStoreKey,
61 + Integer> portNextObjStore) {
60 super(deviceId, appId, config, linkService, flowObjService, 62 super(deviceId, appId, config, linkService, flowObjService,
61 - nsNextObjStore, subnetNextObjStore); 63 + nsNextObjStore, subnetNextObjStore, portNextObjStore);
62 } 64 }
63 65
64 @Override 66 @Override
......
...@@ -80,6 +80,8 @@ public class DefaultGroupHandler { ...@@ -80,6 +80,8 @@ public class DefaultGroupHandler {
80 NeighborSetNextObjectiveStoreKey, Integer> nsNextObjStore = null; 80 NeighborSetNextObjectiveStoreKey, Integer> nsNextObjStore = null;
81 protected EventuallyConsistentMap< 81 protected EventuallyConsistentMap<
82 SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null; 82 SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null;
83 + protected EventuallyConsistentMap<
84 + PortNextObjectiveStoreKey, Integer> portNextObjStore = null;
83 85
84 protected KryoNamespace.Builder kryo = new KryoNamespace.Builder() 86 protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
85 .register(URI.class).register(HashSet.class) 87 .register(URI.class).register(HashSet.class)
...@@ -93,11 +95,12 @@ public class DefaultGroupHandler { ...@@ -93,11 +95,12 @@ public class DefaultGroupHandler {
93 DeviceProperties config, 95 DeviceProperties config,
94 LinkService linkService, 96 LinkService linkService,
95 FlowObjectiveService flowObjService, 97 FlowObjectiveService flowObjService,
96 - EventuallyConsistentMap< 98 + EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
97 - NeighborSetNextObjectiveStoreKey,
98 Integer> nsNextObjStore, 99 Integer> nsNextObjStore,
99 EventuallyConsistentMap<SubnetNextObjectiveStoreKey, 100 EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
100 - Integer> subnetNextObjStore) { 101 + Integer> subnetNextObjStore,
102 + EventuallyConsistentMap<PortNextObjectiveStoreKey,
103 + Integer> portNextObjStore) {
101 this.deviceId = checkNotNull(deviceId); 104 this.deviceId = checkNotNull(deviceId);
102 this.appId = checkNotNull(appId); 105 this.appId = checkNotNull(appId);
103 this.deviceConfig = checkNotNull(config); 106 this.deviceConfig = checkNotNull(config);
...@@ -114,6 +117,7 @@ public class DefaultGroupHandler { ...@@ -114,6 +117,7 @@ public class DefaultGroupHandler {
114 this.flowObjectiveService = flowObjService; 117 this.flowObjectiveService = flowObjService;
115 this.nsNextObjStore = nsNextObjStore; 118 this.nsNextObjStore = nsNextObjStore;
116 this.subnetNextObjStore = subnetNextObjStore; 119 this.subnetNextObjStore = subnetNextObjStore;
120 + this.portNextObjStore = portNextObjStore;
117 121
118 populateNeighborMaps(); 122 populateNeighborMaps();
119 } 123 }
...@@ -133,30 +137,34 @@ public class DefaultGroupHandler { ...@@ -133,30 +137,34 @@ public class DefaultGroupHandler {
133 * @throws DeviceConfigNotFoundException if the device configuration is not found 137 * @throws DeviceConfigNotFoundException if the device configuration is not found
134 * @return default group handler type 138 * @return default group handler type
135 */ 139 */
136 - public static DefaultGroupHandler createGroupHandler(DeviceId deviceId, 140 + public static DefaultGroupHandler createGroupHandler(
137 - ApplicationId appId, 141 + DeviceId deviceId,
138 - DeviceProperties config, 142 + ApplicationId appId,
139 - LinkService linkService, 143 + DeviceProperties config,
140 - FlowObjectiveService flowObjService, 144 + LinkService linkService,
141 - EventuallyConsistentMap< 145 + FlowObjectiveService flowObjService,
142 - NeighborSetNextObjectiveStoreKey, 146 + EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
143 - Integer> nsNextObjStore, 147 + Integer> nsNextObjStore,
144 - EventuallyConsistentMap<SubnetNextObjectiveStoreKey, 148 + EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
145 - Integer> subnetNextObjStore) 149 + Integer> subnetNextObjStore,
146 - throws DeviceConfigNotFoundException { 150 + EventuallyConsistentMap<PortNextObjectiveStoreKey,
151 + Integer> portNextObjStore)
152 + throws DeviceConfigNotFoundException {
147 // handle possible exception in the caller 153 // handle possible exception in the caller
148 if (config.isEdgeDevice(deviceId)) { 154 if (config.isEdgeDevice(deviceId)) {
149 return new DefaultEdgeGroupHandler(deviceId, appId, config, 155 return new DefaultEdgeGroupHandler(deviceId, appId, config,
150 linkService, 156 linkService,
151 flowObjService, 157 flowObjService,
152 nsNextObjStore, 158 nsNextObjStore,
153 - subnetNextObjStore); 159 + subnetNextObjStore,
160 + portNextObjStore);
154 } else { 161 } else {
155 return new DefaultTransitGroupHandler(deviceId, appId, config, 162 return new DefaultTransitGroupHandler(deviceId, appId, config,
156 linkService, 163 linkService,
157 flowObjService, 164 flowObjService,
158 nsNextObjStore, 165 nsNextObjStore,
159 - subnetNextObjStore); 166 + subnetNextObjStore,
167 + portNextObjStore);
160 } 168 }
161 } 169 }
162 170
...@@ -231,25 +239,21 @@ public class DefaultGroupHandler { ...@@ -231,25 +239,21 @@ public class DefaultGroupHandler {
231 239
232 Integer nextId = nsNextObjStore. 240 Integer nextId = nsNextObjStore.
233 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns)); 241 get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
234 - if (nextId != null) { 242 + if (nextId != null && isMaster) {
235 NextObjective.Builder nextObjBuilder = DefaultNextObjective 243 NextObjective.Builder nextObjBuilder = DefaultNextObjective
236 .builder().withId(nextId) 244 .builder().withId(nextId)
237 .withType(NextObjective.Type.HASHED).fromApp(appId); 245 .withType(NextObjective.Type.HASHED).fromApp(appId);
238 246
239 nextObjBuilder.addTreatment(tBuilder.build()); 247 nextObjBuilder.addTreatment(tBuilder.build());
240 -
241 log.info("**linkUp in device {}: Adding Bucket " 248 log.info("**linkUp in device {}: Adding Bucket "
242 - + "with Port {} to next object id {} and amIMaster:{}", 249 + + "with Port {} to next object id {}",
243 deviceId, 250 deviceId,
244 newLink.src().port(), 251 newLink.src().port(),
245 - nextId, isMaster); 252 + nextId);
246 - 253 + NextObjective nextObjective = nextObjBuilder.
247 - if (isMaster) { 254 + addToExisting(new SRNextObjectiveContext(deviceId));
248 - NextObjective nextObjective = nextObjBuilder. 255 + flowObjectiveService.next(deviceId, nextObjective);
249 - addToExisting(new SRNextObjectiveContext(deviceId)); 256 + } else if (isMaster) {
250 - flowObjectiveService.next(deviceId, nextObjective);
251 - }
252 - } else {
253 log.warn("linkUp in device {}, but global store has no record " 257 log.warn("linkUp in device {}, but global store has no record "
254 + "for neighbor-set {}", deviceId, ns); 258 + "for neighbor-set {}", deviceId, ns);
255 } 259 }
...@@ -331,8 +335,8 @@ public class DefaultGroupHandler { ...@@ -331,8 +335,8 @@ public class DefaultGroupHandler {
331 } 335 }
332 336
333 /** 337 /**
334 - * Returns the next objective associated with the neighborset. 338 + * Returns the next objective of type hashed associated with the neighborset.
335 - * If there is no next objective for this neighborset, this API 339 + * If there is no next objective for this neighborset, this method
336 * would create a next objective and return. Optionally metadata can be 340 * would create a next objective and return. Optionally metadata can be
337 * passed in for the creation of the next objective. 341 * passed in for the creation of the next objective.
338 * 342 *
...@@ -372,9 +376,10 @@ public class DefaultGroupHandler { ...@@ -372,9 +376,10 @@ public class DefaultGroupHandler {
372 } 376 }
373 377
374 /** 378 /**
375 - * Returns the next objective associated with the subnet. 379 + * Returns the next objective of type broadcast associated with the subnet,
376 - * If there is no next objective for this subnet, this API 380 + * or -1 if no such objective exists. Note that this method does NOT create
377 - * would create a next objective and return. 381 + * the next objective as a side-effect. It is expected that is objective is
382 + * created at startup from network configuration.
378 * 383 *
379 * @param prefix subnet information 384 * @param prefix subnet information
380 * @return int if found or -1 385 * @return int if found or -1
...@@ -387,6 +392,38 @@ public class DefaultGroupHandler { ...@@ -387,6 +392,38 @@ public class DefaultGroupHandler {
387 } 392 }
388 393
389 /** 394 /**
395 + * Returns the next objective of type simple associated with the port on the
396 + * device, given the treatment. Different treatments to the same port result
397 + * in different next objectives. If no such objective exists, this method
398 + * creates one and returns the id. Optionally metadata can be passed in for
399 + * the creation of the objective.
400 + *
401 + * @param portNum the port number for the simple next objective
402 + * @param treatment the actions to apply on the packets (should include outport)
403 + * @param meta optional metadata passed into the creation of the next objective
404 + * @return int if found or created, -1 if there are errors during the
405 + * creation of the next objective.
406 + */
407 + public int getPortNextObjectiveId(PortNumber portNum, TrafficTreatment treatment,
408 + TrafficSelector meta) {
409 + Integer nextId = portNextObjStore.
410 + get(new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
411 + if (nextId == null) {
412 + log.trace("getPortNextObjectiveId in device{}: Next objective id "
413 + + "not found for {} and {} creating", deviceId, portNum);
414 + createGroupFromPort(portNum, treatment, meta);
415 + nextId = portNextObjStore.get(
416 + new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
417 + if (nextId == null) {
418 + log.warn("getPortNextObjectiveId: unable to create next obj"
419 + + "for dev:{} port{}", deviceId, portNum);
420 + return -1;
421 + }
422 + }
423 + return nextId;
424 + }
425 +
426 + /**
390 * Checks if the next objective ID (group) for the neighbor set exists or not. 427 * Checks if the next objective ID (group) for the neighbor set exists or not.
391 * 428 *
392 * @param ns neighbor set to check 429 * @param ns neighbor set to check
...@@ -561,7 +598,7 @@ public class DefaultGroupHandler { ...@@ -561,7 +598,7 @@ public class DefaultGroupHandler {
561 } 598 }
562 } 599 }
563 if (meta != null) { 600 if (meta != null) {
564 - nextObjBuilder.setMeta(meta); 601 + nextObjBuilder.withMeta(meta);
565 } 602 }
566 NextObjective nextObj = nextObjBuilder. 603 NextObjective nextObj = nextObjBuilder.
567 add(new SRNextObjectiveContext(deviceId)); 604 add(new SRNextObjectiveContext(deviceId));
...@@ -574,7 +611,10 @@ public class DefaultGroupHandler { ...@@ -574,7 +611,10 @@ public class DefaultGroupHandler {
574 } 611 }
575 } 612 }
576 613
577 - 614 + /**
615 + * Creates broadcast groups for all ports in the same configured subnet.
616 + *
617 + */
578 public void createGroupsFromSubnetConfig() { 618 public void createGroupsFromSubnetConfig() {
579 Map<Ip4Prefix, List<PortNumber>> subnetPortMap = 619 Map<Ip4Prefix, List<PortNumber>> subnetPortMap =
580 this.deviceConfig.getSubnetPortsMap(this.deviceId); 620 this.deviceConfig.getSubnetPortsMap(this.deviceId);
...@@ -612,6 +652,37 @@ public class DefaultGroupHandler { ...@@ -612,6 +652,37 @@ public class DefaultGroupHandler {
612 }); 652 });
613 } 653 }
614 654
655 +
656 + /**
657 + * Create simple next objective for a single port. The treatments can include
658 + * all outgoing actions that need to happen on the packet.
659 + *
660 + * @param portNum the outgoing port on the device
661 + * @param treatment the actions to apply on the packets (should include outport)
662 + * @param meta optional data to pass to the driver
663 + */
664 + public void createGroupFromPort(PortNumber portNum, TrafficTreatment treatment,
665 + TrafficSelector meta) {
666 + int nextId = flowObjectiveService.allocateNextId();
667 + PortNextObjectiveStoreKey key = new PortNextObjectiveStoreKey(
668 + deviceId, portNum, treatment);
669 +
670 + NextObjective.Builder nextObjBuilder = DefaultNextObjective
671 + .builder().withId(nextId)
672 + .withType(NextObjective.Type.SIMPLE)
673 + .addTreatment(treatment)
674 + .fromApp(appId)
675 + .withMeta(meta);
676 +
677 + NextObjective nextObj = nextObjBuilder.add();
678 + flowObjectiveService.next(deviceId, nextObj);
679 + log.debug("createGroupFromPort: Submited next objective {} in device {} "
680 + + "for port {}", nextId, deviceId, portNum);
681 +
682 + portNextObjStore.put(key, nextId);
683 + }
684 +
685 +
615 public GroupKey getGroupKey(Object obj) { 686 public GroupKey getGroupKey(Object obj) {
616 return new DefaultGroupKey(kryo.build().serialize(obj)); 687 return new DefaultGroupKey(kryo.build().serialize(obj));
617 } 688 }
......
...@@ -50,9 +50,11 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler { ...@@ -50,9 +50,11 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler {
50 NeighborSetNextObjectiveStoreKey, 50 NeighborSetNextObjectiveStoreKey,
51 Integer> nsNextObjStore, 51 Integer> nsNextObjStore,
52 EventuallyConsistentMap<SubnetNextObjectiveStoreKey, 52 EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
53 - Integer> subnetNextObjStore) { 53 + Integer> subnetNextObjStore,
54 + EventuallyConsistentMap<PortNextObjectiveStoreKey,
55 + Integer> portNextObjStore) {
54 super(deviceId, appId, config, linkService, flowObjService, 56 super(deviceId, appId, config, linkService, flowObjService,
55 - nsNextObjStore, subnetNextObjStore); 57 + nsNextObjStore, subnetNextObjStore, portNextObjStore);
56 } 58 }
57 59
58 @Override 60 @Override
......
...@@ -68,9 +68,11 @@ public class PolicyGroupHandler extends DefaultGroupHandler { ...@@ -68,9 +68,11 @@ public class PolicyGroupHandler extends DefaultGroupHandler {
68 EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, 68 EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
69 Integer> nsNextObjStore, 69 Integer> nsNextObjStore,
70 EventuallyConsistentMap<SubnetNextObjectiveStoreKey, 70 EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
71 - Integer> subnetNextObjStore) { 71 + Integer> subnetNextObjStore,
72 + EventuallyConsistentMap<PortNextObjectiveStoreKey,
73 + Integer> portNextObjStore) {
72 super(deviceId, appId, config, linkService, flowObjService, 74 super(deviceId, appId, config, linkService, flowObjService,
73 - nsNextObjStore, subnetNextObjStore); 75 + nsNextObjStore, subnetNextObjStore, portNextObjStore);
74 } 76 }
75 77
76 public PolicyGroupIdentifier createPolicyGroupChain(String id, 78 public PolicyGroupIdentifier createPolicyGroupChain(String id,
......
1 +package org.onosproject.segmentrouting.grouphandler;
2 +
3 +import org.onosproject.net.DeviceId;
4 +import org.onosproject.net.PortNumber;
5 +import org.onosproject.net.flow.TrafficTreatment;
6 +
7 +import java.util.Objects;
8 +
9 +/**
10 + * Class definition of Key for Device/Port to NextObjective store. Since there
11 + * can be multiple next objectives to the same physical port, we differentiate
12 + * between them by including the treatment in the key.
13 + */
14 +public class PortNextObjectiveStoreKey {
15 + private final DeviceId deviceId;
16 + private final PortNumber portNum;
17 + private final TrafficTreatment treatment;
18 +
19 + public PortNextObjectiveStoreKey(DeviceId deviceId, PortNumber portNum,
20 + TrafficTreatment treatment) {
21 + this.deviceId = deviceId;
22 + this.portNum = portNum;
23 + this.treatment = treatment;
24 + }
25 +
26 + /**
27 + * Gets device id in this PortNextObjectiveStoreKey.
28 + *
29 + * @return device id
30 + */
31 + public DeviceId deviceId() {
32 + return deviceId;
33 + }
34 +
35 + /**
36 + * Gets port information in this PortNextObjectiveStoreKey.
37 + *
38 + * @return port information
39 + */
40 + public PortNumber portNumber() {
41 + return portNum;
42 + }
43 +
44 + /**
45 + * Gets treatment information in this PortNextObjectiveStoreKey.
46 + *
47 + * @return treatment information
48 + */
49 + public TrafficTreatment treatment() {
50 + return treatment;
51 + }
52 +
53 + @Override
54 + public boolean equals(Object o) {
55 + if (this == o) {
56 + return true;
57 + }
58 + if (!(o instanceof PortNextObjectiveStoreKey)) {
59 + return false;
60 + }
61 + PortNextObjectiveStoreKey that =
62 + (PortNextObjectiveStoreKey) o;
63 + return (Objects.equals(this.deviceId, that.deviceId) &&
64 + Objects.equals(this.portNum, that.portNum) &&
65 + Objects.equals(this.treatment, that.treatment));
66 + }
67 +
68 + @Override
69 + public int hashCode() {
70 + return Objects.hash(deviceId, portNum, treatment);
71 + }
72 +
73 + @Override
74 + public String toString() {
75 + return "Device: " + deviceId + " Port: " + portNum + " Treatment: " + treatment;
76 + }
77 +}
...@@ -119,7 +119,7 @@ public class GroupsListCommand extends AbstractShellCommand { ...@@ -119,7 +119,7 @@ public class GroupsListCommand extends AbstractShellCommand {
119 } 119 }
120 120
121 private void printGroups(DeviceId deviceId, List<Group> groups) { 121 private void printGroups(DeviceId deviceId, List<Group> groups) {
122 - print("deviceId=%s", deviceId); 122 + print("deviceId=%s, groupCount=%s", deviceId, groups.size());
123 for (Group group : groups) { 123 for (Group group : groups) {
124 print(FORMAT, Integer.toHexString(group.id().id()), group.state(), group.type(), 124 print(FORMAT, Integer.toHexString(group.id().id()), group.state(), group.type(),
125 group.bytes(), group.packets(), group.appId().name()); 125 group.bytes(), group.packets(), group.appId().name());
......
...@@ -196,7 +196,7 @@ public final class DefaultFilteringObjective implements FilteringObjective { ...@@ -196,7 +196,7 @@ public final class DefaultFilteringObjective implements FilteringObjective {
196 } 196 }
197 197
198 @Override 198 @Override
199 - public Builder setMeta(TrafficTreatment treatment) { 199 + public Builder withMeta(TrafficTreatment treatment) {
200 this.meta = treatment; 200 this.meta = treatment;
201 return this; 201 return this;
202 } 202 }
......
...@@ -181,7 +181,7 @@ public final class DefaultNextObjective implements NextObjective { ...@@ -181,7 +181,7 @@ public final class DefaultNextObjective implements NextObjective {
181 } 181 }
182 182
183 @Override 183 @Override
184 - public Builder setMeta(TrafficSelector meta) { 184 + public Builder withMeta(TrafficSelector meta) {
185 this.meta = meta; 185 this.meta = meta;
186 return this; 186 return this;
187 } 187 }
......
...@@ -133,7 +133,7 @@ public interface FilteringObjective extends Objective { ...@@ -133,7 +133,7 @@ public interface FilteringObjective extends Objective {
133 * @param treatment traffic treatment to use 133 * @param treatment traffic treatment to use
134 * @return a filtering builder 134 * @return a filtering builder
135 */ 135 */
136 - Builder setMeta(TrafficTreatment treatment); 136 + Builder withMeta(TrafficTreatment treatment);
137 137
138 /** 138 /**
139 * Assigns an application id. 139 * Assigns an application id.
......
...@@ -147,7 +147,7 @@ public interface NextObjective extends Objective { ...@@ -147,7 +147,7 @@ public interface NextObjective extends Objective {
147 * @param selector match conditions 147 * @param selector match conditions
148 * @return an objective builder 148 * @return an objective builder
149 */ 149 */
150 - Builder setMeta(TrafficSelector selector); 150 + Builder withMeta(TrafficSelector selector);
151 151
152 /** 152 /**
153 * Builds the next objective that will be added. 153 * Builds the next objective that will be added.
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
16 package org.onosproject.net.flowobjective.impl; 16 package org.onosproject.net.flowobjective.impl;
17 17
18 import com.google.common.collect.Maps; 18 import com.google.common.collect.Maps;
19 -import com.google.common.collect.Sets;
20 import org.apache.felix.scr.annotations.Activate; 19 import org.apache.felix.scr.annotations.Activate;
21 import org.apache.felix.scr.annotations.Component; 20 import org.apache.felix.scr.annotations.Component;
22 import org.apache.felix.scr.annotations.Deactivate; 21 import org.apache.felix.scr.annotations.Deactivate;
...@@ -53,9 +52,11 @@ import org.onosproject.net.group.GroupService; ...@@ -53,9 +52,11 @@ import org.onosproject.net.group.GroupService;
53 import org.slf4j.Logger; 52 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory; 53 import org.slf4j.LoggerFactory;
55 54
55 +import java.util.Collections;
56 import java.util.Map; 56 import java.util.Map;
57 import java.util.Objects; 57 import java.util.Objects;
58 import java.util.Set; 58 import java.util.Set;
59 +import java.util.concurrent.ConcurrentHashMap;
59 import java.util.concurrent.ExecutorService; 60 import java.util.concurrent.ExecutorService;
60 61
61 import static com.google.common.base.Preconditions.checkNotNull; 62 import static com.google.common.base.Preconditions.checkNotNull;
...@@ -228,8 +229,10 @@ public class FlowObjectiveManager implements FlowObjectiveService { ...@@ -228,8 +229,10 @@ public class FlowObjectiveManager implements FlowObjectiveService {
228 flowObjectiveStore.getNextGroup(fwd.nextId()) == null) { 229 flowObjectiveStore.getNextGroup(fwd.nextId()) == null) {
229 log.trace("Queuing forwarding objective for nextId {}", fwd.nextId()); 230 log.trace("Queuing forwarding objective for nextId {}", fwd.nextId());
230 // TODO: change to computeIfAbsent 231 // TODO: change to computeIfAbsent
231 - Set<PendingNext> pnext = pendingForwards.putIfAbsent(fwd.nextId(), 232 + Set<PendingNext> newset = Collections.newSetFromMap(
232 - Sets.newHashSet(new PendingNext(deviceId, fwd))); 233 + new ConcurrentHashMap<PendingNext, Boolean>());
234 + newset.add(new PendingNext(deviceId, fwd));
235 + Set<PendingNext> pnext = pendingForwards.putIfAbsent(fwd.nextId(), newset);
233 if (pnext != null) { 236 if (pnext != null) {
234 pnext.add(new PendingNext(deviceId, fwd)); 237 pnext.add(new PendingNext(deviceId, fwd));
235 } 238 }
......
...@@ -350,7 +350,7 @@ public class DistributedGroupStore ...@@ -350,7 +350,7 @@ public class DistributedGroupStore
350 // Check if a group is existing with the same key 350 // Check if a group is existing with the same key
351 Group existingGroup = getGroup(groupDesc.deviceId(), groupDesc.appCookie()); 351 Group existingGroup = getGroup(groupDesc.deviceId(), groupDesc.appCookie());
352 if (existingGroup != null) { 352 if (existingGroup != null) {
353 - log.warn("Group already exists with the same key {} in dev:{} with id:{}", 353 + log.warn("Group already exists with the same key {} in dev:{} with id:0x{}",
354 groupDesc.appCookie(), groupDesc.deviceId(), 354 groupDesc.appCookie(), groupDesc.deviceId(),
355 Integer.toHexString(existingGroup.id().id())); 355 Integer.toHexString(existingGroup.id().id()));
356 return; 356 return;
......
...@@ -39,7 +39,9 @@ import org.onosproject.net.flow.FlowRuleOperations; ...@@ -39,7 +39,9 @@ import org.onosproject.net.flow.FlowRuleOperations;
39 import org.onosproject.net.flow.FlowRuleOperationsContext; 39 import org.onosproject.net.flow.FlowRuleOperationsContext;
40 import org.onosproject.net.flow.TrafficSelector; 40 import org.onosproject.net.flow.TrafficSelector;
41 import org.onosproject.net.flow.TrafficTreatment; 41 import org.onosproject.net.flow.TrafficTreatment;
42 +import org.onosproject.net.flow.criteria.Criteria;
42 import org.onosproject.net.flow.criteria.Criterion; 43 import org.onosproject.net.flow.criteria.Criterion;
44 +import org.onosproject.net.flow.criteria.EthCriterion;
43 import org.onosproject.net.flow.criteria.EthTypeCriterion; 45 import org.onosproject.net.flow.criteria.EthTypeCriterion;
44 import org.onosproject.net.flow.criteria.IPCriterion; 46 import org.onosproject.net.flow.criteria.IPCriterion;
45 import org.onosproject.net.flow.criteria.MplsBosCriterion; 47 import org.onosproject.net.flow.criteria.MplsBosCriterion;
...@@ -62,6 +64,14 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { ...@@ -62,6 +64,14 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
62 64
63 private final Logger log = getLogger(getClass()); 65 private final Logger log = getLogger(getClass());
64 66
67 + /*
68 + * Cpqd emulation does not require the non-OF standard rules for
69 + * matching untagged packets.
70 + *
71 + * (non-Javadoc)
72 + * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter
73 + */
74 +
65 @Override 75 @Override
66 protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion, 76 protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion,
67 VlanIdCriterion vidCriterion, 77 VlanIdCriterion vidCriterion,
...@@ -122,16 +132,101 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { ...@@ -122,16 +132,101 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
122 return rules; 132 return rules;
123 } 133 }
124 134
135 + /*
136 + * Cpqd emulation does not handle vlan tags and mpls labels correctly.
137 + * Workaround requires popping off the VLAN tags in the TMAC table.
138 + *
139 + * (non-Javadoc)
140 + * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
141 + */
125 @Override 142 @Override
126 - protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) { 143 + protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion,
144 + EthCriterion ethCriterion,
145 + VlanIdCriterion vidCriterion,
146 + VlanId assignedVlan,
147 + ApplicationId applicationId) {
148 + //handling untagged packets via assigned VLAN
149 + if (vidCriterion.vlanId() == VlanId.NONE) {
150 + vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
151 + }
152 + // ofdpa cannot match on ALL portnumber, so we need to use separate
153 + // rules for each port.
154 + List<PortNumber> portnums = new ArrayList<PortNumber>();
155 + if (portCriterion.port() == PortNumber.ALL) {
156 + for (Port port : deviceService.getPorts(deviceId)) {
157 + if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
158 + portnums.add(port.number());
159 + }
160 + }
161 + } else {
162 + portnums.add(portCriterion.port());
163 + }
164 +
165 + List<FlowRule> rules = new ArrayList<FlowRule>();
166 + for (PortNumber pnum : portnums) {
167 + // for unicast IP packets
168 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
169 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
170 + selector.matchInPort(pnum);
171 + selector.matchVlanId(vidCriterion.vlanId());
172 + selector.matchEthType(Ethernet.TYPE_IPV4);
173 + selector.matchEthDst(ethCriterion.mac());
174 + /*
175 + * Note: CpqD switches do not handle MPLS-related operation properly
176 + * for a packet with VLAN tag. We pop VLAN here as a workaround.
177 + * Side effect: HostService learns redundant hosts with same MAC but
178 + * different VLAN. No known side effect on the network reachability.
179 + */
180 + treatment.popVlan();
181 + treatment.transition(UNICAST_ROUTING_TABLE);
182 + FlowRule rule = DefaultFlowRule.builder()
183 + .forDevice(deviceId)
184 + .withSelector(selector.build())
185 + .withTreatment(treatment.build())
186 + .withPriority(DEFAULT_PRIORITY)
187 + .fromApp(applicationId)
188 + .makePermanent()
189 + .forTable(TMAC_TABLE).build();
190 + rules.add(rule);
191 + //for MPLS packets
192 + selector = DefaultTrafficSelector.builder();
193 + treatment = DefaultTrafficTreatment.builder();
194 + selector.matchInPort(pnum);
195 + selector.matchVlanId(vidCriterion.vlanId());
196 + selector.matchEthType(Ethernet.MPLS_UNICAST);
197 + selector.matchEthDst(ethCriterion.mac());
198 + // workaround here again
199 + treatment.popVlan();
200 + treatment.transition(MPLS_TABLE_0);
201 + rule = DefaultFlowRule.builder()
202 + .forDevice(deviceId)
203 + .withSelector(selector.build())
204 + .withTreatment(treatment.build())
205 + .withPriority(DEFAULT_PRIORITY)
206 + .fromApp(applicationId)
207 + .makePermanent()
208 + .forTable(TMAC_TABLE).build();
209 + rules.add(rule);
210 + }
211 + return rules;
212 + }
213 +
214 + /*
215 + * Cpqd emulation allows MPLS ecmp.
216 + *
217 + * (non-Javadoc)
218 + * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
219 + */
220 + @Override
221 + protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
127 TrafficSelector selector = fwd.selector(); 222 TrafficSelector selector = fwd.selector();
128 EthTypeCriterion ethType = 223 EthTypeCriterion ethType =
129 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); 224 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
130 if ((ethType == null) || 225 if ((ethType == null) ||
131 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) && 226 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
132 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) { 227 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) {
133 - log.warn("processSpecific: Unsupported " 228 + log.warn("processSpecific: Unsupported forwarding objective criteria"
134 - + "forwarding objective criteraia"); 229 + + "ethType:{} in dev:{}", ethType, deviceId);
135 fail(fwd, ObjectiveError.UNSUPPORTED); 230 fail(fwd, ObjectiveError.UNSUPPORTED);
136 return Collections.emptySet(); 231 return Collections.emptySet();
137 } 232 }
...@@ -143,8 +238,8 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { ...@@ -143,8 +238,8 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
143 .matchIPDst(((IPCriterion) 238 .matchIPDst(((IPCriterion)
144 selector.getCriterion(Criterion.Type.IPV4_DST)).ip()); 239 selector.getCriterion(Criterion.Type.IPV4_DST)).ip());
145 forTableId = UNICAST_ROUTING_TABLE; 240 forTableId = UNICAST_ROUTING_TABLE;
146 - log.debug("processing IPv4 specific forwarding objective {} hash{} in dev:{}", 241 + log.debug("processing IPv4 specific forwarding objective {} -> next:{}"
147 - fwd.id(), fwd.hashCode(), deviceId); 242 + + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
148 } else { 243 } else {
149 filteredSelector 244 filteredSelector
150 .matchEthType(Ethernet.MPLS_UNICAST) 245 .matchEthType(Ethernet.MPLS_UNICAST)
...@@ -156,8 +251,8 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { ...@@ -156,8 +251,8 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
156 filteredSelector.matchMplsBos(bos.mplsBos()); 251 filteredSelector.matchMplsBos(bos.mplsBos());
157 } 252 }
158 forTableId = MPLS_TABLE_1; 253 forTableId = MPLS_TABLE_1;
159 - log.debug("processing MPLS specific forwarding objective {} hash:{} in dev {}", 254 + log.debug("processing MPLS specific forwarding objective {} -> next:{}"
160 - fwd.id(), fwd.hashCode(), deviceId); 255 + + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
161 } 256 }
162 257
163 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder(); 258 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
...@@ -197,7 +292,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { ...@@ -197,7 +292,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
197 return Collections.singletonList(ruleBuilder.build()); 292 return Collections.singletonList(ruleBuilder.build());
198 } 293 }
199 294
200 -
201 @Override 295 @Override
202 protected void initializePipeline() { 296 protected void initializePipeline() {
203 processPortTable(); 297 processPortTable();
...@@ -210,7 +304,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { ...@@ -210,7 +304,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
210 processAclTable(); 304 processAclTable();
211 } 305 }
212 306
213 - @Override
214 protected void processPortTable() { 307 protected void processPortTable() {
215 FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); 308 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
216 TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); 309 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
...@@ -239,7 +332,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { ...@@ -239,7 +332,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
239 })); 332 }));
240 } 333 }
241 334
242 - @Override
243 protected void processTmacTable() { 335 protected void processTmacTable() {
244 //table miss entry 336 //table miss entry
245 FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); 337 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
...@@ -270,7 +362,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { ...@@ -270,7 +362,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
270 })); 362 }));
271 } 363 }
272 364
273 - @Override
274 protected void processIpTable() { 365 protected void processIpTable() {
275 //table miss entry 366 //table miss entry
276 FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); 367 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
...@@ -278,6 +369,7 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { ...@@ -278,6 +369,7 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
278 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); 369 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
279 selector = DefaultTrafficSelector.builder(); 370 selector = DefaultTrafficSelector.builder();
280 treatment = DefaultTrafficTreatment.builder(); 371 treatment = DefaultTrafficTreatment.builder();
372 + treatment.deferred().setOutput(PortNumber.CONTROLLER);
281 treatment.transition(ACL_TABLE); 373 treatment.transition(ACL_TABLE);
282 FlowRule rule = DefaultFlowRule.builder() 374 FlowRule rule = DefaultFlowRule.builder()
283 .forDevice(deviceId) 375 .forDevice(deviceId)
...@@ -301,7 +393,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { ...@@ -301,7 +393,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
301 })); 393 }));
302 } 394 }
303 395
304 - @Override
305 protected void processMplsTable() { 396 protected void processMplsTable() {
306 //table miss entry 397 //table miss entry
307 FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); 398 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
...@@ -374,7 +465,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { ...@@ -374,7 +465,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
374 })); 465 }));
375 } 466 }
376 467
377 - @Override
378 protected void processAclTable() { 468 protected void processAclTable() {
379 //table miss entry - catch all to executed action-set 469 //table miss entry - catch all to executed action-set
380 FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); 470 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
......
...@@ -18,7 +18,6 @@ package org.onosproject.driver.pipeline; ...@@ -18,7 +18,6 @@ package org.onosproject.driver.pipeline;
18 import static org.onlab.util.Tools.groupedThreads; 18 import static org.onlab.util.Tools.groupedThreads;
19 import static org.slf4j.LoggerFactory.getLogger; 19 import static org.slf4j.LoggerFactory.getLogger;
20 20
21 -import java.nio.ByteBuffer;
22 import java.util.ArrayDeque; 21 import java.util.ArrayDeque;
23 import java.util.ArrayList; 22 import java.util.ArrayList;
24 import java.util.Collection; 23 import java.util.Collection;
...@@ -28,6 +27,7 @@ import java.util.List; ...@@ -28,6 +27,7 @@ import java.util.List;
28 import java.util.Map; 27 import java.util.Map;
29 import java.util.Set; 28 import java.util.Set;
30 import java.util.concurrent.ConcurrentHashMap; 29 import java.util.concurrent.ConcurrentHashMap;
30 +import java.util.concurrent.CopyOnWriteArrayList;
31 import java.util.concurrent.Executors; 31 import java.util.concurrent.Executors;
32 import java.util.concurrent.ScheduledExecutorService; 32 import java.util.concurrent.ScheduledExecutorService;
33 import java.util.concurrent.TimeUnit; 33 import java.util.concurrent.TimeUnit;
...@@ -35,14 +35,9 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -35,14 +35,9 @@ import java.util.concurrent.atomic.AtomicInteger;
35 import java.util.stream.Collectors; 35 import java.util.stream.Collectors;
36 36
37 import org.onlab.osgi.ServiceDirectory; 37 import org.onlab.osgi.ServiceDirectory;
38 -import org.onlab.packet.Data;
39 import org.onlab.packet.Ethernet; 38 import org.onlab.packet.Ethernet;
40 -import org.onlab.packet.IPv4;
41 -import org.onlab.packet.IpPrefix;
42 -import org.onlab.packet.MPLS;
43 import org.onlab.packet.MacAddress; 39 import org.onlab.packet.MacAddress;
44 import org.onlab.packet.MplsLabel; 40 import org.onlab.packet.MplsLabel;
45 -import org.onlab.packet.UDP;
46 import org.onlab.packet.VlanId; 41 import org.onlab.packet.VlanId;
47 import org.onlab.util.KryoNamespace; 42 import org.onlab.util.KryoNamespace;
48 import org.onosproject.core.ApplicationId; 43 import org.onosproject.core.ApplicationId;
...@@ -99,10 +94,6 @@ import org.onosproject.net.group.GroupEvent; ...@@ -99,10 +94,6 @@ import org.onosproject.net.group.GroupEvent;
99 import org.onosproject.net.group.GroupKey; 94 import org.onosproject.net.group.GroupKey;
100 import org.onosproject.net.group.GroupListener; 95 import org.onosproject.net.group.GroupListener;
101 import org.onosproject.net.group.GroupService; 96 import org.onosproject.net.group.GroupService;
102 -import org.onosproject.net.packet.DefaultOutboundPacket;
103 -import org.onosproject.net.packet.OutboundPacket;
104 -import org.onosproject.net.packet.PacketContext;
105 -import org.onosproject.net.packet.PacketProcessor;
106 import org.onosproject.net.packet.PacketService; 97 import org.onosproject.net.packet.PacketService;
107 import org.onosproject.store.serializers.KryoNamespaces; 98 import org.onosproject.store.serializers.KryoNamespaces;
108 import org.slf4j.Logger; 99 import org.slf4j.Logger;
...@@ -160,7 +151,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -160,7 +151,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
160 protected ApplicationId driverId; 151 protected ApplicationId driverId;
161 protected PacketService packetService; 152 protected PacketService packetService;
162 protected DeviceService deviceService; 153 protected DeviceService deviceService;
163 - private InternalPacketProcessor processor = new InternalPacketProcessor();
164 protected KryoNamespace appKryo = new KryoNamespace.Builder() 154 protected KryoNamespace appKryo = new KryoNamespace.Builder()
165 .register(KryoNamespaces.API) 155 .register(KryoNamespaces.API)
166 .register(GroupKey.class) 156 .register(GroupKey.class)
...@@ -170,7 +160,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -170,7 +160,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
170 .register(ArrayDeque.class) 160 .register(ArrayDeque.class)
171 .build(); 161 .build();
172 162
173 - private Cache<GroupKey, OfdpaNextGroup> pendingNextObjectives; 163 + private Cache<GroupKey, List<OfdpaNextGroup>> pendingNextObjectives;
174 private ConcurrentHashMap<GroupKey, Set<GroupChainElem>> pendingGroups; 164 private ConcurrentHashMap<GroupKey, Set<GroupChainElem>> pendingGroups;
175 165
176 private ScheduledExecutorService groupChecker = 166 private ScheduledExecutorService groupChecker =
...@@ -196,10 +186,12 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -196,10 +186,12 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
196 pendingNextObjectives = CacheBuilder.newBuilder() 186 pendingNextObjectives = CacheBuilder.newBuilder()
197 .expireAfterWrite(20, TimeUnit.SECONDS) 187 .expireAfterWrite(20, TimeUnit.SECONDS)
198 .removalListener(( 188 .removalListener((
199 - RemovalNotification<GroupKey, OfdpaNextGroup> notification) -> { 189 + RemovalNotification<GroupKey, List<OfdpaNextGroup>> notification) -> {
200 if (notification.getCause() == RemovalCause.EXPIRED) { 190 if (notification.getCause() == RemovalCause.EXPIRED) {
201 - fail(notification.getValue().nextObjective(), 191 + notification.getValue().forEach(ofdpaNextGrp ->
202 - ObjectiveError.GROUPINSTALLATIONFAILED); 192 + fail(ofdpaNextGrp.nextObj,
193 + ObjectiveError.GROUPINSTALLATIONFAILED));
194 +
203 } 195 }
204 }).build(); 196 }).build();
205 197
...@@ -212,7 +204,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -212,7 +204,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
212 flowObjectiveStore = context.store(); 204 flowObjectiveStore = context.store();
213 packetService = serviceDirectory.get(PacketService.class); 205 packetService = serviceDirectory.get(PacketService.class);
214 deviceService = serviceDirectory.get(DeviceService.class); 206 deviceService = serviceDirectory.get(DeviceService.class);
215 - packetService.addProcessor(processor, PacketProcessor.director(2));
216 groupService.addListener(new InnerGroupListener()); 207 groupService.addListener(new InnerGroupListener());
217 208
218 driverId = coreService.registerApplication( 209 driverId = coreService.registerApplication(
...@@ -271,7 +262,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -271,7 +262,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
271 log.warn("Unknown forwarding type {}", fwd.op()); 262 log.warn("Unknown forwarding type {}", fwd.op());
272 } 263 }
273 264
274 -
275 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() { 265 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
276 @Override 266 @Override
277 public void onSuccess(FlowRuleOperations ops) { 267 public void onSuccess(FlowRuleOperations ops) {
...@@ -283,7 +273,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -283,7 +273,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
283 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED); 273 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
284 } 274 }
285 })); 275 }));
286 -
287 } 276 }
288 277
289 @Override 278 @Override
...@@ -697,17 +686,57 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -697,17 +686,57 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
697 * returned if there is an issue in processing the objective. 686 * returned if there is an issue in processing the objective.
698 */ 687 */
699 protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) { 688 protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
700 - TrafficSelector selector = fwd.selector(); 689 + log.trace("Processing specific fwd objective:{} in dev:{} with next:{}",
701 - EthTypeCriterion ethType = 690 + fwd.id(), deviceId, fwd.nextId());
702 - (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); 691 + boolean isEthTypeObj = isSupportedEthTypeObjective(fwd);
703 - if ((ethType == null) || 692 + boolean isEthDstObj = isSupportedEthDstObjective(fwd);
704 - (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) && 693 +
705 - (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) { 694 + if (isEthTypeObj) {
706 - log.warn("processSpecific: Unsupported " 695 + return processEthTypeSpecific(fwd);
707 - + "forwarding objective criteraia"); 696 + } else if (isEthDstObj) {
697 + return processEthDstSpecific(fwd);
698 + } else {
699 + log.warn("processSpecific: Unsupported forwarding objective "
700 + + "criteria fwd:{} in dev:{}", fwd.nextId(), deviceId);
708 fail(fwd, ObjectiveError.UNSUPPORTED); 701 fail(fwd, ObjectiveError.UNSUPPORTED);
709 return Collections.emptySet(); 702 return Collections.emptySet();
710 } 703 }
704 + }
705 +
706 + private boolean isSupportedEthTypeObjective(ForwardingObjective fwd) {
707 + TrafficSelector selector = fwd.selector();
708 + EthTypeCriterion ethType = (EthTypeCriterion) selector
709 + .getCriterion(Criterion.Type.ETH_TYPE);
710 + if ((ethType == null) ||
711 + ((ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
712 + (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST))) {
713 + return false;
714 + }
715 + return true;
716 + }
717 +
718 + private boolean isSupportedEthDstObjective(ForwardingObjective fwd) {
719 + TrafficSelector selector = fwd.selector();
720 + EthCriterion ethDst = (EthCriterion) selector
721 + .getCriterion(Criterion.Type.ETH_DST);
722 + VlanIdCriterion vlanId = (VlanIdCriterion) selector
723 + .getCriterion(Criterion.Type.VLAN_VID);
724 + if (ethDst == null && vlanId == null) {
725 + return false;
726 + }
727 + return true;
728 + }
729 +
730 + /**
731 + * Handles forwarding rules to the IP and MPLS tables.
732 + *
733 + * @param fwd the forwarding objective
734 + * @return A collection of flow rules, or an empty set
735 + */
736 + protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
737 + TrafficSelector selector = fwd.selector();
738 + EthTypeCriterion ethType =
739 + (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
711 740
712 int forTableId = -1; 741 int forTableId = -1;
713 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder(); 742 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
...@@ -716,8 +745,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -716,8 +745,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
716 .matchIPDst(((IPCriterion) 745 .matchIPDst(((IPCriterion)
717 selector.getCriterion(Criterion.Type.IPV4_DST)).ip()); 746 selector.getCriterion(Criterion.Type.IPV4_DST)).ip());
718 forTableId = UNICAST_ROUTING_TABLE; 747 forTableId = UNICAST_ROUTING_TABLE;
719 - log.debug("processing IPv4 specific forwarding objective {} in dev:{}", 748 + log.debug("processing IPv4 specific forwarding objective {} -> next:{}"
720 - fwd.id(), deviceId); 749 + + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
721 } else { 750 } else {
722 filteredSelector 751 filteredSelector
723 .matchEthType(Ethernet.MPLS_UNICAST) 752 .matchEthType(Ethernet.MPLS_UNICAST)
...@@ -729,8 +758,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -729,8 +758,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
729 filteredSelector.matchMplsBos(bos.mplsBos()); 758 filteredSelector.matchMplsBos(bos.mplsBos());
730 } 759 }
731 forTableId = MPLS_TABLE_1; 760 forTableId = MPLS_TABLE_1;
732 - log.debug("processing MPLS specific forwarding objective {} in dev {}", 761 + log.debug("processing MPLS specific forwarding objective {} -> next:{}"
733 - fwd.id(), deviceId); 762 + + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
734 } 763 }
735 764
736 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder(); 765 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
...@@ -754,6 +783,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -754,6 +783,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
754 // MPLS interface, or a MPLS SWAP (with-same) but that would 783 // MPLS interface, or a MPLS SWAP (with-same) but that would
755 // have to be handled in the next-objective. Also the pop-mpls 784 // have to be handled in the next-objective. Also the pop-mpls
756 // logic used here won't work in non-BoS case. 785 // logic used here won't work in non-BoS case.
786 + fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
757 return Collections.emptySet(); 787 return Collections.emptySet();
758 } 788 }
759 789
...@@ -762,7 +792,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -762,7 +792,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
762 // we only need the top level group's key to point the flow to it 792 // we only need the top level group's key to point the flow to it
763 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst()); 793 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
764 if (group == null) { 794 if (group == null) {
765 - log.warn("The group left!"); 795 + log.warn("Group with key:{} for next-id:{} not found in dev:{}",
796 + gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
766 fail(fwd, ObjectiveError.GROUPMISSING); 797 fail(fwd, ObjectiveError.GROUPMISSING);
767 return Collections.emptySet(); 798 return Collections.emptySet();
768 } 799 }
...@@ -786,6 +817,88 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -786,6 +817,88 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
786 return Collections.singletonList(ruleBuilder.build()); 817 return Collections.singletonList(ruleBuilder.build());
787 } 818 }
788 819
820 + /**
821 + * Handles forwarding rules to the L2 bridging table. Flow actions are not
822 + * allowed in the bridging table - instead we use L2 Interface group or
823 + * L2 flood group
824 + *
825 + * @param fwd the forwarding objective
826 + * @return A collection of flow rules, or an empty set
827 + */
828 + protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
829 + List<FlowRule> rules = new ArrayList<>();
830 +
831 + // Build filtered selector
832 + TrafficSelector selector = fwd.selector();
833 + EthCriterion ethCriterion = (EthCriterion) selector
834 + .getCriterion(Criterion.Type.ETH_DST);
835 + VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
836 + .getCriterion(Criterion.Type.VLAN_VID);
837 +
838 + if (vlanIdCriterion == null) {
839 + log.warn("Forwarding objective for bridging requires vlan. Not "
840 + + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
841 + fail(fwd, ObjectiveError.BADPARAMS);
842 + return Collections.emptySet();
843 + }
844 +
845 + TrafficSelector.Builder filteredSelectorBuilder =
846 + DefaultTrafficSelector.builder();
847 + // Do not match MacAddress for subnet broadcast entry
848 + if (!ethCriterion.mac().equals(MacAddress.NONE)) {
849 + filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
850 + log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
851 + fwd.id(), fwd.nextId(), deviceId);
852 + } else {
853 + log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
854 + + "in dev:{} for vlan:{}",
855 + fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
856 + }
857 + filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
858 + TrafficSelector filteredSelector = filteredSelectorBuilder.build();
859 +
860 + if (fwd.treatment() != null) {
861 + log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
862 + + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
863 + }
864 +
865 + TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
866 + if (fwd.nextId() != null) {
867 + NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
868 + if (next != null) {
869 + List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
870 + // we only need the top level group's key to point the flow to it
871 + Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
872 + if (group != null) {
873 + treatmentBuilder.deferred().group(group.id());
874 + } else {
875 + log.warn("Group with key:{} for next-id:{} not found in dev:{}",
876 + gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
877 + fail(fwd, ObjectiveError.GROUPMISSING);
878 + return Collections.emptySet();
879 + }
880 + }
881 + }
882 + treatmentBuilder.immediate().transition(ACL_TABLE);
883 + TrafficTreatment filteredTreatment = treatmentBuilder.build();
884 +
885 + // Build bridging table entries
886 + FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
887 + flowRuleBuilder.fromApp(fwd.appId())
888 + .withPriority(fwd.priority())
889 + .forDevice(deviceId)
890 + .withSelector(filteredSelector)
891 + .withTreatment(filteredTreatment)
892 + .forTable(BRIDGING_TABLE);
893 + if (fwd.permanent()) {
894 + flowRuleBuilder.makePermanent();
895 + } else {
896 + flowRuleBuilder.makeTemporary(fwd.timeout());
897 + }
898 + rules.add(flowRuleBuilder.build());
899 + return rules;
900 + }
901 +
789 private void pass(Objective obj) { 902 private void pass(Objective obj) {
790 if (obj.context().isPresent()) { 903 if (obj.context().isPresent()) {
791 obj.context().get().onSuccess(obj); 904 obj.context().get().onSuccess(obj);
...@@ -842,9 +955,26 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -842,9 +955,26 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
842 * @param nextObj the nextObjective of type SIMPLE 955 * @param nextObj the nextObjective of type SIMPLE
843 */ 956 */
844 private void processSimpleNextObjective(NextObjective nextObj) { 957 private void processSimpleNextObjective(NextObjective nextObj) {
845 - // break up simple next objective to GroupChain objects
846 TrafficTreatment treatment = nextObj.next().iterator().next(); 958 TrafficTreatment treatment = nextObj.next().iterator().next();
959 + // determine if plain L2 or L3->L2
960 + boolean plainL2 = true;
961 + for (Instruction ins : treatment.allInstructions()) {
962 + if (ins.type() == Instruction.Type.L2MODIFICATION) {
963 + L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
964 + if (l2ins.subtype() == L2SubType.ETH_DST ||
965 + l2ins.subtype() == L2SubType.ETH_SRC) {
966 + plainL2 = false;
967 + break;
968 + }
969 + }
970 + }
971 +
972 + if (plainL2) {
973 + createL2InterfaceGroup(nextObj);
974 + return;
975 + }
847 976
977 + // break up simple next objective to GroupChain objects
848 GroupInfo groupInfo = createL2L3Chain(treatment, nextObj.id(), 978 GroupInfo groupInfo = createL2L3Chain(treatment, nextObj.id(),
849 nextObj.appId(), false, 979 nextObj.appId(), false,
850 nextObj.meta()); 980 nextObj.meta());
...@@ -860,8 +990,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -860,8 +990,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
860 Collections.singletonList(gkeyChain), 990 Collections.singletonList(gkeyChain),
861 nextObj); 991 nextObj);
862 992
863 - // store l3groupkey with the ofdpaGroupChain for the nextObjective that depends on it 993 + // store l3groupkey with the ofdpaNextGroup for the nextObjective that depends on it
864 - pendingNextObjectives.put(groupInfo.outerGrpDesc.appCookie(), ofdpaGrp); 994 + updatePendingNextObjective(groupInfo.outerGrpDesc.appCookie(), ofdpaGrp);
865 995
866 // now we are ready to send the l2 groupDescription (inner), as all the stores 996 // now we are ready to send the l2 groupDescription (inner), as all the stores
867 // that will get async replies have been updated. By waiting to update 997 // that will get async replies have been updated. By waiting to update
...@@ -869,6 +999,98 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -869,6 +999,98 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
869 groupService.addGroup(groupInfo.innerGrpDesc); 999 groupService.addGroup(groupInfo.innerGrpDesc);
870 } 1000 }
871 1001
1002 + private void updatePendingNextObjective(GroupKey key, OfdpaNextGroup value) {
1003 + List<OfdpaNextGroup> nextList = new CopyOnWriteArrayList<OfdpaNextGroup>();
1004 + nextList.add(value);
1005 + List<OfdpaNextGroup> ret = pendingNextObjectives.asMap()
1006 + .putIfAbsent(key, nextList);
1007 + if (ret != null) {
1008 + ret.add(value);
1009 + }
1010 + }
1011 +
1012 + /**
1013 + * Creates a simple L2 Interface Group.
1014 + *
1015 + * @param nextObj the next Objective
1016 + */
1017 + private void createL2InterfaceGroup(NextObjective nextObj) {
1018 + // only allowed actions are vlan pop and outport
1019 + TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder();
1020 + PortNumber portNum = null;
1021 + for (Instruction ins : nextObj.next().iterator().next().allInstructions()) {
1022 + if (ins.type() == Instruction.Type.L2MODIFICATION) {
1023 + L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
1024 + switch (l2ins.subtype()) {
1025 + case VLAN_POP:
1026 + ttb.add(l2ins);
1027 + break;
1028 + default:
1029 + break;
1030 + }
1031 + } else if (ins.type() == Instruction.Type.OUTPUT) {
1032 + portNum = ((OutputInstruction) ins).port();
1033 + ttb.add(ins);
1034 + } else {
1035 + log.warn("Driver does not handle this type of TrafficTreatment"
1036 + + " instruction in simple nextObjectives: {}", ins.type());
1037 + }
1038 + }
1039 + //use the vlanid associated with the port
1040 + VlanId vlanid = port2Vlan.get(portNum);
1041 +
1042 + if (vlanid == null && nextObj.meta() != null) {
1043 + // use metadata vlan info if available
1044 + Criterion vidCriterion = nextObj.meta().getCriterion(Type.VLAN_VID);
1045 + if (vidCriterion != null) {
1046 + vlanid = ((VlanIdCriterion) vidCriterion).vlanId();
1047 + }
1048 + }
1049 +
1050 + if (vlanid == null) {
1051 + log.error("Driver cannot process an L2/L3 group chain without "
1052 + + "egress vlan information for dev: {} port:{}",
1053 + deviceId, portNum);
1054 + return;
1055 + }
1056 +
1057 + // assemble information for ofdpa l2interface group
1058 + Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum.toLong();
1059 + // a globally unique groupkey that is different for ports in the same devices
1060 + // but different for the same portnumber on different devices. Also different
1061 + // for the various group-types created out of the same next objective.
1062 + int l2gk = 0x0ffffff & (deviceId.hashCode() << 8 | (int) portNum.toLong());
1063 + final GroupKey l2groupkey = new DefaultGroupKey(appKryo.serialize(l2gk));
1064 +
1065 + // create group description for the l2interfacegroup
1066 + GroupBucket l2interfaceGroupBucket =
1067 + DefaultGroupBucket.createIndirectGroupBucket(ttb.build());
1068 + GroupDescription l2groupDescription =
1069 + new DefaultGroupDescription(
1070 + deviceId,
1071 + GroupDescription.Type.INDIRECT,
1072 + new GroupBuckets(Collections.singletonList(
1073 + l2interfaceGroupBucket)),
1074 + l2groupkey,
1075 + l2groupId,
1076 + nextObj.appId());
1077 + log.debug("Trying L2Interface: device:{} gid:{} gkey:{} nextId:{}",
1078 + deviceId, Integer.toHexString(l2groupId),
1079 + l2groupkey, nextObj.id());
1080 +
1081 + // create object for local and distributed storage
1082 + Deque<GroupKey> singleKey = new ArrayDeque<>();
1083 + singleKey.addFirst(l2groupkey);
1084 + OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(
1085 + Collections.singletonList(singleKey),
1086 + nextObj);
1087 +
1088 + // store l2groupkey for the nextObjective that depends on it
1089 + updatePendingNextObjective(l2groupkey, ofdpaGrp);
1090 + // send the group description to the group service
1091 + groupService.addGroup(l2groupDescription);
1092 + }
1093 +
872 /** 1094 /**
873 * Creates one of two possible group-chains from the treatment 1095 * Creates one of two possible group-chains from the treatment
874 * passed in. Depending on the MPLS boolean, this method either creates 1096 * passed in. Depending on the MPLS boolean, this method either creates
...@@ -895,6 +1117,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -895,6 +1117,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
895 TrafficTreatment.Builder innerTtb = DefaultTrafficTreatment.builder(); 1117 TrafficTreatment.Builder innerTtb = DefaultTrafficTreatment.builder();
896 VlanId vlanid = null; 1118 VlanId vlanid = null;
897 long portNum = 0; 1119 long portNum = 0;
1120 + boolean setVlan = false, popVlan = false;
898 for (Instruction ins : treatment.allInstructions()) { 1121 for (Instruction ins : treatment.allInstructions()) {
899 if (ins.type() == Instruction.Type.L2MODIFICATION) { 1122 if (ins.type() == Instruction.Type.L2MODIFICATION) {
900 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins; 1123 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
...@@ -908,9 +1131,11 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -908,9 +1131,11 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
908 case VLAN_ID: 1131 case VLAN_ID:
909 vlanid = ((ModVlanIdInstruction) l2ins).vlanId(); 1132 vlanid = ((ModVlanIdInstruction) l2ins).vlanId();
910 outerTtb.setVlanId(vlanid); 1133 outerTtb.setVlanId(vlanid);
1134 + setVlan = true;
911 break; 1135 break;
912 case VLAN_POP: 1136 case VLAN_POP:
913 innerTtb.popVlan(); 1137 innerTtb.popVlan();
1138 + popVlan = true;
914 break; 1139 break;
915 case DEC_MPLS_TTL: 1140 case DEC_MPLS_TTL:
916 case MPLS_LABEL: 1141 case MPLS_LABEL:
...@@ -935,12 +1160,11 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -935,12 +1160,11 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
935 vlanid = port2Vlan.get(PortNumber.portNumber(portNum)); 1160 vlanid = port2Vlan.get(PortNumber.portNumber(portNum));
936 } 1161 }
937 1162
938 - if (vlanid == null) { 1163 + if (vlanid == null && meta != null) {
939 - // use metadata 1164 + // use metadata if available
940 - for (Criterion metaCriterion : meta.criteria()) { 1165 + Criterion vidCriterion = meta.getCriterion(Type.VLAN_VID);
941 - if (metaCriterion.type() == Type.VLAN_VID) { 1166 + if (vidCriterion != null) {
942 - vlanid = ((VlanIdCriterion) metaCriterion).vlanId(); 1167 + vlanid = ((VlanIdCriterion) vidCriterion).vlanId();
943 - }
944 } 1168 }
945 } 1169 }
946 1170
...@@ -951,6 +1175,14 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -951,6 +1175,14 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
951 return null; 1175 return null;
952 } 1176 }
953 1177
1178 + if (!setVlan && !popVlan) {
1179 + // untagged outgoing port
1180 + TrafficTreatment.Builder temp = DefaultTrafficTreatment.builder();
1181 + temp.popVlan();
1182 + innerTtb.build().allInstructions().forEach(i -> temp.add(i));
1183 + innerTtb = temp;
1184 + }
1185 +
954 // assemble information for ofdpa l2interface group 1186 // assemble information for ofdpa l2interface group
955 Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum; 1187 Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum;
956 // a globally unique groupkey that is different for ports in the same devices 1188 // a globally unique groupkey that is different for ports in the same devices
...@@ -1077,6 +1309,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -1077,6 +1309,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
1077 } 1309 }
1078 1310
1079 // also ensure that all ports are in the same vlan 1311 // also ensure that all ports are in the same vlan
1312 + // XXX maybe HA issue here?
1080 VlanId thisvlanid = port2Vlan.get(portNum); 1313 VlanId thisvlanid = port2Vlan.get(portNum);
1081 if (vlanid == null) { 1314 if (vlanid == null) {
1082 vlanid = thisvlanid; 1315 vlanid = thisvlanid;
...@@ -1151,7 +1384,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -1151,7 +1384,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
1151 1384
1152 // store l2floodgroupkey with the ofdpaGroupChain for the nextObjective 1385 // store l2floodgroupkey with the ofdpaGroupChain for the nextObjective
1153 // that depends on it 1386 // that depends on it
1154 - pendingNextObjectives.put(l2floodgroupkey, ofdpaGrp); 1387 + updatePendingNextObjective(l2floodgroupkey, ofdpaGrp);
1155 1388
1156 for (GroupDescription l2intGrpDesc : l2interfaceGroupDescs) { 1389 for (GroupDescription l2intGrpDesc : l2interfaceGroupDescs) {
1157 // store all l2groupkeys with the groupChainElem for the l2floodgroup 1390 // store all l2groupkeys with the groupChainElem for the l2floodgroup
...@@ -1336,7 +1569,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -1336,7 +1569,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
1336 1569
1337 // store l3ecmpGroupKey with the ofdpaGroupChain for the nextObjective 1570 // store l3ecmpGroupKey with the ofdpaGroupChain for the nextObjective
1338 // that depends on it 1571 // that depends on it
1339 - pendingNextObjectives.put(l3ecmpGroupKey, ofdpaGrp); 1572 + updatePendingNextObjective(l3ecmpGroupKey, ofdpaGrp);
1340 1573
1341 log.debug("Trying L3ECMP: device:{} gid:{} gkey:{} nextId:{}", 1574 log.debug("Trying L3ECMP: device:{} gid:{} gkey:{} nextId:{}",
1342 deviceId, Integer.toHexString(l3ecmpGroupId), 1575 deviceId, Integer.toHexString(l3ecmpGroupId),
...@@ -1422,16 +1655,18 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -1422,16 +1655,18 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
1422 processGroupChain(gce); 1655 processGroupChain(gce);
1423 } 1656 }
1424 } else { 1657 } else {
1425 - OfdpaNextGroup obj = pendingNextObjectives.getIfPresent(key); 1658 + List<OfdpaNextGroup> objList = pendingNextObjectives.getIfPresent(key);
1426 - if (obj != null) { 1659 + if (objList != null) {
1427 - log.info("Group service processed group key {} in device:{}. "
1428 - + "Done implementing next objective: {} <<-->> gid:{}",
1429 - key, deviceId, obj.nextObjective().id(),
1430 - Integer.toHexString(groupService.getGroup(deviceId, key)
1431 - .givenGroupId()));
1432 - pass(obj.nextObjective());
1433 pendingNextObjectives.invalidate(key); 1660 pendingNextObjectives.invalidate(key);
1434 - flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj); 1661 + objList.forEach(obj -> {
1662 + log.info("Group service processed group key {} in device:{}. "
1663 + + "Done implementing next objective: {} <<-->> gid:{}",
1664 + key, deviceId, obj.nextObjective().id(),
1665 + Integer.toHexString(groupService.getGroup(deviceId, key)
1666 + .givenGroupId()));
1667 + pass(obj.nextObjective());
1668 + flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj);
1669 + });
1435 } 1670 }
1436 } 1671 }
1437 }); 1672 });
...@@ -1455,16 +1690,18 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -1455,16 +1690,18 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
1455 processGroupChain(gce); 1690 processGroupChain(gce);
1456 } 1691 }
1457 } else { 1692 } else {
1458 - OfdpaNextGroup obj = pendingNextObjectives.getIfPresent(key); 1693 + List<OfdpaNextGroup> objList = pendingNextObjectives.getIfPresent(key);
1459 - if (obj != null) { 1694 + if (objList != null) {
1460 - log.info("group ADDED with key {} in dev {}.. Done implementing next "
1461 - + "objective: {} <<-->> gid:{}",
1462 - key, deviceId, obj.nextObjective().id(),
1463 - Integer.toHexString(groupService.getGroup(deviceId, key)
1464 - .givenGroupId()));
1465 - pass(obj.nextObjective());
1466 pendingNextObjectives.invalidate(key); 1695 pendingNextObjectives.invalidate(key);
1467 - flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj); 1696 + objList.forEach(obj -> {
1697 + log.info("group ADDED with key {} in dev {}.. Done implementing next "
1698 + + "objective: {} <<-->> gid:{}",
1699 + key, deviceId, obj.nextObjective().id(),
1700 + Integer.toHexString(groupService.getGroup(deviceId, key)
1701 + .givenGroupId()));
1702 + pass(obj.nextObjective());
1703 + flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj);
1704 + });
1468 } 1705 }
1469 } 1706 }
1470 } 1707 }
...@@ -1550,418 +1787,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -1550,418 +1787,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
1550 " waiting-on-groups: " + waitOnGroups.get() + 1787 " waiting-on-groups: " + waitOnGroups.get() +
1551 " device: " + deviceId); 1788 " device: " + deviceId);
1552 } 1789 }
1553 -
1554 - }
1555 -
1556 - //////////////////////////////////////
1557 - // Test code to be used for future
1558 - // static-flow-pusher app
1559 - //////////////////////////////////////
1560 -
1561 - public void processStaticFlows() {
1562 - //processPortTable();
1563 - processGroupTable();
1564 - processVlanTable();
1565 - processTmacTable();
1566 - processIpTable();
1567 - //processMcastTable();
1568 - //processBridgingTable();
1569 - processAclTable();
1570 - sendPackets();
1571 - processMplsTable();
1572 - }
1573 -
1574 - protected void processGroupTable() {
1575 - TrafficTreatment.Builder act = DefaultTrafficTreatment.builder();
1576 -
1577 - act.popVlan(); // to send out untagged packets
1578 - act.setOutput(PortNumber.portNumber(24));
1579 - GroupBucket bucket =
1580 - DefaultGroupBucket.createIndirectGroupBucket(act.build());
1581 - final GroupKey groupkey = new DefaultGroupKey(appKryo.serialize(500));
1582 - Integer groupId = 0x00c80018; //l2 interface, vlan 200, port 24
1583 - GroupDescription groupDescription = new DefaultGroupDescription(deviceId,
1584 - GroupDescription.Type.INDIRECT,
1585 - new GroupBuckets(Collections.singletonList(bucket)),
1586 - groupkey,
1587 - groupId,
1588 - driverId);
1589 - groupService.addGroup(groupDescription);
1590 -
1591 - TrafficTreatment.Builder act2 = DefaultTrafficTreatment.builder();
1592 - act2.setOutput(PortNumber.portNumber(40));
1593 - GroupBucket bucket2 = DefaultGroupBucket.createIndirectGroupBucket(act2.build());
1594 - final GroupKey groupkey2 = new DefaultGroupKey(appKryo.serialize(502));
1595 - Integer groupId2 = 0x00c50028; //l2 interface, vlan 197, port 40
1596 - GroupDescription groupDescription2 = new DefaultGroupDescription(deviceId,
1597 - GroupDescription.Type.INDIRECT,
1598 - new GroupBuckets(Collections.singletonList(bucket2)),
1599 - groupkey2,
1600 - groupId2,
1601 - driverId);
1602 - groupService.addGroup(groupDescription2);
1603 -
1604 - while (groupService.getGroup(deviceId, groupkey2) == null) {
1605 - try {
1606 - Thread.sleep(500);
1607 - } catch (InterruptedException e) {
1608 - // TODO Auto-generated catch block
1609 - e.printStackTrace();
1610 - }
1611 - }
1612 -
1613 - //Now for L3 Unicast group
1614 - TrafficTreatment.Builder act3 = DefaultTrafficTreatment.builder();
1615 - act3.setEthDst(MacAddress.valueOf(0x2020));
1616 - act3.setEthSrc(MacAddress.valueOf(0x1010));
1617 - act3.setVlanId(VlanId.vlanId((short) 200));
1618 - act3.group(new DefaultGroupId(0x00c80018)); // point to L2 interface
1619 - // MPLS interface group - does not work for popping single label
1620 - //Integer secGroupId = MPLSINTERFACEMASK | 38; // 0x90000026
1621 - Integer groupId3 = L3UNICASTMASK | 1; // 0x20000001
1622 - GroupBucket bucket3 =
1623 - DefaultGroupBucket.createIndirectGroupBucket(act3.build());
1624 - final GroupKey groupkey3 = new DefaultGroupKey(appKryo.serialize(503));
1625 - GroupDescription groupDescription3 = new DefaultGroupDescription(deviceId,
1626 - GroupDescription.Type.INDIRECT,
1627 - new GroupBuckets(Collections.singletonList(bucket3)),
1628 - groupkey3,
1629 - groupId3,
1630 - driverId);
1631 - groupService.addGroup(groupDescription3);
1632 -
1633 - //Another L3 Unicast group
1634 - TrafficTreatment.Builder act4 = DefaultTrafficTreatment.builder();
1635 - act4.setEthDst(MacAddress.valueOf(0x3030));
1636 - act4.setEthSrc(MacAddress.valueOf(0x1010));
1637 - act4.setVlanId(VlanId.vlanId((short) 197));
1638 - act4.group(new DefaultGroupId(0x00c50028)); // point to L2 interface
1639 - Integer groupId4 = L3UNICASTMASK | 2; // 0x20000002
1640 - GroupBucket bucket4 =
1641 - DefaultGroupBucket.createIndirectGroupBucket(act4.build());
1642 - final GroupKey groupkey4 = new DefaultGroupKey(appKryo.serialize(504));
1643 - GroupDescription groupDescription4 = new DefaultGroupDescription(deviceId,
1644 - GroupDescription.Type.INDIRECT,
1645 - new GroupBuckets(Collections.singletonList(bucket4)),
1646 - groupkey4,
1647 - groupId4,
1648 - driverId);
1649 - groupService.addGroup(groupDescription4);
1650 -
1651 - while (groupService.getGroup(deviceId, groupkey4) == null) {
1652 - try {
1653 - Thread.sleep(500);
1654 - } catch (InterruptedException e) {
1655 - // TODO Auto-generated catch block
1656 - e.printStackTrace();
1657 - }
1658 - }
1659 -
1660 - // L3 ecmp group
1661 - TrafficTreatment.Builder act5 = DefaultTrafficTreatment.builder();
1662 - act5.group(new DefaultGroupId(0x20000001));
1663 - TrafficTreatment.Builder act6 = DefaultTrafficTreatment.builder();
1664 - act6.group(new DefaultGroupId(0x20000002));
1665 - GroupBucket buckete1 =
1666 - DefaultGroupBucket.createSelectGroupBucket(act5.build());
1667 - GroupBucket buckete2 =
1668 - DefaultGroupBucket.createSelectGroupBucket(act6.build());
1669 - List<GroupBucket> bktlist = new ArrayList<GroupBucket>();
1670 - bktlist.add(buckete1);
1671 - bktlist.add(buckete2);
1672 - final GroupKey groupkey5 = new DefaultGroupKey(appKryo.serialize(505));
1673 - Integer groupId5 = L3ECMPMASK | 5; // 0x70000005
1674 - GroupDescription groupDescription5 = new DefaultGroupDescription(deviceId,
1675 - GroupDescription.Type.SELECT,
1676 - new GroupBuckets(bktlist),
1677 - groupkey5,
1678 - groupId5,
1679 - driverId);
1680 - groupService.addGroup(groupDescription5);
1681 -
1682 -
1683 - }
1684 -
1685 - @SuppressWarnings("deprecation")
1686 - protected void processMplsTable() {
1687 - FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1688 - TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1689 - selector.matchEthType(Ethernet.MPLS_UNICAST);
1690 - selector.matchMplsLabel(MplsLabel.mplsLabel(0xff)); //255
1691 - selector.matchMplsBos(true);
1692 - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1693 - treatment.decMplsTtl(); // nw_ttl does not work
1694 - treatment.copyTtlIn();
1695 - treatment.popMpls(Ethernet.TYPE_IPV4);
1696 - treatment.deferred().group(new DefaultGroupId(0x20000001)); // point to L3 Unicast
1697 - //treatment.deferred().group(new DefaultGroupId(0x70000005)); // point to L3 ECMP
1698 - treatment.transition(ACL_TABLE);
1699 - FlowRule test = DefaultFlowRule.builder().forDevice(deviceId)
1700 - .withSelector(selector.build()).withTreatment(treatment.build())
1701 - .withPriority(DEFAULT_PRIORITY).fromApp(driverId).makePermanent()
1702 - .forTable(24).build();
1703 - ops = ops.add(test);
1704 -
1705 - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1706 - @Override
1707 - public void onSuccess(FlowRuleOperations ops) {
1708 - log.info("Initialized mpls table");
1709 - }
1710 -
1711 - @Override
1712 - public void onError(FlowRuleOperations ops) {
1713 - log.info("Failed to initialize mpls table");
1714 - }
1715 - }));
1716 -
1717 - }
1718 -
1719 - protected void processPortTable() {
1720 - FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1721 - TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1722 - selector.matchInPort(PortNumber.portNumber(0)); // should be maskable?
1723 - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1724 - treatment.transition(VLAN_TABLE);
1725 - FlowRule tmisse = DefaultFlowRule.builder()
1726 - .forDevice(deviceId)
1727 - .withSelector(selector.build())
1728 - .withTreatment(treatment.build())
1729 - .withPriority(LOWEST_PRIORITY)
1730 - .fromApp(driverId)
1731 - .makePermanent()
1732 - .forTable(PORT_TABLE).build();
1733 - ops = ops.add(tmisse);
1734 -
1735 - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1736 - @Override
1737 - public void onSuccess(FlowRuleOperations ops) {
1738 - log.info("Initialized port table");
1739 - }
1740 -
1741 - @Override
1742 - public void onError(FlowRuleOperations ops) {
1743 - log.info("Failed to initialize port table");
1744 - }
1745 - }));
1746 -
1747 - }
1748 -
1749 - private void processVlanTable() {
1750 - // Table miss entry is not required as ofdpa default is to drop
1751 - // In OF terms, the absence of a t.m.e. also implies drop
1752 - FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1753 - TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1754 - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1755 - selector.matchInPort(PortNumber.portNumber(12));
1756 - selector.matchVlanId(VlanId.vlanId((short) 100));
1757 - treatment.transition(TMAC_TABLE);
1758 - FlowRule rule = DefaultFlowRule.builder()
1759 - .forDevice(deviceId)
1760 - .withSelector(selector.build())
1761 - .withTreatment(treatment.build())
1762 - .withPriority(DEFAULT_PRIORITY)
1763 - .fromApp(driverId)
1764 - .makePermanent()
1765 - .forTable(VLAN_TABLE).build();
1766 - ops = ops.add(rule);
1767 - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1768 - @Override
1769 - public void onSuccess(FlowRuleOperations ops) {
1770 - log.info("Initialized vlan table");
1771 - }
1772 -
1773 - @Override
1774 - public void onError(FlowRuleOperations ops) {
1775 - log.info("Failed to initialize vlan table");
1776 - }
1777 - }));
1778 - }
1779 -
1780 - protected void processTmacTable() {
1781 - //table miss entry
1782 - FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1783 - TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1784 - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1785 - selector.matchInPort(PortNumber.portNumber(12));
1786 - selector.matchVlanId(VlanId.vlanId((short) 100));
1787 - selector.matchEthType(Ethernet.TYPE_IPV4);
1788 - selector.matchEthDst(MacAddress.valueOf("00:00:00:00:00:02"));
1789 - treatment.transition(UNICAST_ROUTING_TABLE);
1790 - FlowRule rule = DefaultFlowRule.builder()
1791 - .forDevice(deviceId)
1792 - .withSelector(selector.build())
1793 - .withTreatment(treatment.build())
1794 - .withPriority(DEFAULT_PRIORITY)
1795 - .fromApp(driverId)
1796 - .makePermanent()
1797 - .forTable(TMAC_TABLE).build();
1798 - ops = ops.add(rule);
1799 -
1800 - selector.matchEthType(Ethernet.MPLS_UNICAST);
1801 - treatment.transition(MPLS_TABLE_0);
1802 - FlowRule rulempls = DefaultFlowRule.builder()
1803 - .forDevice(deviceId)
1804 - .withSelector(selector.build())
1805 - .withTreatment(treatment.build())
1806 - .withPriority(DEFAULT_PRIORITY)
1807 - .fromApp(driverId)
1808 - .makePermanent()
1809 - .forTable(TMAC_TABLE).build();
1810 - ops = ops.add(rulempls);
1811 -
1812 - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1813 - @Override
1814 - public void onSuccess(FlowRuleOperations ops) {
1815 - log.info("Initialized tmac table");
1816 - }
1817 -
1818 - @Override
1819 - public void onError(FlowRuleOperations ops) {
1820 - log.info("Failed to initialize tmac table");
1821 - }
1822 - }));
1823 - }
1824 -
1825 - protected void processIpTable() {
1826 - //table miss entry
1827 - FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1828 - TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1829 - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1830 - selector.matchEthType(Ethernet.TYPE_IPV4);
1831 - selector.matchIPDst(IpPrefix.valueOf("2.0.0.0/16"));
1832 - treatment.deferred().group(new DefaultGroupId(0x20000001));
1833 - treatment.transition(ACL_TABLE);
1834 - FlowRule rule = DefaultFlowRule.builder()
1835 - .forDevice(deviceId)
1836 - .withSelector(selector.build())
1837 - .withTreatment(treatment.build())
1838 - .withPriority(30000)
1839 - .fromApp(driverId)
1840 - .makePermanent()
1841 - .forTable(UNICAST_ROUTING_TABLE).build();
1842 - ops = ops.add(rule);
1843 - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1844 - @Override
1845 - public void onSuccess(FlowRuleOperations ops) {
1846 - log.info("Initialized IP table");
1847 - }
1848 -
1849 - @Override
1850 - public void onError(FlowRuleOperations ops) {
1851 - log.info("Failed to initialize unicast IP table");
1852 - }
1853 - }));
1854 - }
1855 -
1856 - protected void processAclTable() {
1857 - //table miss entry
1858 - FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
1859 - TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
1860 - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
1861 - selector.matchEthDst(MacAddress.valueOf("00:00:00:00:00:02"));
1862 - treatment.deferred().group(new DefaultGroupId(0x20000001));
1863 - FlowRule rule = DefaultFlowRule.builder()
1864 - .forDevice(deviceId)
1865 - .withSelector(selector.build())
1866 - .withTreatment(treatment.build())
1867 - .withPriority(60000)
1868 - .fromApp(driverId)
1869 - .makePermanent()
1870 - .forTable(ACL_TABLE).build();
1871 - ops = ops.add(rule);
1872 - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
1873 - @Override
1874 - public void onSuccess(FlowRuleOperations ops) {
1875 - log.info("Initialized Acl table");
1876 - }
1877 -
1878 - @Override
1879 - public void onError(FlowRuleOperations ops) {
1880 - log.info("Failed to initialize Acl table");
1881 - }
1882 - }));
1883 - }
1884 -
1885 - private void sendPackets() {
1886 - Ethernet eth = new Ethernet();
1887 - eth.setDestinationMACAddress("00:00:00:00:00:02");
1888 - eth.setSourceMACAddress("00:00:00:11:22:33");
1889 - eth.setVlanID((short) 100);
1890 - eth.setEtherType(Ethernet.MPLS_UNICAST);
1891 - MPLS mplsPkt = new MPLS();
1892 - mplsPkt.setLabel(255);
1893 - mplsPkt.setTtl((byte) 5);
1894 -
1895 - IPv4 ipv4 = new IPv4();
1896 -
1897 - ipv4.setDestinationAddress("4.0.5.6");
1898 - ipv4.setSourceAddress("1.0.2.3");
1899 - ipv4.setTtl((byte) 64);
1900 - ipv4.setChecksum((short) 0);
1901 -
1902 - UDP udp = new UDP();
1903 - udp.setDestinationPort(666);
1904 - udp.setSourcePort(333);
1905 - udp.setPayload(new Data(new byte[]{(byte) 1, (byte) 2}));
1906 - udp.setChecksum((short) 0);
1907 -
1908 - ipv4.setPayload(udp);
1909 - mplsPkt.setPayload(ipv4);
1910 - eth.setPayload(mplsPkt);
1911 -
1912 - TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1913 - .setOutput(PortNumber.portNumber(24))
1914 - .build();
1915 - OutboundPacket packet = new DefaultOutboundPacket(deviceId,
1916 - treatment,
1917 - ByteBuffer.wrap(eth.serialize()));
1918 -
1919 -
1920 - Ethernet eth2 = new Ethernet();
1921 - eth2.setDestinationMACAddress("00:00:00:00:00:02");
1922 - eth2.setSourceMACAddress("00:00:00:11:22:33");
1923 - eth2.setVlanID((short) 100);
1924 - eth2.setEtherType(Ethernet.TYPE_IPV4);
1925 -
1926 - IPv4 ipv42 = new IPv4();
1927 - ipv42.setDestinationAddress("2.0.0.2");
1928 - ipv42.setSourceAddress("1.0.9.9");
1929 - ipv42.setTtl((byte) 64);
1930 - ipv42.setChecksum((short) 0);
1931 -
1932 - UDP udp2 = new UDP();
1933 - udp2.setDestinationPort(999);
1934 - udp2.setSourcePort(333);
1935 - udp2.setPayload(new Data(new byte[]{(byte) 1, (byte) 2}));
1936 - udp2.setChecksum((short) 0);
1937 -
1938 - ipv42.setPayload(udp2);
1939 - eth2.setPayload(ipv42);
1940 -
1941 - TrafficTreatment treatment2 = DefaultTrafficTreatment.builder()
1942 - .setOutput(PortNumber.portNumber(26))
1943 - .build();
1944 - OutboundPacket packet2 = new DefaultOutboundPacket(deviceId,
1945 - treatment2,
1946 - ByteBuffer.wrap(eth2.serialize()));
1947 -
1948 -
1949 - log.info("Emitting packets now");
1950 - packetService.emit(packet);
1951 - packetService.emit(packet);
1952 - packetService.emit(packet2);
1953 - packetService.emit(packet);
1954 - packetService.emit(packet);
1955 - log.info("Done emitting packets");
1956 - }
1957 -
1958 - private class InternalPacketProcessor implements PacketProcessor {
1959 -
1960 - @Override
1961 - public void process(PacketContext context) {
1962 -
1963 -
1964 - }
1965 } 1790 }
1966 1791
1967 } 1792 }
......
...@@ -287,24 +287,14 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour ...@@ -287,24 +287,14 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
287 case SIMPLE: 287 case SIMPLE:
288 Collection<TrafficTreatment> treatments = nextObjective.next(); 288 Collection<TrafficTreatment> treatments = nextObjective.next();
289 if (treatments.size() == 1) { 289 if (treatments.size() == 1) {
290 - TrafficTreatment treatment = treatments.iterator().next(); 290 + // Spring Open TTP converts simple nextObjective to flow-actions
291 - GroupBucket bucket = DefaultGroupBucket 291 + // in a dummy group
292 - .createIndirectGroupBucket(treatment); 292 + TrafficTreatment treatment = nextObjective.next().iterator().next();
293 - final GroupKey key = new DefaultGroupKey( 293 + log.debug("Converting SIMPLE group for next objective id {} " +
294 - appKryo.serialize(nextObjective 294 + "to {} flow-actions in device:{}", nextObjective.id(),
295 - .id())); 295 + treatment.allInstructions().size(), deviceId);
296 - GroupDescription groupDescription = new DefaultGroupDescription( 296 + flowObjectiveStore.putNextGroup(nextObjective.id(),
297 - deviceId, 297 + new SpringOpenGroup(null, treatment));
298 - GroupDescription.Type.INDIRECT,
299 - new GroupBuckets(
300 - Collections.singletonList(bucket)),
301 - key,
302 - null,
303 - nextObjective.appId());
304 - log.debug("Creating SIMPLE group for next objective id {} "
305 - + "in dev:{}", nextObjective.id(), deviceId);
306 - pendingGroups.put(key, nextObjective);
307 - groupService.addGroup(groupDescription);
308 } 298 }
309 break; 299 break;
310 case HASHED: 300 case HASHED:
...@@ -624,8 +614,9 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour ...@@ -624,8 +614,9 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
624 if (next != null) { 614 if (next != null) {
625 SpringOpenGroup soGroup = appKryo.deserialize(next.data()); 615 SpringOpenGroup soGroup = appKryo.deserialize(next.data());
626 if (soGroup.dummy) { 616 if (soGroup.dummy) {
627 - log.debug("Adding flow-actions for fwd. obj. {} " 617 + log.debug("Adding {} flow-actions for fwd. obj. {} -> next:{} "
628 - + "in dev: {}", fwd.id(), deviceId); 618 + + "in dev: {}", soGroup.treatment.allInstructions().size(),
619 + fwd.id(), fwd.nextId(), deviceId);
629 for (Instruction ins : soGroup.treatment.allInstructions()) { 620 for (Instruction ins : soGroup.treatment.allInstructions()) {
630 treatmentBuilder.add(ins); 621 treatmentBuilder.add(ins);
631 } 622 }
...@@ -639,7 +630,8 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour ...@@ -639,7 +630,8 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
639 } 630 }
640 treatmentBuilder.deferred().group(group.id()); 631 treatmentBuilder.deferred().group(group.id());
641 log.debug("Adding OUTGROUP action to group:{} for fwd. obj. {} " 632 log.debug("Adding OUTGROUP action to group:{} for fwd. obj. {} "
642 - + "in dev: {}", group.id(), fwd.id(), deviceId); 633 + + "for next:{} in dev: {}", group.id(), fwd.id(),
634 + fwd.nextId(), deviceId);
643 } 635 }
644 } else { 636 } else {
645 log.warn("processSpecific: No associated next objective object"); 637 log.warn("processSpecific: No associated next objective object");
...@@ -705,10 +697,11 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour ...@@ -705,10 +697,11 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
705 if (next != null) { 697 if (next != null) {
706 SpringOpenGroup soGrp = appKryo.deserialize(next.data()); 698 SpringOpenGroup soGrp = appKryo.deserialize(next.data());
707 if (soGrp.dummy) { 699 if (soGrp.dummy) {
708 - log.debug("Adding flow-actions for fwd. obj. {} " 700 + log.debug("Adding {} flow-actions for fwd. obj. {} "
709 - + "in dev: {}", fwd.id(), deviceId); 701 + + "in dev: {}", soGrp.treatment.allInstructions().size(),
702 + fwd.id(), deviceId);
710 for (Instruction ins : soGrp.treatment.allInstructions()) { 703 for (Instruction ins : soGrp.treatment.allInstructions()) {
711 - treatmentBuilder.add(ins); 704 + treatmentBuilder.deferred().add(ins);
712 } 705 }
713 } else { 706 } else {
714 GroupKey key = soGrp.key; 707 GroupKey key = soGrp.key;
...@@ -773,6 +766,12 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour ...@@ -773,6 +766,12 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
773 return rules; 766 return rules;
774 } 767 }
775 768
769 + /*
770 + * Note: CpqD switches do not handle MPLS-related operation properly
771 + * for a packet with VLAN tag. We pop VLAN here as a workaround.
772 + * Side effect: HostService learns redundant hosts with same MAC but
773 + * different VLAN. No known side effect on the network reachability.
774 + */
776 protected List<FlowRule> processEthDstFilter(EthCriterion ethCriterion, 775 protected List<FlowRule> processEthDstFilter(EthCriterion ethCriterion,
777 VlanIdCriterion vlanIdCriterion, 776 VlanIdCriterion vlanIdCriterion,
778 FilteringObjective filt, 777 FilteringObjective filt,
...@@ -783,12 +782,6 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour ...@@ -783,12 +782,6 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
783 vlanIdCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan); 782 vlanIdCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
784 } 783 }
785 784
786 - /*
787 - * Note: CpqD switches do not handle MPLS-related operation properly
788 - * for a packet with VLAN tag. We pop VLAN here as a workaround.
789 - * Side effect: HostService learns redundant hosts with same MAC but
790 - * different VLAN. No known side effect on the network reachability.
791 - */
792 List<FlowRule> rules = new ArrayList<>(); 785 List<FlowRule> rules = new ArrayList<>();
793 TrafficSelector.Builder selectorIp = DefaultTrafficSelector 786 TrafficSelector.Builder selectorIp = DefaultTrafficSelector
794 .builder(); 787 .builder();
......