Working with OVS
[vpnservice.git] / interfacemgr / interfacemgr-impl / src / main / java / org / opendaylight / vpnservice / interfacemgr / servicebindings / flowbased / utilities / FlowBasedServicesUtils.java
diff --git a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/servicebindings/flowbased/utilities/FlowBasedServicesUtils.java b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/servicebindings/flowbased/utilities/FlowBasedServicesUtils.java
new file mode 100644 (file)
index 0000000..8df055b
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.interfacemgr.servicebindings.flowbased.utilities;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.interfacemgr.IfmConstants;
+import org.opendaylight.vpnservice.interfacemgr.IfmUtil;
+import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceManagerCommonUtils;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
+import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
+import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteMetadataCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.ServiceBindings;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.StypeOpenflow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.ServicesInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.ServicesInfoKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServices;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+public class FlowBasedServicesUtils {
+    private static final Logger LOG = LoggerFactory.getLogger(FlowBasedServicesUtils.class);
+
+    public static ServicesInfo getServicesInfoForInterface(String interfaceName, DataBroker dataBroker) {
+        ServicesInfoKey servicesInfoKey = new ServicesInfoKey(interfaceName);
+        InstanceIdentifier.InstanceIdentifierBuilder<ServicesInfo> servicesInfoIdentifierBuilder =
+                InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class, servicesInfoKey);
+        Optional<ServicesInfo> servicesInfoOptional = IfmUtil.read(LogicalDatastoreType.CONFIGURATION,
+                servicesInfoIdentifierBuilder.build(), dataBroker);
+
+        if (servicesInfoOptional.isPresent()) {
+            return servicesInfoOptional.get();
+        }
+
+        return null;
+    }
+
+    public static NodeConnectorId getNodeConnectorIdFromInterface(Interface iface, DataBroker dataBroker) {
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState =
+                InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(iface.getName(), dataBroker);
+        List<String> ofportIds = ifState.getLowerLayerIf();
+        return new NodeConnectorId(ofportIds.get(0));
+    }
+
+    public static List<MatchInfo> getMatchInfoForVlanPortAtIngressTable(BigInteger dpId, long portNo, long vlanId) {
+        List<MatchInfo> matches = new ArrayList<>();
+        matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {dpId, BigInteger.valueOf(portNo)}));
+        if (vlanId > 0) {
+            LOG.error("VlanId matching support is not fully available in Be.");
+            matches.add(new MatchInfo(MatchFieldType.vlan_vid, new long[]{vlanId}));
+        }
+        return matches;
+    }
+
+    public static List<MatchInfo> getMatchInfoForTunnelPortAtIngressTable(BigInteger dpId, long portNo, Interface iface) {
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[]{dpId, BigInteger.valueOf(portNo)}));
+        /*IfTunnel tunnel = iface.getAugmentation(IfTunnel.class);
+        TunnelResources tunnelResources = tunnel.getTunnelResources();
+        if (tunnelResources.getTunnelType().isAssignableFrom(TunnelTypeGre.class)) {
+            IfGre ifgre = tunnelResources.getAugmentation(IfGre.class);
+            BigInteger grekey = ifgre.getGreKey();
+            // FIXME: Add tunnel-id match information
+
+        } else if (tunnelResources.getTunnelType().isAssignableFrom(TunnelTypeVxlan.class)) {
+            IfVxlan ifVxlan = tunnelResources.getAugmentation(IfVxlan.class);
+            BigInteger vni = ifVxlan.getVni();
+            // FIXME: Add tunnel-id match information
+        }*/
+
+        return matches;
+    }
+
+    public static List<MatchInfo> getMatchInfoForDispatcherTable(BigInteger dpId, Interface iface,
+                                                                 int interfaceTag, short servicePriority) {
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+                MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, servicePriority),
+                MetaDataUtil.getMetaDataMaskForLPortDispatcher() }));
+        /*if (iface.getType().isAssignableFrom(Tunnel.class)) {
+            IfTunnel tunnel = iface.getAugmentation(IfTunnel.class);
+            TunnelResources tunnelResources = tunnel.getTunnelResources();
+            if (tunnelResources.getTunnelType().isAssignableFrom(TunnelTypeGre.class)) {
+                IfGre ifgre = tunnelResources.getAugmentation(IfGre.class);
+                BigInteger grekey = ifgre.getGreKey();
+                // FIXME: Add tunnel-id match information
+
+            } else if (tunnelResources.getTunnelType().isAssignableFrom(TunnelTypeVxlan.class)) {
+                IfVxlan ifVxlan = tunnelResources.getAugmentation(IfVxlan.class);
+                BigInteger vni = ifVxlan.getVni();
+                // FIXME: Add tunnel-id match information
+            }
+        }*/
+        return matches;
+    }
+
+    public static Long getLPortTag(Interface iface, DataBroker dataBroker) {
+        /*ParentRefs parentRefs = iface.getAugmentation(ParentRefs.class);
+        String portName = parentRefs.getParentInterface();
+        BigInteger dpIdFromInterface = parentRefs.getDatapathNodeIdentifier();
+        String portKey = FlowBasedServicesUtils.getInterfaceRefInfo(dpIdFromInterface.toString(), portName);
+        if (iface.getType().isAssignableFrom(L2vlan.class)) {
+            InterfacesMetaKey interfacesMetaKey = new InterfacesMetaKey(portKey);
+            InterfacesInfoKey interfacesInfoKey = new InterfacesInfoKey(iface.getName());
+            InterfacesInfo interfacesInfo = VlanInterfaceUtilities.getInterfacesInfoFromConfigDS(interfacesMetaKey,
+                    interfacesInfoKey, dataBroker);
+            return interfacesInfo.getLporttag();
+        } else if (iface.getType().isAssignableFrom(Tunnel.class)) {
+            TunnelInterfaceRefInfoKey tunnelInterfaceRefInfoKey = new TunnelInterfaceRefInfoKey(portKey);
+            TunnelInterfaceEntries tunnelInterfaceEntries =
+                    TunnelInterfaceUtilities.getTunnelInterfaceRefEntriesFromConfigDs(
+                            tunnelInterfaceRefInfoKey, iface.getName(), dataBroker);
+            return tunnelInterfaceEntries.getLportTag();
+        } */
+        return 0L;
+    }
+
+    public static void installInterfaceIngressFlow(BigInteger dpId, int vlanId,
+                                                   BoundServices boundServiceNew,
+                                                   DataBroker dataBroker, WriteTransaction t,
+                                                   List<MatchInfo> matches, int lportTag, short tableId) {
+        List<Instruction> instructions = boundServiceNew.getAugmentation(StypeOpenflow.class).getInstruction();
+
+        int serviceInstructionsSize = instructions.size();
+        List<Instruction> instructionSet = new ArrayList<Instruction>();
+        if (vlanId != 0) {
+            // incrementing instructionSize and using it as actionKey. Because it won't clash with any other instructions
+            int actionKey = ++serviceInstructionsSize;
+            instructionSet.add(MDSALUtil.buildAndGetPopVlanActionInstruction(actionKey, ++serviceInstructionsSize));
+        }
+
+        if (lportTag != 0L) {
+            BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(instructions);
+            short sIndex = boundServiceNew.getServicePriority();
+            BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag,
+                    ++sIndex, metadataValues[0]);
+            BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(
+                    MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
+                    MetaDataUtil.METADATA_MASK_LPORT_TAG, metadataValues[1]);
+            instructionSet.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask,
+                    ++serviceInstructionsSize));
+        }
+
+        if (instructions != null && !instructions.isEmpty()) {
+            for (Instruction info : instructions) {
+                // Skip meta data write as that is handled already
+                if (info.getInstruction() instanceof WriteMetadataCase) {
+                    continue;
+                }
+                instructionSet.add(info);
+            }
+        }
+
+        String serviceRef = boundServiceNew.getServiceName();
+        StypeOpenflow stypeOpenflow = boundServiceNew.getAugmentation(StypeOpenflow.class);
+        Flow ingressFlow = MDSALUtil.buildFlowNew(tableId, serviceRef,
+                stypeOpenflow.getFlowPriority(), serviceRef, 0, 0,
+                stypeOpenflow.getFlowCookie(), matches, instructionSet);
+        installFlow(dpId, ingressFlow, dataBroker, t);
+    }
+
+    private static void installFlow(BigInteger dpId, Flow flow, DataBroker dataBroker, WriteTransaction t) {
+        FlowKey flowKey = new FlowKey(new FlowId(flow.getId()));
+        Node nodeDpn = buildInventoryDpnNode(dpId);
+        InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
+                .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
+                .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class,flowKey).build();
+
+        t.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
+    }
+
+    private static Node buildInventoryDpnNode(BigInteger dpnId) {
+        NodeId nodeId = new NodeId("openflow:" + dpnId);
+        Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
+
+        return nodeDpn;
+    }
+
+    public static void installLPortDispatcherFlow(BigInteger dpId, BoundServices boundService, Interface iface,
+                                                  DataBroker dataBroker, WriteTransaction t, int interfaceTag) {
+        LOG.debug("Installing LPort Dispatcher Flows {}, {}", dpId, iface);
+        short serviceIndex = boundService.getServicePriority();
+        String serviceRef = boundService.getServiceName();
+        List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForDispatcherTable(dpId, iface,
+                interfaceTag, serviceIndex);
+
+        // Get the metadata and mask from the service's write metadata instruction
+        StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
+        List<Instruction> serviceInstructions = stypeOpenFlow.getInstruction();
+        int instructionSize = serviceInstructions.size();
+        BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(serviceInstructions);
+        BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, ++serviceIndex, metadataValues[0]);
+        BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
+                MetaDataUtil.METADATA_MASK_LPORT_TAG, metadataValues[1]);
+
+        // build the final instruction for LPort Dispatcher table flow entry
+        List<Instruction> instructions = new ArrayList<Instruction>();
+        instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++instructionSize));
+        if (serviceInstructions != null && !serviceInstructions.isEmpty()) {
+            for (Instruction info : serviceInstructions) {
+                // Skip meta data write as that is handled already
+                if (info.getInstruction() instanceof WriteMetadataCase) {
+                    continue;
+                }
+                instructions.add(info);
+            }
+        }
+
+        // build the flow and install it
+        Flow ingressFlow = MDSALUtil.buildFlowNew(stypeOpenFlow.getDispatcherTableId(), serviceRef,
+                boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches, instructions);
+        installFlow(dpId, ingressFlow, dataBroker, t);
+    }
+
+    public static void removeIngressFlow(Interface iface, BoundServices serviceOld, BigInteger dpId,
+                                         DataBroker dataBroker, WriteTransaction t) {
+        LOG.debug("Removing Ingress Flows");
+        String flowKeyStr = iface.getName() + serviceOld.getServicePriority() +
+                serviceOld.getServiceName() + IfmConstants.VLAN_INTERFACE_INGRESS_TABLE;
+        FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
+        Node nodeDpn = buildInventoryDpnNode(dpId);
+        InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
+                .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
+                .child(Table.class, new TableKey(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
+
+        t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
+    }
+
+    public static void removeLPortDispatcherFlow(BigInteger dpId, Interface iface, BoundServices boundServicesOld,
+                                                 DataBroker dataBroker, WriteTransaction t) {
+        LOG.debug("Removing LPort Dispatcher Flows {}, {}", dpId, iface);
+        Long interfaceTag = FlowBasedServicesUtils.getLPortTag(iface, dataBroker);
+
+        StypeOpenflow stypeOpenFlow = boundServicesOld.getAugmentation(StypeOpenflow.class);
+        String flowKeyStr = iface.getName() + boundServicesOld.getServicePriority() +
+                boundServicesOld.getServiceName() + stypeOpenFlow.getDispatcherTableId();
+        FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
+        Node nodeDpn = buildInventoryDpnNode(dpId);
+        InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
+                .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
+                .child(Table.class, new TableKey(stypeOpenFlow.getDispatcherTableId())).child(Flow.class, flowKey).build();
+
+        t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
+    }
+
+    public static String getInterfaceRefInfo(String dpId, String portName) {
+        String portRefInfo = "";
+        if (!"".equals(dpId)) {
+            portRefInfo = dpId.toString() + ":";
+        }
+        portRefInfo = portRefInfo + portName;
+        return portRefInfo;
+    }
+}
\ No newline at end of file