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(); | ... | ... |
-
Please register or login to post a comment