QoS: DSCP marking doesn't work for dual stack VMs 65/72165/9
authorRavindra Thakur <ravindra.nath.thakur@ericsson.com>
Tue, 22 May 2018 14:08:15 +0000 (19:38 +0530)
committerSam Hague <shague@redhat.com>
Mon, 11 Jun 2018 20:51:15 +0000 (20:51 +0000)
Added support for DSCP marking for dual stack VM so that DSCP
marking flows are present for both ipv4 and ipv6.

Change-Id: If49662abfe8f6673c6f1c96d00376eadbefcfc51
Signed-off-by: Ravindra Thakur <ravindra.nath.thakur@ericsson.com>
qosservice/impl/src/main/java/org/opendaylight/netvirt/qosservice/QosConstants.java
qosservice/impl/src/main/java/org/opendaylight/netvirt/qosservice/QosInterfaceStateChangeListener.java
qosservice/impl/src/main/java/org/opendaylight/netvirt/qosservice/QosNeutronPortChangeListener.java
qosservice/impl/src/main/java/org/opendaylight/netvirt/qosservice/QosNeutronUtils.java

index 77d522b5d0a536c04a1cab4523814890d4be6410..3eef05b27e08f3046dc105cd2a66232fba178782 100644 (file)
@@ -17,4 +17,7 @@ public interface QosConstants {
     String FELIX_FILEINSTALL_FILENAME = "felix.fileinstall.filename";
     String SERVICE_PID = "service.pid";
     String QOS_ALERT_OWNER_ENTITY_TYPE = "netvirt-qos-owner-entity";
+
+    short IPV4_ADDR_MASK_BIT = 0;
+    short IPV6_ADDR_MASK_BIT = 1;
 }
index 99167461b18ccb62c191c1cdaf68a33aa25f5f1b..d9355dd43e41675f9e4eb5a95bd540eddc6d81b9 100644 (file)
@@ -15,6 +15,7 @@ import javax.inject.Singleton;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
+import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.srm.RecoverableListener;
 import org.opendaylight.genius.srm.ServiceRecoveryRegistry;
 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
@@ -127,7 +128,8 @@ public class QosInterfaceStateChangeListener extends AsyncClusteredDataTreeChang
                 return Optional.fromJavaUtil(uuid.toJavaUtil().map(qosNeutronUtils::getNeutronPort));
             }
             LOG.trace("Qos Service : interface {} clearing stale flow entries if any", portName);
-            qosNeutronUtils.removeStaleFlowEntry(intrf);
+            qosNeutronUtils.removeStaleFlowEntry(intrf, NwConstants.ETHTYPE_IPV4);
+            qosNeutronUtils.removeStaleFlowEntry(intrf, NwConstants.ETHTYPE_IPV6);
         }
         return Optional.absent();
     }
index 98eadb2cb9db89fc9fd20423579e1c288aa8dd0c..61ae08e4b1a3ebdac58a10807a5635b5fcc4a492 100644 (file)
@@ -7,18 +7,24 @@
  */
 package org.opendaylight.netvirt.qosservice;
 
+import java.math.BigInteger;
+import java.util.Collections;
 import javax.annotation.PostConstruct;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
+import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.srm.RecoverableListener;
 import org.opendaylight.genius.srm.ServiceRecoveryRegistry;
+import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
 import org.opendaylight.netvirt.qosservice.recovery.QosServiceRecoveryHandler;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.ext.rev160613.QosPortExtension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.QosPolicy;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -30,14 +36,20 @@ public class QosNeutronPortChangeListener extends AsyncClusteredDataTreeChangeLi
     private static final Logger LOG = LoggerFactory.getLogger(QosNeutronPortChangeListener.class);
     private final DataBroker dataBroker;
     private final QosNeutronUtils qosNeutronUtils;
+    private final QosEosHandler qosEosHandler;
+    private final JobCoordinator jobCoordinator;
 
     @Inject
     public QosNeutronPortChangeListener(final DataBroker dataBroker,
             final QosNeutronUtils qosNeutronUtils, final QosServiceRecoveryHandler qosServiceRecoveryHandler,
-                                        final ServiceRecoveryRegistry serviceRecoveryRegistry) {
+                                        final ServiceRecoveryRegistry serviceRecoveryRegistry,
+                                        final QosEosHandler qosEosHandler,
+                                        final JobCoordinator jobCoordinator) {
         super(Port.class, QosNeutronPortChangeListener.class);
         this.dataBroker = dataBroker;
         this.qosNeutronUtils = qosNeutronUtils;
+        this.qosEosHandler = qosEosHandler;
+        this.jobCoordinator = jobCoordinator;
         serviceRecoveryRegistry.addRecoverableListener(qosServiceRecoveryHandler.buildServiceRegistryKey(),
                 this);
         LOG.debug("{} created",  getClass().getSimpleName());
@@ -99,5 +111,49 @@ public class QosNeutronPortChangeListener extends AsyncClusteredDataTreeChangeLi
             qosNeutronUtils.removeFromQosPortsCache(originalQos.getQosPolicyId(), original);
         }
 
