Saurav Das
Committed by Gerrit Code Review

SR app now assigns internal vlans per subnet and passes this

information in a filtering objective to drivers. OF-DPA driver
uses this information to assign vlans to untagged packets.

Change-Id: Ibf33bdcedf5f83992f362dfb91c12575c65da3b4
...@@ -38,6 +38,7 @@ import java.util.HashMap; ...@@ -38,6 +38,7 @@ import java.util.HashMap;
38 import java.util.List; 38 import java.util.List;
39 import java.util.Map; 39 import java.util.Map;
40 import java.util.Set; 40 import java.util.Set;
41 +import java.util.concurrent.ConcurrentHashMap;
41 42
42 /** 43 /**
43 * Segment Routing configuration component that reads the 44 * Segment Routing configuration component that reads the
...@@ -51,7 +52,8 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -51,7 +52,8 @@ public class DeviceConfiguration implements DeviceProperties {
51 private static final Logger log = LoggerFactory 52 private static final Logger log = LoggerFactory
52 .getLogger(DeviceConfiguration.class); 53 .getLogger(DeviceConfiguration.class);
53 private final List<Integer> allSegmentIds = new ArrayList<>(); 54 private final List<Integer> allSegmentIds = new ArrayList<>();
54 - private final HashMap<DeviceId, SegmentRouterInfo> deviceConfigMap = new HashMap<>(); 55 + private final ConcurrentHashMap<DeviceId, SegmentRouterInfo> deviceConfigMap
56 + = new ConcurrentHashMap<>();
55 57
56 private class SegmentRouterInfo { 58 private class SegmentRouterInfo {
57 int nodeSid; 59 int nodeSid;
...@@ -133,11 +135,10 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -133,11 +135,10 @@ public class DeviceConfiguration implements DeviceProperties {
133 */ 135 */
134 @Override 136 @Override
135 public int getSegmentId(DeviceId deviceId) { 137 public int getSegmentId(DeviceId deviceId) {
136 - if (deviceConfigMap.get(deviceId) != null) { 138 + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
137 - log.trace("getSegmentId for device{} is {}", 139 + if (srinfo != null) {
138 - deviceId, 140 + log.trace("getSegmentId for device{} is {}", deviceId, srinfo.nodeSid);
139 - deviceConfigMap.get(deviceId).nodeSid); 141 + return srinfo.nodeSid;
140 - return deviceConfigMap.get(deviceId).nodeSid;
141 } else { 142 } else {
142 log.warn("getSegmentId for device {} " 143 log.warn("getSegmentId for device {} "
143 + "throwing IllegalStateException " 144 + "throwing IllegalStateException "
...@@ -150,7 +151,7 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -150,7 +151,7 @@ public class DeviceConfiguration implements DeviceProperties {
150 * Returns the Node segment id of a segment router given its Router mac address. 151 * Returns the Node segment id of a segment router given its Router mac address.
151 * 152 *
152 * @param routerMac router mac address 153 * @param routerMac router mac address
153 - * @return segment id 154 + * @return node segment id, or -1 if not found in config
154 */ 155 */
155 public int getSegmentId(MacAddress routerMac) { 156 public int getSegmentId(MacAddress routerMac) {
156 for (Map.Entry<DeviceId, SegmentRouterInfo> entry: 157 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
...@@ -167,7 +168,7 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -167,7 +168,7 @@ public class DeviceConfiguration implements DeviceProperties {
167 * Returns the Node segment id of a segment router given its Router ip address. 168 * Returns the Node segment id of a segment router given its Router ip address.
168 * 169 *
169 * @param routerAddress router ip address 170 * @param routerAddress router ip address
170 - * @return segment id 171 + * @return node segment id, or -1 if not found in config
171 */ 172 */
172 public int getSegmentId(Ip4Address routerAddress) { 173 public int getSegmentId(Ip4Address routerAddress) {
173 for (Map.Entry<DeviceId, SegmentRouterInfo> entry: 174 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
...@@ -188,11 +189,10 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -188,11 +189,10 @@ public class DeviceConfiguration implements DeviceProperties {
188 */ 189 */
189 @Override 190 @Override
190 public MacAddress getDeviceMac(DeviceId deviceId) { 191 public MacAddress getDeviceMac(DeviceId deviceId) {
191 - if (deviceConfigMap.get(deviceId) != null) { 192 + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
192 - log.trace("getDeviceMac for device{} is {}", 193 + if (srinfo != null) {
193 - deviceId, 194 + log.trace("getDeviceMac for device{} is {}", deviceId, srinfo.mac);
194 - deviceConfigMap.get(deviceId).mac); 195 + return srinfo.mac;
195 - return deviceConfigMap.get(deviceId).mac;
196 } else { 196 } else {
197 log.warn("getDeviceMac for device {} " 197 log.warn("getDeviceMac for device {} "
198 + "throwing IllegalStateException " 198 + "throwing IllegalStateException "
...@@ -208,11 +208,10 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -208,11 +208,10 @@ public class DeviceConfiguration implements DeviceProperties {
208 * @return router ip address 208 * @return router ip address
209 */ 209 */
210 public Ip4Address getRouterIp(DeviceId deviceId) { 210 public Ip4Address getRouterIp(DeviceId deviceId) {
211 - if (deviceConfigMap.get(deviceId) != null) { 211 + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
212 - log.trace("getDeviceIp for device{} is {}", 212 + if (srinfo != null) {
213 - deviceId, 213 + log.trace("getDeviceIp for device{} is {}", deviceId, srinfo.ip);
214 - deviceConfigMap.get(deviceId).ip); 214 + return srinfo.ip;
215 - return deviceConfigMap.get(deviceId).ip;
216 } else { 215 } else {
217 log.warn("getRouterIp for device {} " 216 log.warn("getRouterIp for device {} "
218 + "throwing IllegalStateException " 217 + "throwing IllegalStateException "
...@@ -230,11 +229,10 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -230,11 +229,10 @@ public class DeviceConfiguration implements DeviceProperties {
230 */ 229 */
231 @Override 230 @Override
232 public boolean isEdgeDevice(DeviceId deviceId) { 231 public boolean isEdgeDevice(DeviceId deviceId) {
233 - if (deviceConfigMap.get(deviceId) != null) { 232 + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
234 - log.trace("isEdgeDevice for device{} is {}", 233 + if (srinfo != null) {
235 - deviceId, 234 + log.trace("isEdgeDevice for device{} is {}", deviceId, srinfo.isEdge);
236 - deviceConfigMap.get(deviceId).isEdge); 235 + return srinfo.isEdge;
237 - return deviceConfigMap.get(deviceId).isEdge;
238 } else { 236 } else {
239 log.warn("isEdgeDevice for device {} " 237 log.warn("isEdgeDevice for device {} "
240 + "throwing IllegalStateException " 238 + "throwing IllegalStateException "
...@@ -295,17 +293,16 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -295,17 +293,16 @@ public class DeviceConfiguration implements DeviceProperties {
295 * on those ports. 293 * on those ports.
296 * 294 *
297 * @param deviceId device identifier 295 * @param deviceId device identifier
298 - * @return list of ip addresses configured on the ports 296 + * @return list of ip addresses configured on the ports or null if not found
299 */ 297 */
300 public List<Ip4Address> getPortIPs(DeviceId deviceId) { 298 public List<Ip4Address> getPortIPs(DeviceId deviceId) {
301 - if (deviceConfigMap.get(deviceId) != null) { 299 + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
302 - log.trace("getSubnetGatewayIps for device{} is {}", 300 + if (srinfo != null) {
303 - deviceId, 301 + log.trace("getSubnetGatewayIps for device{} is {}", deviceId,
304 - deviceConfigMap.get(deviceId).gatewayIps.values()); 302 + srinfo.gatewayIps.values());
305 - return new ArrayList<>(deviceConfigMap.get(deviceId).gatewayIps.values()); 303 + return new ArrayList<>(srinfo.gatewayIps.values());
306 - } else {
307 - return null;
308 } 304 }
305 + return null;
309 } 306 }
310 307
311 /** 308 /**
...@@ -313,11 +310,12 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -313,11 +310,12 @@ public class DeviceConfiguration implements DeviceProperties {
313 * for a segment router. 310 * for a segment router.
314 * 311 *
315 * @param deviceId device identifier 312 * @param deviceId device identifier
316 - * @return map of port to gateway IP addresses 313 + * @return map of port to gateway IP addresses or null if not found
317 */ 314 */
318 public Map<PortNumber, Ip4Address> getPortIPMap(DeviceId deviceId) { 315 public Map<PortNumber, Ip4Address> getPortIPMap(DeviceId deviceId) {
319 - if (deviceConfigMap.get(deviceId) != null) { 316 + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
320 - return deviceConfigMap.get(deviceId).gatewayIps; 317 + if (srinfo != null) {
318 + return srinfo.gatewayIps;
321 } 319 }
322 return null; 320 return null;
323 } 321 }
...@@ -326,17 +324,32 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -326,17 +324,32 @@ public class DeviceConfiguration implements DeviceProperties {
326 * Returns the configured subnet prefixes for a segment router. 324 * Returns the configured subnet prefixes for a segment router.
327 * 325 *
328 * @param deviceId device identifier 326 * @param deviceId device identifier
329 - * @return list of ip prefixes 327 + * @return list of ip prefixes or null if not found
330 */ 328 */
331 public List<Ip4Prefix> getSubnets(DeviceId deviceId) { 329 public List<Ip4Prefix> getSubnets(DeviceId deviceId) {
332 - if (deviceConfigMap.get(deviceId) != null) { 330 + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
333 - log.trace("getSubnets for device{} is {}", 331 + if (srinfo != null) {
334 - deviceId, 332 + log.trace("getSubnets for device{} is {}", deviceId,
335 - deviceConfigMap.get(deviceId).subnets.values()); 333 + srinfo.subnets.values());
336 - return new ArrayList<>(deviceConfigMap.get(deviceId).subnets.values()); 334 + return new ArrayList<>(srinfo.subnets.values());
337 - } else { 335 + }
338 - return null; 336 + return null;
337 + }
338 +
339 + /**
340 + * Returns the configured subnet on the given port, or null if no
341 + * subnet has been configured on the port.
342 + *
343 + * @param deviceId device identifier
344 + * @param pnum port identifier
345 + * @return configured subnet on port, or null
346 + */
347 + public Ip4Prefix getPortSubnet(DeviceId deviceId, PortNumber pnum) {
348 + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
349 + if (srinfo != null) {
350 + return srinfo.subnets.get(pnum);
339 } 351 }
352 + return null;
340 } 353 }
341 354
342 /** 355 /**
...@@ -365,7 +378,7 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -365,7 +378,7 @@ public class DeviceConfiguration implements DeviceProperties {
365 * specified ip address as one of its subnet gateway ip address. 378 * specified ip address as one of its subnet gateway ip address.
366 * 379 *
367 * @param gatewayIpAddress router gateway ip address 380 * @param gatewayIpAddress router gateway ip address
368 - * @return router mac address 381 + * @return router mac address or null if not found
369 */ 382 */
370 public MacAddress getRouterMacForAGatewayIp(Ip4Address gatewayIpAddress) { 383 public MacAddress getRouterMacForAGatewayIp(Ip4Address gatewayIpAddress) {
371 for (Map.Entry<DeviceId, SegmentRouterInfo> entry: 384 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
...@@ -415,8 +428,9 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -415,8 +428,9 @@ public class DeviceConfiguration implements DeviceProperties {
415 * @return list of port numbers 428 * @return list of port numbers
416 */ 429 */
417 public List<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) { 430 public List<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
418 - if (deviceConfigMap.get(deviceId) != null) { 431 + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
419 - for (AdjacencySid asid : deviceConfigMap.get(deviceId).adjacencySids) { 432 + if (srinfo != null) {
433 + for (AdjacencySid asid : srinfo.adjacencySids) {
420 if (asid.getAsid() == sid) { 434 if (asid.getAsid() == sid) {
421 return asid.getPorts(); 435 return asid.getPorts();
422 } 436 }
...@@ -435,12 +449,13 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -435,12 +449,13 @@ public class DeviceConfiguration implements DeviceProperties {
435 * otherwise false 449 * otherwise false
436 */ 450 */
437 public boolean isAdjacencySid(DeviceId deviceId, int sid) { 451 public boolean isAdjacencySid(DeviceId deviceId, int sid) {
438 - if (deviceConfigMap.get(deviceId) != null) { 452 + SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
439 - if (deviceConfigMap.get(deviceId).adjacencySids.isEmpty()) { 453 + if (srinfo != null) {
454 + if (srinfo.adjacencySids.isEmpty()) {
440 return false; 455 return false;
441 } else { 456 } else {
442 for (AdjacencySid asid: 457 for (AdjacencySid asid:
443 - deviceConfigMap.get(deviceId).adjacencySids) { 458 + srinfo.adjacencySids) {
444 if (asid.getAsid() == sid) { 459 if (asid.getAsid() == sid) {
445 return true; 460 return true;
446 } 461 }
......
...@@ -25,6 +25,7 @@ import org.onlab.packet.VlanId; ...@@ -25,6 +25,7 @@ import org.onlab.packet.VlanId;
25 import org.onosproject.segmentrouting.grouphandler.NeighborSet; 25 import org.onosproject.segmentrouting.grouphandler.NeighborSet;
26 import org.onosproject.net.DeviceId; 26 import org.onosproject.net.DeviceId;
27 import org.onosproject.net.Link; 27 import org.onosproject.net.Link;
28 +import org.onosproject.net.Port;
28 import org.onosproject.net.PortNumber; 29 import org.onosproject.net.PortNumber;
29 import org.onosproject.net.flow.DefaultTrafficSelector; 30 import org.onosproject.net.flow.DefaultTrafficSelector;
30 import org.onosproject.net.flow.DefaultTrafficTreatment; 31 import org.onosproject.net.flow.DefaultTrafficTreatment;
...@@ -60,6 +61,8 @@ public class RoutingRulePopulator { ...@@ -60,6 +61,8 @@ public class RoutingRulePopulator {
60 private DeviceConfiguration config; 61 private DeviceConfiguration config;
61 62
62 private static final int HIGHEST_PRIORITY = 0xffff; 63 private static final int HIGHEST_PRIORITY = 0xffff;
64 + private static final long OFPP_MAX = 0xffffff00L;
65 +
63 66
64 /** 67 /**
65 * Creates a RoutingRulePopulator object. 68 * Creates a RoutingRulePopulator object.
...@@ -355,25 +358,37 @@ public class RoutingRulePopulator { ...@@ -355,25 +358,37 @@ public class RoutingRulePopulator {
355 358
356 /** 359 /**
357 * Creates a filtering objective to permit all untagged packets with a 360 * Creates a filtering objective to permit all untagged packets with a
358 - * dstMac corresponding to the router's MAC address. 361 + * dstMac corresponding to the router's MAC address. For those pipelines
362 + * that need to internally assign vlans to untagged packets, this method
363 + * provides per-subnet vlan-ids as metadata.
359 * 364 *
360 * @param deviceId the switch dpid for the router 365 * @param deviceId the switch dpid for the router
361 */ 366 */
362 public void populateRouterMacVlanFilters(DeviceId deviceId) { 367 public void populateRouterMacVlanFilters(DeviceId deviceId) {
363 - FilteringObjective.Builder fob = DefaultFilteringObjective.builder(); 368 + log.debug("Installing per-port filtering objective for untagged "
364 - fob.withKey(Criteria.matchInPort(PortNumber.ALL)) 369 + + "packets in device {}", deviceId);
370 + for (Port port : srManager.deviceService.getPorts(deviceId)) {
371 + if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
372 + Ip4Prefix portSubnet = config.getPortSubnet(deviceId, port.number());
373 + VlanId assignedVlan = (portSubnet == null)
374 + ? VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET)
375 + : srManager.getSubnetAssignedVlanId(deviceId, portSubnet);
376 + TrafficTreatment tt = DefaultTrafficTreatment.builder()
377 + .pushVlan().setVlanId(assignedVlan).build();
378 + FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
379 + fob.withKey(Criteria.matchInPort(port.number()))
365 .addCondition(Criteria.matchEthDst(config.getDeviceMac(deviceId))) 380 .addCondition(Criteria.matchEthDst(config.getDeviceMac(deviceId)))
366 .addCondition(Criteria.matchVlanId(VlanId.NONE)) 381 .addCondition(Criteria.matchVlanId(VlanId.NONE))
367 - .addCondition(Criteria.matchIPDst( 382 + .setMeta(tt)
368 - IpPrefix.valueOf(config.getRouterIp(deviceId), 383 + .addCondition(Criteria.matchIPDst(IpPrefix.valueOf(
369 - IpPrefix.MAX_INET_MASK_LENGTH))); 384 + config.getRouterIp(deviceId),
370 - 385 + IpPrefix.MAX_INET_MASK_LENGTH)));
371 - fob.permit().fromApp(srManager.appId); 386 + fob.permit().fromApp(srManager.appId);
372 - log.debug("Installing filtering objective for untagged packets"); 387 + srManager.flowObjectiveService.
373 - srManager.flowObjectiveService. 388 + filter(deviceId, fob.add(new SRObjectiveContext(deviceId,
374 - filter(deviceId, 389 + SRObjectiveContext.ObjectiveType.FILTER)));
375 - fob.add(new SRObjectiveContext(deviceId, 390 + }
376 - SRObjectiveContext.ObjectiveType.FILTER))); 391 + }
377 } 392 }
378 393
379 /** 394 /**
......
...@@ -23,6 +23,8 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; ...@@ -23,6 +23,8 @@ import org.apache.felix.scr.annotations.ReferenceCardinality;
23 import org.apache.felix.scr.annotations.Service; 23 import org.apache.felix.scr.annotations.Service;
24 import org.onlab.packet.Ethernet; 24 import org.onlab.packet.Ethernet;
25 import org.onlab.packet.IPv4; 25 import org.onlab.packet.IPv4;
26 +import org.onlab.packet.Ip4Prefix;
27 +import org.onlab.packet.VlanId;
26 import org.onlab.util.KryoNamespace; 28 import org.onlab.util.KryoNamespace;
27 import org.onosproject.core.ApplicationId; 29 import org.onosproject.core.ApplicationId;
28 import org.onosproject.core.CoreService; 30 import org.onosproject.core.CoreService;
...@@ -45,7 +47,6 @@ import org.onosproject.net.device.DeviceEvent; ...@@ -45,7 +47,6 @@ import org.onosproject.net.device.DeviceEvent;
45 import org.onosproject.net.device.DeviceListener; 47 import org.onosproject.net.device.DeviceListener;
46 import org.onosproject.net.device.DeviceService; 48 import org.onosproject.net.device.DeviceService;
47 import org.onosproject.net.flowobjective.FlowObjectiveService; 49 import org.onosproject.net.flowobjective.FlowObjectiveService;
48 -import org.onosproject.net.group.GroupKey;
49 import org.onosproject.net.host.HostService; 50 import org.onosproject.net.host.HostService;
50 import org.onosproject.net.intent.IntentService; 51 import org.onosproject.net.intent.IntentService;
51 import org.onosproject.net.link.LinkEvent; 52 import org.onosproject.net.link.LinkEvent;
...@@ -64,9 +65,11 @@ import org.slf4j.Logger; ...@@ -64,9 +65,11 @@ import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory; 65 import org.slf4j.LoggerFactory;
65 66
66 import java.net.URI; 67 import java.net.URI;
68 +import java.util.Collections;
67 import java.util.HashSet; 69 import java.util.HashSet;
68 import java.util.List; 70 import java.util.List;
69 import java.util.Map; 71 import java.util.Map;
72 +import java.util.Set;
70 import java.util.concurrent.ConcurrentHashMap; 73 import java.util.concurrent.ConcurrentHashMap;
71 import java.util.concurrent.ConcurrentLinkedQueue; 74 import java.util.concurrent.ConcurrentLinkedQueue;
72 import java.util.concurrent.Executors; 75 import java.util.concurrent.Executors;
...@@ -135,6 +138,10 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -135,6 +138,10 @@ public class SegmentRoutingManager implements SegmentRoutingService {
135 Integer> nsNextObjStore = null; 138 Integer> nsNextObjStore = null;
136 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null; 139 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
137 private EventuallyConsistentMap<String, Policy> policyStore = null; 140 private EventuallyConsistentMap<String, Policy> policyStore = null;
141 + // Per device, per-subnet assigned-vlans store, with (device id + subnet
142 + // IPv4 prefix) as key
143 + private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
144 + subnetVidStore = null;
138 145
139 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 146 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
140 protected StorageService storageService; 147 protected StorageService storageService;
...@@ -163,6 +170,9 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -163,6 +170,9 @@ public class SegmentRoutingManager implements SegmentRoutingService {
163 170
164 private KryoNamespace.Builder kryoBuilder = null; 171 private KryoNamespace.Builder kryoBuilder = null;
165 172
173 + private static final short ASSIGNED_VLAN_START = 4093;
174 + public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
175 +
166 @Activate 176 @Activate
167 protected void activate() { 177 protected void activate() {
168 appId = coreService 178 appId = coreService
...@@ -180,7 +190,9 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -180,7 +190,9 @@ public class SegmentRoutingManager implements SegmentRoutingService {
180 DefaultTunnel.class, 190 DefaultTunnel.class,
181 Policy.class, 191 Policy.class,
182 TunnelPolicy.class, 192 TunnelPolicy.class,
183 - Policy.Type.class 193 + Policy.Type.class,
194 + SubnetAssignedVidStoreKey.class,
195 + VlanId.class
184 ); 196 );
185 197
186 log.debug("Creating EC map nsnextobjectivestore"); 198 log.debug("Creating EC map nsnextobjectivestore");
...@@ -212,6 +224,15 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -212,6 +224,15 @@ public class SegmentRoutingManager implements SegmentRoutingService {
212 .withTimestampProvider((k, v) -> new WallClockTimestamp()) 224 .withTimestampProvider((k, v) -> new WallClockTimestamp())
213 .build(); 225 .build();
214 226
227 + EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
228 + subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
229 +
230 + subnetVidStore = subnetVidStoreMapBuilder
231 + .withName("subnetvidstore")
232 + .withSerializer(kryoBuilder)
233 + .withTimestampProvider((k, v) -> new WallClockTimestamp())
234 + .build();
235 +
215 cfgService.addListener(cfgListener); 236 cfgService.addListener(cfgListener);
216 cfgService.registerConfigFactory(cfgFactory); 237 cfgService.registerConfigFactory(cfgFactory);
217 238
...@@ -296,23 +317,72 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -296,23 +317,72 @@ public class SegmentRoutingManager implements SegmentRoutingService {
296 } 317 }
297 318
298 /** 319 /**
299 - * Returns the GroupKey object for the device and the NeighborSet given. 320 + * Returns the vlan-id assigned to the subnet configured for a device.
300 - * XXX is this called 321 + * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
322 + * if and only if this controller instance is the master for the device.
323 + * <p>
324 + * USAGE: The assigned vlans are meant to be applied to untagged packets on those
325 + * switches/pipelines that need this functionality. These vids are meant
326 + * to be used internally within a switch, and thus need to be unique only
327 + * on a switch level. Note that packets never go out on the wire with these
328 + * vlans. Currently, vlan ids are assigned from value 4093 down.
329 + * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
330 + * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
331 + * per subnet.
332 + * XXX This method should avoid any vlans configured on the ports, but
333 + * currently the app works only on untagged packets and as a result
334 + * ignores any vlan configuration.
301 * 335 *
302 - * @param ns NeightborSet object for the GroupKey 336 + * @param deviceId switch dpid
303 - * @return GroupKey object for the NeighborSet 337 + * @param subnet IPv4 prefix for which assigned vlan is desired
338 + * @return VlanId assigned for the subnet on the device, or
339 + * null if no vlan assignment was found and this instance is not
340 + * the master for the device.
304 */ 341 */
305 - public GroupKey getGroupKey(NeighborSet ns) { 342 + public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
306 - for (DefaultGroupHandler groupHandler : groupHandlerMap.values()) { 343 + VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
307 - return groupHandler.getGroupKey(ns); 344 + deviceId, subnet));
345 + if (assignedVid != null) {
346 + log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
347 + + "{}", subnet, deviceId, assignedVid);
348 + return assignedVid;
349 + }
350 + //check mastership for the right to assign a vlan
351 + if (!mastershipService.isLocalMaster(deviceId)) {
352 + log.warn("This controller instance is not the master for device {}. "
353 + + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
354 + return null;
355 + }
356 + // vlan assignment is expensive but done only once
357 + List<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
358 + Set<Short> assignedVlans = new HashSet<>();
359 + Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
360 + for (Ip4Prefix sub : configuredSubnets) {
361 + VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
362 + sub));
363 + if (v != null) {
364 + assignedVlans.add(v.toShort());
365 + } else {
366 + unassignedSubnets.add(sub);
367 + }
368 + }
369 + short nextAssignedVlan = ASSIGNED_VLAN_START;
370 + if (!assignedVlans.isEmpty()) {
371 + nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
372 + }
373 + for (Ip4Prefix unsub : unassignedSubnets) {
374 + subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
375 + VlanId.vlanId(nextAssignedVlan--));
376 + log.info("Assigned vlan: {} to subnet: {} on device: {}",
377 + nextAssignedVlan + 1, unsub, deviceId);
308 } 378 }
309 379
310 - return null; 380 + return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
311 } 381 }
312 382
313 /** 383 /**
314 - * Returns the next objective ID for the NeighborSet given. If the nextObjectiveID does not exist, 384 + * Returns the next objective ID for the given NeighborSet.
315 - * a new one is created and returned. 385 + * If the nextObjectiveID does not exist, a new one is created and returned.
316 * 386 *
317 * @param deviceId Device ID 387 * @param deviceId Device ID
318 * @param ns NegighborSet 388 * @param ns NegighborSet
......
1 +package org.onosproject.segmentrouting;
2 +
3 +import java.util.Objects;
4 +
5 +import org.onlab.packet.Ip4Prefix;
6 +import org.onosproject.net.DeviceId;
7 +
8 +/**
9 + * Class definition for key used to map per device subnets to assigned Vlan ids.
10 + *
11 + */
12 +public class SubnetAssignedVidStoreKey {
13 + private final DeviceId deviceId;
14 + private final Ip4Prefix subnet;
15 +
16 + public SubnetAssignedVidStoreKey(DeviceId deviceId, Ip4Prefix subnet) {
17 + this.deviceId = deviceId;
18 + this.subnet = subnet;
19 + }
20 +
21 + /**
22 + * Returns the device identification used to create this key.
23 + *
24 + * @return the device identifier
25 + */
26 + public DeviceId deviceId() {
27 + return deviceId;
28 + }
29 +
30 + /**
31 + * Returns the subnet information used to create this key.
32 + *
33 + * @return the subnet
34 + */
35 + public Ip4Prefix subnet() {
36 + return subnet;
37 + }
38 +
39 + @Override
40 + public boolean equals(Object o) {
41 + if (this == o) {
42 + return true;
43 + }
44 + if (!(o instanceof SubnetAssignedVidStoreKey)) {
45 + return false;
46 + }
47 + SubnetAssignedVidStoreKey that =
48 + (SubnetAssignedVidStoreKey) o;
49 + return (Objects.equals(this.deviceId, that.deviceId) &&
50 + Objects.equals(this.subnet, that.subnet));
51 + }
52 +
53 + @Override
54 + public int hashCode() {
55 + int result = 17;
56 + result = 31 * result + Objects.hashCode(deviceId)
57 + + Objects.hashCode(subnet);
58 + return result;
59 + }
60 +
61 + @Override
62 + public String toString() {
63 + return "Device: " + deviceId + " Subnet: " + subnet;
64 + }
65 +
66 +}
...@@ -148,12 +148,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -148,12 +148,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
148 //private static final int MPLSINTERFACEMASK = 0x90000000; 148 //private static final int MPLSINTERFACEMASK = 0x90000000;
149 private static final int L3ECMPMASK = 0x70000000; 149 private static final int L3ECMPMASK = 0x70000000;
150 150
151 - /*
152 - * This driver assigns all incoming untagged packets the same VLAN ID
153 - */
154 - private static final short UNTAGGED_ASSIGNED_VLAN = 0xffa; // 4090
155 -
156 -
157 private final Logger log = getLogger(getClass()); 151 private final Logger log = getLogger(getClass());
158 private ServiceDirectory serviceDirectory; 152 private ServiceDirectory serviceDirectory;
159 protected FlowRuleService flowRuleService; 153 protected FlowRuleService flowRuleService;
...@@ -351,11 +345,35 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -351,11 +345,35 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
351 } 345 }
352 } 346 }
353 347
348 + VlanId assignedVlan = null;
349 + if (vidCriterion != null && vidCriterion.vlanId() == VlanId.NONE) {
350 + // untagged packets are assigned vlans in OF-DPA
351 + if (filt.meta() == null) {
352 + log.error("Missing metadata in filtering objective required "
353 + + "for vlan assignment in dev {}", deviceId);
354 + fail(filt, ObjectiveError.BADPARAMS);
355 + return;
356 + }
357 + for (Instruction i : filt.meta().allInstructions()) {
358 + if (i instanceof ModVlanIdInstruction) {
359 + assignedVlan = ((ModVlanIdInstruction) i).vlanId();
360 + }
361 + }
362 + if (assignedVlan == null) {
363 + log.error("Driver requires an assigned vlan-id to tag incoming "
364 + + "untagged packets. Not processing vlan filters on "
365 + + "device {}", deviceId);
366 + fail(filt, ObjectiveError.BADPARAMS);
367 + return;
368 + }
369 + }
370 +
354 if (ethCriterion == null) { 371 if (ethCriterion == null) {
355 log.debug("filtering objective missing dstMac, cannot program TMAC table"); 372 log.debug("filtering objective missing dstMac, cannot program TMAC table");
356 } else { 373 } else {
357 for (FlowRule tmacRule : processEthDstFilter(portCriterion, ethCriterion, 374 for (FlowRule tmacRule : processEthDstFilter(portCriterion, ethCriterion,
358 - vidCriterion, applicationId)) { 375 + vidCriterion, assignedVlan,
376 + applicationId)) {
359 log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}", 377 log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}",
360 tmacRule, deviceId); 378 tmacRule, deviceId);
361 ops = install ? ops.add(tmacRule) : ops.remove(tmacRule); 379 ops = install ? ops.add(tmacRule) : ops.remove(tmacRule);
...@@ -367,6 +385,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -367,6 +385,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
367 + "Vlan Table"); 385 + "Vlan Table");
368 } else { 386 } else {
369 for (FlowRule vlanRule : processVlanIdFilter(portCriterion, vidCriterion, 387 for (FlowRule vlanRule : processVlanIdFilter(portCriterion, vidCriterion,
388 + assignedVlan,
370 applicationId)) { 389 applicationId)) {
371 log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}", 390 log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}",
372 vlanRule, deviceId); 391 vlanRule, deviceId);
...@@ -419,14 +438,18 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -419,14 +438,18 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
419 438
420 /** 439 /**
421 * Allows untagged packets into pipeline by assigning a vlan id. 440 * Allows untagged packets into pipeline by assigning a vlan id.
441 + * Vlan assignment is done by the application.
422 * Allows tagged packets into pipeline as per configured port-vlan info. 442 * Allows tagged packets into pipeline as per configured port-vlan info.
443 + *
423 * @param portCriterion port on device for which this filter is programmed 444 * @param portCriterion port on device for which this filter is programmed
424 * @param vidCriterion vlan assigned to port, or NONE for untagged 445 * @param vidCriterion vlan assigned to port, or NONE for untagged
446 + * @param assignedVlan assigned vlan-id for untagged packets
425 * @param applicationId for application programming this filter 447 * @param applicationId for application programming this filter
426 * @return list of FlowRule for port-vlan filters 448 * @return list of FlowRule for port-vlan filters
427 */ 449 */
428 protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion, 450 protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion,
429 VlanIdCriterion vidCriterion, 451 VlanIdCriterion vidCriterion,
452 + VlanId assignedVlan,
430 ApplicationId applicationId) { 453 ApplicationId applicationId) {
431 List<FlowRule> rules = new ArrayList<FlowRule>(); 454 List<FlowRule> rules = new ArrayList<FlowRule>();
432 TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); 455 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
...@@ -434,7 +457,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -434,7 +457,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
434 selector.matchVlanId(vidCriterion.vlanId()); 457 selector.matchVlanId(vidCriterion.vlanId());
435 if (vidCriterion.vlanId() == VlanId.NONE) { 458 if (vidCriterion.vlanId() == VlanId.NONE) {
436 // untagged packets are assigned vlans 459 // untagged packets are assigned vlans
437 - treatment.pushVlan().setVlanId(VlanId.vlanId(UNTAGGED_ASSIGNED_VLAN)); 460 + treatment.pushVlan().setVlanId(assignedVlan);
438 // XXX ofdpa may require an additional vlan match on the assigned vlan 461 // XXX ofdpa may require an additional vlan match on the assigned vlan
439 // and it may not require the push. 462 // and it may not require the push.
440 } 463 }
...@@ -475,6 +498,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -475,6 +498,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
475 * @param portCriterion port on device for which this filter is programmed 498 * @param portCriterion port on device for which this filter is programmed
476 * @param ethCriterion dstMac of device for which is filter is programmed 499 * @param ethCriterion dstMac of device for which is filter is programmed
477 * @param vidCriterion vlan assigned to port, or NONE for untagged 500 * @param vidCriterion vlan assigned to port, or NONE for untagged
501 + * @param assignedVlan assigned vlan-id for untagged packets
478 * @param applicationId for application programming this filter 502 * @param applicationId for application programming this filter
479 * @return list of FlowRule for port-vlan filters 503 * @return list of FlowRule for port-vlan filters
480 504
...@@ -482,11 +506,11 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -482,11 +506,11 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
482 protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion, 506 protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion,
483 EthCriterion ethCriterion, 507 EthCriterion ethCriterion,
484 VlanIdCriterion vidCriterion, 508 VlanIdCriterion vidCriterion,
509 + VlanId assignedVlan,
485 ApplicationId applicationId) { 510 ApplicationId applicationId) {
486 //handling untagged packets via assigned VLAN 511 //handling untagged packets via assigned VLAN
487 if (vidCriterion.vlanId() == VlanId.NONE) { 512 if (vidCriterion.vlanId() == VlanId.NONE) {
488 - vidCriterion = (VlanIdCriterion) Criteria 513 + vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
489 - .matchVlanId(VlanId.vlanId(UNTAGGED_ASSIGNED_VLAN));
490 } 514 }
491 // ofdpa cannot match on ALL portnumber, so we need to use separate 515 // ofdpa cannot match on ALL portnumber, so we need to use separate
492 // rules for each port. 516 // rules for each port.
......