CORD-48 Fixing filtering rule bug in multi-instance operation.
Change-Id: Ie91b2efcebff1bdb14357b6720ff8214a712cdc2
diff --git a/src/main/java/org/onosproject/segmentrouting/ArpHandler.java b/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
index 55192a9..36563f0 100644
--- a/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
+++ b/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
@@ -35,7 +35,8 @@
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
-import java.util.List;
+import java.util.Set;
+
import static com.google.common.base.Preconditions.checkNotNull;
public class ArpHandler {
@@ -112,7 +113,7 @@
private boolean isArpReqForRouter(DeviceId deviceId, ARP arpRequest) {
- List<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId);
+ Set<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId);
if (gatewayIpAddresses != null) {
Ip4Address targetProtocolAddress = Ip4Address.valueOf(arpRequest
.getTargetProtocolAddress());
diff --git a/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java b/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
index 6b51ff3..828c51c 100644
--- a/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
+++ b/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
@@ -312,14 +312,14 @@
* on those ports.
*
* @param deviceId device identifier
- * @return list of ip addresses configured on the ports or null if not found
+ * @return immutable set of ip addresses configured on the ports or null if not found
*/
- public List<Ip4Address> getPortIPs(DeviceId deviceId) {
+ public Set<Ip4Address> getPortIPs(DeviceId deviceId) {
SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
if (srinfo != null) {
log.trace("getSubnetGatewayIps for device{} is {}", deviceId,
srinfo.gatewayIps.values());
- return new ArrayList<>(srinfo.gatewayIps.values());
+ return ImmutableSet.copyOf(srinfo.gatewayIps.values());
}
return null;
}
diff --git a/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java b/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
index a77ec95..b3916b0 100644
--- a/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
+++ b/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
@@ -32,7 +32,7 @@
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
-import java.util.List;
+import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -70,7 +70,7 @@
DeviceId deviceId = connectPoint.deviceId();
Ip4Address destinationAddress =
Ip4Address.valueOf(ipv4.getDestinationAddress());
- List<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId);
+ Set<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId);
Ip4Address routerIp = config.getRouterIp(deviceId);
IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
Ip4Address routerIpAddress = routerIpPrefix.getIp4Prefix().address();
diff --git a/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
index 0d7d4c9..d46028e 100644
--- a/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
+++ b/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
@@ -45,6 +45,7 @@
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
@@ -361,6 +362,10 @@
* dstMac corresponding to the router's MAC address. For those pipelines
* that need to internally assign vlans to untagged packets, this method
* provides per-subnet vlan-ids as metadata.
+ * <p>
+ * Note that the vlan assignment is only done by the master-instance for a switch.
+ * However we send the filtering objective from slave-instances as well, so
+ * that drivers can obtain other information (like Router MAC and IP).
*
* @param deviceId the switch dpid for the router
*/
@@ -373,16 +378,16 @@
VlanId assignedVlan = (portSubnet == null)
? VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET)
: srManager.getSubnetAssignedVlanId(deviceId, portSubnet);
- TrafficTreatment tt = DefaultTrafficTreatment.builder()
- .pushVlan().setVlanId(assignedVlan).build();
FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
fob.withKey(Criteria.matchInPort(port.number()))
.addCondition(Criteria.matchEthDst(config.getDeviceMac(deviceId)))
- .addCondition(Criteria.matchVlanId(VlanId.NONE))
- .setMeta(tt)
- .addCondition(Criteria.matchIPDst(IpPrefix.valueOf(
- config.getRouterIp(deviceId),
- IpPrefix.MAX_INET_MASK_LENGTH)));
+ .addCondition(Criteria.matchVlanId(VlanId.NONE));
+ // vlan assignment is valid only if this instance is master
+ if (srManager.mastershipService.isLocalMaster(deviceId)) {
+ TrafficTreatment tt = DefaultTrafficTreatment.builder()
+ .pushVlan().setVlanId(assignedVlan).build();
+ fob.setMeta(tt);
+ }
fob.permit().fromApp(srManager.appId);
srManager.flowObjectiveService.
filter(deviceId, fob.add(new SRObjectiveContext(deviceId,
@@ -393,16 +398,22 @@
/**
* Creates a forwarding objective to punt all IP packets, destined to the
- * router's port IP addresses, to the controller. Note that it the input
+ * router's port IP addresses, to the controller. Note that the input
* port should not be matched on, as these packets can come from any input.
+ * Furthermore, these are applied only by the master instance.
*
* @param deviceId the switch dpid for the router
*/
public void populateRouterIpPunts(DeviceId deviceId) {
+ if (!srManager.mastershipService.isLocalMaster(deviceId)) {
+ log.debug("Not installing port-IP punts - not the master for dev:{} ",
+ deviceId);
+ return;
+ }
ForwardingObjective.Builder puntIp = DefaultForwardingObjective.builder();
-
- List<Ip4Address> gws = config.getPortIPs(deviceId);
- for (Ip4Address ipaddr : gws) {
+ Set<Ip4Address> allIps = new HashSet<Ip4Address>(config.getPortIPs(deviceId));
+ allIps.add(config.getRouterIp(deviceId));
+ for (Ip4Address ipaddr : allIps) {
TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
selector.matchEthType(Ethernet.TYPE_IPV4);
diff --git a/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index 012f134..9d60b27 100644
--- a/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -533,6 +533,8 @@
event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
if (deviceService.isAvailable(((Device) event.subject()).id())) {
+ log.info("Processing device event {} for available device {}",
+ event.type(), ((Device) event.subject()).id());
processDeviceAdded((Device) event.subject());
}
} else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
@@ -594,11 +596,12 @@
private void processDeviceAdded(Device device) {
log.debug("A new device with ID {} was added", device.id());
- //Irrespective whether the local is a MASTER or not for this device,
- //create group handler instance and push default TTP flow rules.
- //Because in a multi-instance setup, instances can initiate
- //groups for any devices. Also the default TTP rules are needed
- //to be pushed before inserting any IP table entries for any device
+ // Irrespective of whether the local is a MASTER or not for this device,
+ // we need to create a SR-group-handler instance. This is because in a
+ // multi-instance setup, any instance can initiate forwarding/next-objectives
+ // for any switch (even if this instance is a SLAVE or not even connected
+ // to the switch). To handle this, a default-group-handler instance is necessary
+ // per switch.
DefaultGroupHandler groupHandler = DefaultGroupHandler.
createGroupHandler(device.id(),
appId,
@@ -608,6 +611,11 @@
nsNextObjStore,
subnetNextObjStore);
groupHandlerMap.put(device.id(), groupHandler);
+
+ // Also, in some cases, drivers may need extra
+ // information to process rules (eg. Router IP/MAC); and so, we send
+ // port addressing rules to the driver as well irrespective of whether
+ // this instance is the master or not.
defaultRoutingHandler.populatePortAddressingRules(device.id());
if (mastershipService.isLocalMaster(device.id())) {
@@ -646,11 +654,12 @@
tunnelHandler, policyStore);
for (Device device : deviceService.getDevices()) {
- //Irrespective whether the local is a MASTER or not for this device,
- //create group handler instance and push default TTP flow rules.
- //Because in a multi-instance setup, instances can initiate
- //groups for any devices. Also the default TTP rules are needed
- //to be pushed before inserting any IP table entries for any device
+ // Irrespective of whether the local is a MASTER or not for this device,
+ // we need to create a SR-group-handler instance. This is because in a
+ // multi-instance setup, any instance can initiate forwarding/next-objectives
+ // for any switch (even if this instance is a SLAVE or not even connected
+ // to the switch). To handle this, a default-group-handler instance is necessary
+ // per switch.
DefaultGroupHandler groupHandler = DefaultGroupHandler
.createGroupHandler(device.id(), appId,
deviceConfiguration, linkService,
@@ -658,6 +667,11 @@
nsNextObjStore,
subnetNextObjStore);
groupHandlerMap.put(device.id(), groupHandler);
+
+ // Also, in some cases, drivers may need extra
+ // information to process rules (eg. Router IP/MAC); and so, we send
+ // port addressing rules to the driver as well, irrespective of whether
+ // this instance is the master or not.
defaultRoutingHandler.populatePortAddressingRules(device.id());
if (mastershipService.isLocalMaster(device.id())) {