+        if (qosEosHandler.isQosClusterOwner()) {
+            checkForPortIpAddressUpdate(original, update);
+        }
+    }
+
+
+
+    private void checkForPortIpAddressUpdate(Port original, Port update) {
+        QosPolicy qosPolicy = qosNeutronUtils.getQosPolicy(update);
+        if (qosPolicy == null || !qosNeutronUtils.hasDscpMarkingRule(qosPolicy)) {
+            return;
+        }
+        int origAddrMask = qosNeutronUtils.getIpVersions(original);
+        int updateAddrMask = qosNeutronUtils.getIpVersions(update);
+
+        if (origAddrMask == updateAddrMask) {
+            return;
+        }
+        jobCoordinator.enqueueJob("QosPort-" + update.getUuid().getValue(), () -> {
+            short dscpVal = qosPolicy.getDscpmarkingRules().get(0).getDscpMark();
+            String ifName = update.getUuid().getValue();
+            BigInteger dpnId = qosNeutronUtils.getDpnForInterface(ifName);
+            if (dpnId.equals(BigInteger.ZERO)) {
+                LOG.warn("dpnId not found for intf {}", ifName);
+                return Collections.emptyList();
+            }
+            Interface intf = qosNeutronUtils.getInterfaceStateFromOperDS(ifName);
+            if (qosNeutronUtils.hasIpv4Addr(origAddrMask) && !qosNeutronUtils.hasIpv4Addr(updateAddrMask)) {
+                LOG.debug("removing ipv4 flow for port: {}", update.getUuid().getValue());
+                qosNeutronUtils.removeFlow(dpnId, ifName, NwConstants.ETHTYPE_IPV4, intf);
+            } else if (!qosNeutronUtils.hasIpv4Addr(origAddrMask) && qosNeutronUtils.hasIpv4Addr(updateAddrMask)) {
+                LOG.debug("adding ipv4 flow for port: {}, dscp: {}", update.getUuid().getValue(), dscpVal);
+                qosNeutronUtils.addFlow(dpnId, dscpVal, ifName, NwConstants.ETHTYPE_IPV4, intf);
+            }
+
+            if (qosNeutronUtils.hasIpv6Addr(origAddrMask) && !qosNeutronUtils.hasIpv6Addr(updateAddrMask)) {
+                LOG.debug("removing ipv6 flow for port: {}", update.getUuid().getValue());
+                qosNeutronUtils.removeFlow(dpnId, ifName, NwConstants.ETHTYPE_IPV6, intf);
+            } else if (!qosNeutronUtils.hasIpv6Addr(origAddrMask) && qosNeutronUtils.hasIpv6Addr(updateAddrMask)) {
+                LOG.debug("adding ipv6 flow for port: {}, dscp: {}", update.getUuid().getValue(), dscpVal);
+                qosNeutronUtils.addFlow(dpnId, dscpVal, ifName, NwConstants.ETHTYPE_IPV6, intf);
+            }
+            return Collections.emptyList();
+        });
     }
 }
