/* * 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 servicesInfoIdentifierBuilder = InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class, servicesInfoKey); Optional 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 ofportIds = ifState.getLowerLayerIf(); return new NodeConnectorId(ofportIds.get(0)); } public static List getMatchInfoForVlanPortAtIngressTable(BigInteger dpId, long portNo, long vlanId) { List 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 getMatchInfoForTunnelPortAtIngressTable(BigInteger dpId, long portNo, Interface iface) { List matches = new ArrayList(); matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[]{dpId, BigInteger.valueOf(portNo)})); return matches; } public static List getMatchInfoForDispatcherTable(BigInteger dpId, Interface iface, int interfaceTag, short servicePriority) { List matches = new ArrayList(); matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] { MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, servicePriority), MetaDataUtil.getMetaDataMaskForLPortDispatcher() })); 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 matches, int lportTag, short tableId) { List instructions = boundServiceNew.getAugmentation(StypeOpenflow.class).getInstruction(); int serviceInstructionsSize = instructions.size(); List instructionSet = new ArrayList(); 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 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 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 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 instructions = new ArrayList(); 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 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 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; } }