Committed by
Gerrit Code Review
CORD-48 Fixing filtering rule bug in multi-instance operation.
Change-Id: Ie91b2efcebff1bdb14357b6720ff8214a712cdc2
Showing
5 changed files
with
54 additions
and
28 deletions
| ... | @@ -35,7 +35,8 @@ import org.slf4j.Logger; | ... | @@ -35,7 +35,8 @@ import org.slf4j.Logger; |
| 35 | import org.slf4j.LoggerFactory; | 35 | import org.slf4j.LoggerFactory; |
| 36 | 36 | ||
| 37 | import java.nio.ByteBuffer; | 37 | import java.nio.ByteBuffer; |
| 38 | -import java.util.List; | 38 | +import java.util.Set; |
| 39 | + | ||
| 39 | import static com.google.common.base.Preconditions.checkNotNull; | 40 | import static com.google.common.base.Preconditions.checkNotNull; |
| 40 | 41 | ||
| 41 | public class ArpHandler { | 42 | public class ArpHandler { |
| ... | @@ -112,7 +113,7 @@ public class ArpHandler { | ... | @@ -112,7 +113,7 @@ public class ArpHandler { |
| 112 | 113 | ||
| 113 | 114 | ||
| 114 | private boolean isArpReqForRouter(DeviceId deviceId, ARP arpRequest) { | 115 | private boolean isArpReqForRouter(DeviceId deviceId, ARP arpRequest) { |
| 115 | - List<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId); | 116 | + Set<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId); |
| 116 | if (gatewayIpAddresses != null) { | 117 | if (gatewayIpAddresses != null) { |
| 117 | Ip4Address targetProtocolAddress = Ip4Address.valueOf(arpRequest | 118 | Ip4Address targetProtocolAddress = Ip4Address.valueOf(arpRequest |
| 118 | .getTargetProtocolAddress()); | 119 | .getTargetProtocolAddress()); | ... | ... |
| ... | @@ -312,14 +312,14 @@ public class DeviceConfiguration implements DeviceProperties { | ... | @@ -312,14 +312,14 @@ public class DeviceConfiguration implements DeviceProperties { |
| 312 | * on those ports. | 312 | * on those ports. |
| 313 | * | 313 | * |
| 314 | * @param deviceId device identifier | 314 | * @param deviceId device identifier |
| 315 | - * @return list of ip addresses configured on the ports or null if not found | 315 | + * @return immutable set of ip addresses configured on the ports or null if not found |
| 316 | */ | 316 | */ |
| 317 | - public List<Ip4Address> getPortIPs(DeviceId deviceId) { | 317 | + public Set<Ip4Address> getPortIPs(DeviceId deviceId) { |
| 318 | SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); | 318 | SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); |
| 319 | if (srinfo != null) { | 319 | if (srinfo != null) { |
| 320 | log.trace("getSubnetGatewayIps for device{} is {}", deviceId, | 320 | log.trace("getSubnetGatewayIps for device{} is {}", deviceId, |
| 321 | srinfo.gatewayIps.values()); | 321 | srinfo.gatewayIps.values()); |
| 322 | - return new ArrayList<>(srinfo.gatewayIps.values()); | 322 | + return ImmutableSet.copyOf(srinfo.gatewayIps.values()); |
| 323 | } | 323 | } |
| 324 | return null; | 324 | return null; |
| 325 | } | 325 | } | ... | ... |
| ... | @@ -32,7 +32,7 @@ import org.slf4j.Logger; | ... | @@ -32,7 +32,7 @@ import org.slf4j.Logger; |
| 32 | import org.slf4j.LoggerFactory; | 32 | import org.slf4j.LoggerFactory; |
| 33 | 33 | ||
| 34 | import java.nio.ByteBuffer; | 34 | import java.nio.ByteBuffer; |
| 35 | -import java.util.List; | 35 | +import java.util.Set; |
| 36 | 36 | ||
| 37 | import static com.google.common.base.Preconditions.checkNotNull; | 37 | import static com.google.common.base.Preconditions.checkNotNull; |
| 38 | 38 | ||
| ... | @@ -70,7 +70,7 @@ public class IcmpHandler { | ... | @@ -70,7 +70,7 @@ public class IcmpHandler { |
| 70 | DeviceId deviceId = connectPoint.deviceId(); | 70 | DeviceId deviceId = connectPoint.deviceId(); |
| 71 | Ip4Address destinationAddress = | 71 | Ip4Address destinationAddress = |
| 72 | Ip4Address.valueOf(ipv4.getDestinationAddress()); | 72 | Ip4Address.valueOf(ipv4.getDestinationAddress()); |
| 73 | - List<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId); | 73 | + Set<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId); |
| 74 | Ip4Address routerIp = config.getRouterIp(deviceId); | 74 | Ip4Address routerIp = config.getRouterIp(deviceId); |
| 75 | IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH); | 75 | IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH); |
| 76 | Ip4Address routerIpAddress = routerIpPrefix.getIp4Prefix().address(); | 76 | Ip4Address routerIpAddress = routerIpPrefix.getIp4Prefix().address(); | ... | ... |
| ... | @@ -45,6 +45,7 @@ import org.slf4j.Logger; | ... | @@ -45,6 +45,7 @@ import org.slf4j.Logger; |
| 45 | import org.slf4j.LoggerFactory; | 45 | import org.slf4j.LoggerFactory; |
| 46 | 46 | ||
| 47 | import java.util.ArrayList; | 47 | import java.util.ArrayList; |
| 48 | +import java.util.HashSet; | ||
| 48 | import java.util.List; | 49 | import java.util.List; |
| 49 | import java.util.Set; | 50 | import java.util.Set; |
| 50 | import java.util.concurrent.atomic.AtomicLong; | 51 | import java.util.concurrent.atomic.AtomicLong; |
| ... | @@ -361,6 +362,10 @@ public class RoutingRulePopulator { | ... | @@ -361,6 +362,10 @@ public class RoutingRulePopulator { |
| 361 | * dstMac corresponding to the router's MAC address. For those pipelines | 362 | * dstMac corresponding to the router's MAC address. For those pipelines |
| 362 | * that need to internally assign vlans to untagged packets, this method | 363 | * that need to internally assign vlans to untagged packets, this method |
| 363 | * provides per-subnet vlan-ids as metadata. | 364 | * provides per-subnet vlan-ids as metadata. |
| 365 | + * <p> | ||
| 366 | + * Note that the vlan assignment is only done by the master-instance for a switch. | ||
| 367 | + * However we send the filtering objective from slave-instances as well, so | ||
| 368 | + * that drivers can obtain other information (like Router MAC and IP). | ||
| 364 | * | 369 | * |
| 365 | * @param deviceId the switch dpid for the router | 370 | * @param deviceId the switch dpid for the router |
| 366 | */ | 371 | */ |
| ... | @@ -373,16 +378,16 @@ public class RoutingRulePopulator { | ... | @@ -373,16 +378,16 @@ public class RoutingRulePopulator { |
| 373 | VlanId assignedVlan = (portSubnet == null) | 378 | VlanId assignedVlan = (portSubnet == null) |
| 374 | ? VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET) | 379 | ? VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET) |
| 375 | : srManager.getSubnetAssignedVlanId(deviceId, portSubnet); | 380 | : srManager.getSubnetAssignedVlanId(deviceId, portSubnet); |
| 376 | - TrafficTreatment tt = DefaultTrafficTreatment.builder() | ||
| 377 | - .pushVlan().setVlanId(assignedVlan).build(); | ||
| 378 | FilteringObjective.Builder fob = DefaultFilteringObjective.builder(); | 381 | FilteringObjective.Builder fob = DefaultFilteringObjective.builder(); |
| 379 | fob.withKey(Criteria.matchInPort(port.number())) | 382 | fob.withKey(Criteria.matchInPort(port.number())) |
| 380 | .addCondition(Criteria.matchEthDst(config.getDeviceMac(deviceId))) | 383 | .addCondition(Criteria.matchEthDst(config.getDeviceMac(deviceId))) |
| 381 | - .addCondition(Criteria.matchVlanId(VlanId.NONE)) | 384 | + .addCondition(Criteria.matchVlanId(VlanId.NONE)); |
| 382 | - .setMeta(tt) | 385 | + // vlan assignment is valid only if this instance is master |
| 383 | - .addCondition(Criteria.matchIPDst(IpPrefix.valueOf( | 386 | + if (srManager.mastershipService.isLocalMaster(deviceId)) { |
| 384 | - config.getRouterIp(deviceId), | 387 | + TrafficTreatment tt = DefaultTrafficTreatment.builder() |
| 385 | - IpPrefix.MAX_INET_MASK_LENGTH))); | 388 | + .pushVlan().setVlanId(assignedVlan).build(); |
| 389 | + fob.setMeta(tt); | ||
| 390 | + } | ||
| 386 | fob.permit().fromApp(srManager.appId); | 391 | fob.permit().fromApp(srManager.appId); |
| 387 | srManager.flowObjectiveService. | 392 | srManager.flowObjectiveService. |
| 388 | filter(deviceId, fob.add(new SRObjectiveContext(deviceId, | 393 | filter(deviceId, fob.add(new SRObjectiveContext(deviceId, |
| ... | @@ -393,16 +398,22 @@ public class RoutingRulePopulator { | ... | @@ -393,16 +398,22 @@ public class RoutingRulePopulator { |
| 393 | 398 | ||
| 394 | /** | 399 | /** |
| 395 | * Creates a forwarding objective to punt all IP packets, destined to the | 400 | * Creates a forwarding objective to punt all IP packets, destined to the |
| 396 | - * router's port IP addresses, to the controller. Note that it the input | 401 | + * router's port IP addresses, to the controller. Note that the input |
| 397 | * port should not be matched on, as these packets can come from any input. | 402 | * port should not be matched on, as these packets can come from any input. |
| 403 | + * Furthermore, these are applied only by the master instance. | ||
| 398 | * | 404 | * |
| 399 | * @param deviceId the switch dpid for the router | 405 | * @param deviceId the switch dpid for the router |
| 400 | */ | 406 | */ |
| 401 | public void populateRouterIpPunts(DeviceId deviceId) { | 407 | public void populateRouterIpPunts(DeviceId deviceId) { |
| 408 | + if (!srManager.mastershipService.isLocalMaster(deviceId)) { | ||
| 409 | + log.debug("Not installing port-IP punts - not the master for dev:{} ", | ||
| 410 | + deviceId); | ||
| 411 | + return; | ||
| 412 | + } | ||
| 402 | ForwardingObjective.Builder puntIp = DefaultForwardingObjective.builder(); | 413 | ForwardingObjective.Builder puntIp = DefaultForwardingObjective.builder(); |
| 403 | - | 414 | + Set<Ip4Address> allIps = new HashSet<Ip4Address>(config.getPortIPs(deviceId)); |
| 404 | - List<Ip4Address> gws = config.getPortIPs(deviceId); | 415 | + allIps.add(config.getRouterIp(deviceId)); |
| 405 | - for (Ip4Address ipaddr : gws) { | 416 | + for (Ip4Address ipaddr : allIps) { |
| 406 | TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); | 417 | TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); |
| 407 | TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); | 418 | TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); |
| 408 | selector.matchEthType(Ethernet.TYPE_IPV4); | 419 | selector.matchEthType(Ethernet.TYPE_IPV4); | ... | ... |
| ... | @@ -533,6 +533,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -533,6 +533,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
| 533 | event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED || | 533 | event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED || |
| 534 | event.type() == DeviceEvent.Type.DEVICE_UPDATED) { | 534 | event.type() == DeviceEvent.Type.DEVICE_UPDATED) { |
| 535 | if (deviceService.isAvailable(((Device) event.subject()).id())) { | 535 | if (deviceService.isAvailable(((Device) event.subject()).id())) { |
| 536 | + log.info("Processing device event {} for available device {}", | ||
| 537 | + event.type(), ((Device) event.subject()).id()); | ||
| 536 | processDeviceAdded((Device) event.subject()); | 538 | processDeviceAdded((Device) event.subject()); |
| 537 | } | 539 | } |
| 538 | } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) { | 540 | } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) { |
| ... | @@ -594,11 +596,12 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -594,11 +596,12 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
| 594 | 596 | ||
| 595 | private void processDeviceAdded(Device device) { | 597 | private void processDeviceAdded(Device device) { |
| 596 | log.debug("A new device with ID {} was added", device.id()); | 598 | log.debug("A new device with ID {} was added", device.id()); |
| 597 | - //Irrespective whether the local is a MASTER or not for this device, | 599 | + // Irrespective of whether the local is a MASTER or not for this device, |
| 598 | - //create group handler instance and push default TTP flow rules. | 600 | + // we need to create a SR-group-handler instance. This is because in a |
| 599 | - //Because in a multi-instance setup, instances can initiate | 601 | + // multi-instance setup, any instance can initiate forwarding/next-objectives |
| 600 | - //groups for any devices. Also the default TTP rules are needed | 602 | + // for any switch (even if this instance is a SLAVE or not even connected |
| 601 | - //to be pushed before inserting any IP table entries for any device | 603 | + // to the switch). To handle this, a default-group-handler instance is necessary |
| 604 | + // per switch. | ||
| 602 | DefaultGroupHandler groupHandler = DefaultGroupHandler. | 605 | DefaultGroupHandler groupHandler = DefaultGroupHandler. |
| 603 | createGroupHandler(device.id(), | 606 | createGroupHandler(device.id(), |
| 604 | appId, | 607 | appId, |
| ... | @@ -608,6 +611,11 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -608,6 +611,11 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
| 608 | nsNextObjStore, | 611 | nsNextObjStore, |
| 609 | subnetNextObjStore); | 612 | subnetNextObjStore); |
| 610 | groupHandlerMap.put(device.id(), groupHandler); | 613 | groupHandlerMap.put(device.id(), groupHandler); |
| 614 | + | ||
| 615 | + // Also, in some cases, drivers may need extra | ||
| 616 | + // information to process rules (eg. Router IP/MAC); and so, we send | ||
| 617 | + // port addressing rules to the driver as well irrespective of whether | ||
| 618 | + // this instance is the master or not. | ||
| 611 | defaultRoutingHandler.populatePortAddressingRules(device.id()); | 619 | defaultRoutingHandler.populatePortAddressingRules(device.id()); |
| 612 | 620 | ||
| 613 | if (mastershipService.isLocalMaster(device.id())) { | 621 | if (mastershipService.isLocalMaster(device.id())) { |
| ... | @@ -646,11 +654,12 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -646,11 +654,12 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
| 646 | tunnelHandler, policyStore); | 654 | tunnelHandler, policyStore); |
| 647 | 655 | ||
| 648 | for (Device device : deviceService.getDevices()) { | 656 | for (Device device : deviceService.getDevices()) { |
| 649 | - //Irrespective whether the local is a MASTER or not for this device, | 657 | + // Irrespective of whether the local is a MASTER or not for this device, |
| 650 | - //create group handler instance and push default TTP flow rules. | 658 | + // we need to create a SR-group-handler instance. This is because in a |
| 651 | - //Because in a multi-instance setup, instances can initiate | 659 | + // multi-instance setup, any instance can initiate forwarding/next-objectives |
| 652 | - //groups for any devices. Also the default TTP rules are needed | 660 | + // for any switch (even if this instance is a SLAVE or not even connected |
| 653 | - //to be pushed before inserting any IP table entries for any device | 661 | + // to the switch). To handle this, a default-group-handler instance is necessary |
| 662 | + // per switch. | ||
| 654 | DefaultGroupHandler groupHandler = DefaultGroupHandler | 663 | DefaultGroupHandler groupHandler = DefaultGroupHandler |
| 655 | .createGroupHandler(device.id(), appId, | 664 | .createGroupHandler(device.id(), appId, |
| 656 | deviceConfiguration, linkService, | 665 | deviceConfiguration, linkService, |
| ... | @@ -658,6 +667,11 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -658,6 +667,11 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
| 658 | nsNextObjStore, | 667 | nsNextObjStore, |
| 659 | subnetNextObjStore); | 668 | subnetNextObjStore); |
| 660 | groupHandlerMap.put(device.id(), groupHandler); | 669 | groupHandlerMap.put(device.id(), groupHandler); |
| 670 | + | ||
| 671 | + // Also, in some cases, drivers may need extra | ||
| 672 | + // information to process rules (eg. Router IP/MAC); and so, we send | ||
| 673 | + // port addressing rules to the driver as well, irrespective of whether | ||
| 674 | + // this instance is the master or not. | ||
| 661 | defaultRoutingHandler.populatePortAddressingRules(device.id()); | 675 | defaultRoutingHandler.populatePortAddressingRules(device.id()); |
| 662 | 676 | ||
| 663 | if (mastershipService.isLocalMaster(device.id())) { | 677 | if (mastershipService.isLocalMaster(device.id())) { | ... | ... |
-
Please register or login to post a comment