index 401a1e98003c6eb97f5e28dd599128446f2b2206..086167b8849ad55afc3a31972b03af2b9b67daaa 100644 (file)
@@ -45,7 +45,6 @@ import org.opendaylight.genius.utils.ServiceIndex;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
@@ -79,6 +78,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev15060
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.ext.rev160613.QosNetworkExtension;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.ext.rev160613.QosPortExtension;
@@ -221,14 +221,14 @@ public class QosNeutronUtils {
 
         QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
 
-        jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () ->
-                Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
-                    // handle DSCP Mark Rules update
-                    if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
-                            && !qosPolicy.getDscpmarkingRules().isEmpty()) {
-                        setPortDscpMarking(port, qosPolicy.getDscpmarkingRules().get(0));
-                    }
-                })));
+        jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
+            // handle DSCP Mark Rules update
+            if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
+                    && !qosPolicy.getDscpmarkingRules().isEmpty()) {
+                setPortDscpMarking(port, qosPolicy.getDscpmarkingRules().get(0));
+            }
+            return Collections.emptyList();
+        });
     }
 
     public void handleNeutronPortQosUpdate(Port port, Uuid qosUuidNew, Uuid qosUuidOld) {
@@ -487,7 +487,7 @@ public class QosNeutronUtils {
 
         BigInteger dpnId = getDpnForInterface(port.getUuid().getValue());
         String ifName = port.getUuid().getValue();
-        IpAddress ipAddress = port.getFixedIps().get(0).getIpAddress();
+        Interface ifState = getInterfaceStateFromOperDS(ifName);
         Short dscpValue = dscpMark.getDscpMark();
 
         if (dpnId.equals(BigInteger.ZERO)) {
@@ -495,8 +495,18 @@ public class QosNeutronUtils {
             return;
         }
 
+        int ipVersions = getIpVersions(port);
+
         //1. OF rules
-        addFlow(dpnId, dscpValue, ifName, ipAddress, getInterfaceStateFromOperDS(ifName));
+        if (hasIpv4Addr(ipVersions)) {
+            LOG.trace("setting ipv4 flow for port: {}, dscp: {}", ifName, dscpValue);
+            addFlow(dpnId, dscpValue, ifName, NwConstants.ETHTYPE_IPV4, ifState);
+        }
+        if (hasIpv6Addr(ipVersions)) {
+            LOG.trace("setting ipv6 flow for port: {}, dscp: {}", ifName, dscpValue);
+            addFlow(dpnId, dscpValue, ifName, NwConstants.ETHTYPE_IPV6, ifState);
+        }
+
         if (qosServiceConfiguredPorts.add(port.getUuid())) {
             // bind qos service to interface
             bindservice(ifName);
@@ -517,15 +527,25 @@ public class QosNeutronUtils {
             LOG.info("DPN ID for port {} not found", port);
             return;
         }
+        Interface intf = getInterfaceStateFromOperDS(ifName);
 
         //unbind service from interface
         unbindservice(ifName);
         // 1. OF
-        removeFlow(dpnId, ifName, getInterfaceStateFromOperDS(ifName));
+        int ipVersions = getIpVersions(port);
+        if (hasIpv4Addr(ipVersions)) {
+            removeFlow(dpnId, ifName, NwConstants.ETHTYPE_IPV4, intf);
+        }
+        if (hasIpv6Addr(ipVersions)) {
+            removeFlow(dpnId, ifName, NwConstants.ETHTYPE_IPV6, intf);
+        }
         qosServiceConfiguredPorts.remove(port.getUuid());
     }
 
     public void unsetPortDscpMark(Port port, Interface intrf) {
+        if (!qosEosHandler.isQosClusterOwner()) {
+            return;
+        }
         LOG.trace("Removing dscp marking rule from Port {}", port);
 
         BigInteger dpnId = getDpIdFromInterface(intrf);
@@ -536,7 +556,14 @@ public class QosNeutronUtils {
             return;
         }
         unbindservice(ifName);
-        removeFlow(dpnId, ifName, intrf);
+        int ipVersions = getIpVersions(port);
+        if (hasIpv4Addr(ipVersions)) {
+            removeFlow(dpnId, ifName, NwConstants.ETHTYPE_IPV4, intrf);
+        }
+        if (hasIpv6Addr(ipVersions)) {
+            removeFlow(dpnId, ifName, NwConstants.ETHTYPE_IPV6, intrf);
+        }
+        qosServiceConfiguredPorts.remove(port.getUuid());
     }
 
     private static BigInteger getDpIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
@@ -610,7 +637,7 @@ public class QosNeutronUtils {
         return InstanceIdentifier.builder(BridgeInterfaceInfo.class).child(BridgeEntry.class, bridgeEntryKey).build();
     }
 
-    public void removeStaleFlowEntry(Interface intrf) {
+    public void removeStaleFlowEntry(Interface intrf, int ethType) {
         List<MatchInfo> matches = new ArrayList<>();
 
         BigInteger dpnId = getDpIdFromInterface(intrf);
@@ -618,13 +645,13 @@ public class QosNeutronUtils {
         Integer ifIndex = intrf.getIfIndex();
         matches.add(new MatchMetadata(MetaDataUtil.getLportTagMetaData(ifIndex), MetaDataUtil.METADATA_MASK_LPORT_TAG));
         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.QOS_DSCP_TABLE,
-                getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex),
+                getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex, ethType),
                 QosConstants.QOS_DEFAULT_FLOW_PRIORITY, "QoSRemoveFlow", 0, 0, NwConstants.COOKIE_QOS_TABLE,
                 matches, null);
         mdsalUtils.removeFlow(flowEntity);
     }
 
-    private void addFlow(BigInteger dpnId, Short dscpValue, String ifName, IpAddress ipAddress, Interface ifState) {
+    public void addFlow(BigInteger dpnId, Short dscpValue, String ifName, int ethType, Interface ifState) {
         if (ifState == null) {
             LOG.trace("Could not find the ifState for interface {}", ifName);
             return;
@@ -632,11 +659,7 @@ public class QosNeutronUtils {
         Integer ifIndex = ifState.getIfIndex();
 
         List<MatchInfo> matches = new ArrayList<>();
-        if (ipAddress.getIpv4Address() != null) {
-            matches.add(new MatchEthernetType(NwConstants.ETHTYPE_IPV4));
-        } else {
-            matches.add(new MatchEthernetType(NwConstants.ETHTYPE_IPV6));
-        }
+        matches.add(new MatchEthernetType(ethType));
         matches.add(new MatchMetadata(MetaDataUtil.getLportTagMetaData(ifIndex), MetaDataUtil.METADATA_MASK_LPORT_TAG));
 
         List<ActionInfo> actionsInfos = new ArrayList<>();
@@ -645,13 +668,13 @@ public class QosNeutronUtils {
 
         List<InstructionInfo> instructions = Collections.singletonList(new InstructionApplyActions(actionsInfos));
         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.QOS_DSCP_TABLE,
-                getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex),
+                getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex, ethType),
                 QosConstants.QOS_DEFAULT_FLOW_PRIORITY, "QoSConfigFlow", 0, 0, NwConstants.COOKIE_QOS_TABLE,
                 matches, instructions);
         mdsalUtils.installFlow(flowEntity);
     }
 
-    private void removeFlow(BigInteger dpnId, String ifName, Interface ifState) {
+    public void removeFlow(BigInteger dpnId, String ifName, int ethType, Interface ifState) {
         if (ifState == null) {
             LOG.trace("Could not find the ifState for interface {}", ifName);
             return;
@@ -659,7 +682,7 @@ public class QosNeutronUtils {
         Integer ifIndex = ifState.getIfIndex();
 
         mdsalUtils.removeFlow(dpnId, NwConstants.QOS_DSCP_TABLE,
-                new FlowId(getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex)));
+                new FlowId(getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex, ethType)));
     }
 
     @Nullable
@@ -720,8 +743,10 @@ public class QosNeutronUtils {
     }
 
     @Nonnull
-    public static String getQosFlowId(short tableId, BigInteger dpId, int lportTag) {
-        return String.valueOf(tableId) + dpId + lportTag;
+    public static String getQosFlowId(short tableId, BigInteger dpId, int lportTag, int ethType) {
+        return new StringBuilder().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(dpId)
+                .append(NwConstants.FLOWID_SEPARATOR).append(lportTag)
+                .append(NwConstants.FLOWID_SEPARATOR).append(ethType).toString();
     }
 
     public boolean portHasQosPolicy(Port port) {
@@ -756,6 +781,13 @@ public class QosNeutronUtils {
         return qosPolicy;
     }
 
+    public boolean hasDscpMarkingRule(QosPolicy qosPolicy) {
+        if (qosPolicy != null) {
+            return qosPolicy.getDscpmarkingRules() != null && !qosPolicy.getDscpmarkingRules().isEmpty();
+        }
+        return false;
+    }
+
     public void addToPortCache(Port port) {
         neutronPortMap.put(port.getUuid(), port);
     }
@@ -800,4 +832,29 @@ public class QosNeutronUtils {
         }
     }
 
+    public int getIpVersions(Port port) {
+        int versions = 0;
+        for (FixedIps fixedIp: port.getFixedIps()) {
+            if (fixedIp.getIpAddress().getIpv4Address() != null) {
+                versions |= (1 << QosConstants.IPV4_ADDR_MASK_BIT);
+            } else if (fixedIp.getIpAddress().getIpv6Address() != null) {
+                versions |= (1 << QosConstants.IPV6_ADDR_MASK_BIT);
+            }
+        }
+        return versions;
+    }
+
+    public boolean hasIpv4Addr(int versions) {
+        if ((versions & (1 << QosConstants.IPV4_ADDR_MASK_BIT)) != 0) {
+            return true;
+        }
+        return false;
+    }
+
+    public boolean hasIpv6Addr(int versions) {
+        if ((versions & (1 << QosConstants.IPV6_ADDR_MASK_BIT)) != 0) {
+            return true;
+        }
+        return false;
+    }
 }