2 * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.vpnservice.interfacemgr.servicebindings.flowbased.utilities;
10 import com.google.common.base.Optional;
11 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
12 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
13 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
14 import org.opendaylight.vpnservice.interfacemgr.IfmConstants;
15 import org.opendaylight.vpnservice.interfacemgr.IfmUtil;
16 import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceManagerCommonUtils;
17 import org.opendaylight.vpnservice.mdsalutil.*;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteMetadataCase;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.ServiceBindings;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.StypeOpenflow;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.ServicesInfo;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.ServicesInfoKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServices;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
42 import java.math.BigInteger;
43 import java.util.ArrayList;
44 import java.util.List;
46 public class FlowBasedServicesUtils {
47 private static final Logger LOG = LoggerFactory.getLogger(FlowBasedServicesUtils.class);
49 public static ServicesInfo getServicesInfoForInterface(String interfaceName, DataBroker dataBroker) {
50 ServicesInfoKey servicesInfoKey = new ServicesInfoKey(interfaceName);
51 InstanceIdentifier.InstanceIdentifierBuilder<ServicesInfo> servicesInfoIdentifierBuilder =
52 InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class, servicesInfoKey);
53 Optional<ServicesInfo> servicesInfoOptional = IfmUtil.read(LogicalDatastoreType.CONFIGURATION,
54 servicesInfoIdentifierBuilder.build(), dataBroker);
56 if (servicesInfoOptional.isPresent()) {
57 return servicesInfoOptional.get();
63 public static NodeConnectorId getNodeConnectorIdFromInterface(Interface iface, DataBroker dataBroker) {
64 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState =
65 InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(iface.getName(), dataBroker);
67 List<String> ofportIds = ifState.getLowerLayerIf();
68 return new NodeConnectorId(ofportIds.get(0));
73 public static List<MatchInfo> getMatchInfoForVlanPortAtIngressTable(BigInteger dpId, long portNo, long vlanId) {
74 List<MatchInfo> matches = new ArrayList<>();
75 matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {dpId, BigInteger.valueOf(portNo)}));
77 LOG.error("VlanId matching support is not fully available in Be.");
78 matches.add(new MatchInfo(MatchFieldType.vlan_vid, new long[]{vlanId}));
83 public static List<MatchInfo> getMatchInfoForTunnelPortAtIngressTable(BigInteger dpId, long portNo, Interface iface) {
84 List<MatchInfo> matches = new ArrayList<MatchInfo>();
85 matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[]{dpId, BigInteger.valueOf(portNo)}));
89 public static List<MatchInfo> getMatchInfoForDispatcherTable(BigInteger dpId, Interface iface,
90 int interfaceTag, short servicePriority) {
91 List<MatchInfo> matches = new ArrayList<MatchInfo>();
92 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
93 MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, servicePriority),
94 MetaDataUtil.getMetaDataMaskForLPortDispatcher() }));
98 public static Long getLPortTag(Interface iface, DataBroker dataBroker) {
99 /*ParentRefs parentRefs = iface.getAugmentation(ParentRefs.class);
100 String portName = parentRefs.getParentInterface();
101 BigInteger dpIdFromInterface = parentRefs.getDatapathNodeIdentifier();
102 String portKey = FlowBasedServicesUtils.getInterfaceRefInfo(dpIdFromInterface.toString(), portName);
103 if (iface.getType().isAssignableFrom(L2vlan.class)) {
104 InterfacesMetaKey interfacesMetaKey = new InterfacesMetaKey(portKey);
105 InterfacesInfoKey interfacesInfoKey = new InterfacesInfoKey(iface.getName());
106 InterfacesInfo interfacesInfo = VlanInterfaceUtilities.getInterfacesInfoFromConfigDS(interfacesMetaKey,
107 interfacesInfoKey, dataBroker);
108 return interfacesInfo.getLporttag();
109 } else if (iface.getType().isAssignableFrom(Tunnel.class)) {
110 TunnelInterfaceRefInfoKey tunnelInterfaceRefInfoKey = new TunnelInterfaceRefInfoKey(portKey);
111 TunnelInterfaceEntries tunnelInterfaceEntries =
112 TunnelInterfaceUtilities.getTunnelInterfaceRefEntriesFromConfigDs(
113 tunnelInterfaceRefInfoKey, iface.getName(), dataBroker);
114 return tunnelInterfaceEntries.getLportTag();
119 public static void installInterfaceIngressFlow(BigInteger dpId, String interfaceName, int vlanId,
120 BoundServices boundServiceNew,
121 DataBroker dataBroker, WriteTransaction t,
122 List<MatchInfo> matches, int lportTag, short tableId) {
123 List<Instruction> instructions = boundServiceNew.getAugmentation(StypeOpenflow.class).getInstruction();
125 int serviceInstructionsSize = instructions.size();
126 List<Instruction> instructionSet = new ArrayList<Instruction>();
128 // incrementing instructionSize and using it as actionKey. Because it won't clash with any other instructions
129 int actionKey = ++serviceInstructionsSize;
130 instructionSet.add(MDSALUtil.buildAndGetPopVlanActionInstruction(actionKey, ++serviceInstructionsSize));
133 if (lportTag != 0L) {
134 BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(instructions);
135 short sIndex = boundServiceNew.getServicePriority();
136 BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag,
137 ++sIndex, metadataValues[0]);
138 BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(
139 MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
140 MetaDataUtil.METADATA_MASK_LPORT_TAG, metadataValues[1]);
141 instructionSet.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask,
142 ++serviceInstructionsSize));
145 if (instructions != null && !instructions.isEmpty()) {
146 for (Instruction info : instructions) {
147 // Skip meta data write as that is handled already
148 if (info.getInstruction() instanceof WriteMetadataCase) {
151 instructionSet.add(info);
155 String serviceRef = boundServiceNew.getServiceName();
156 String flowRef = getFlowRef(dpId, interfaceName, boundServiceNew);
157 StypeOpenflow stypeOpenflow = boundServiceNew.getAugmentation(StypeOpenflow.class);
158 Flow ingressFlow = MDSALUtil.buildFlowNew(tableId, flowRef,
159 stypeOpenflow.getFlowPriority(), serviceRef, 0, 0,
160 stypeOpenflow.getFlowCookie(), matches, instructionSet);
161 installFlow(dpId, ingressFlow, t);
164 public static void installFlow(BigInteger dpId, Flow flow, WriteTransaction t) {
165 FlowKey flowKey = new FlowKey(new FlowId(flow.getId()));
166 Node nodeDpn = buildInventoryDpnNode(dpId);
167 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
168 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
169 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class,flowKey).build();
171 t.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
174 public static void removeFlow(String flowRef, BigInteger dpId, WriteTransaction t) {
175 LOG.debug("Removing Ingress Flows");
176 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
177 Node nodeDpn = buildInventoryDpnNode(dpId);
178 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
179 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
180 .child(Table.class, new TableKey(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
182 t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
185 private static Node buildInventoryDpnNode(BigInteger dpnId) {
186 NodeId nodeId = new NodeId("openflow:" + dpnId);
187 Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
192 public static void installLPortDispatcherFlow(BigInteger dpId, BoundServices boundService, Interface iface,
193 WriteTransaction t, int interfaceTag) {
194 LOG.debug("Installing LPort Dispatcher Flows {}, {}", dpId, iface);
195 short serviceIndex = boundService.getServicePriority();
196 String serviceRef = boundService.getServiceName();
197 List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForDispatcherTable(dpId, iface,
198 interfaceTag, serviceIndex);
200 // Get the metadata and mask from the service's write metadata instruction
201 StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
202 List<Instruction> serviceInstructions = stypeOpenFlow.getInstruction();
203 int instructionSize = serviceInstructions.size();
204 BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(serviceInstructions);
205 BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, ++serviceIndex, metadataValues[0]);
206 BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
207 MetaDataUtil.METADATA_MASK_LPORT_TAG, metadataValues[1]);
209 // build the final instruction for LPort Dispatcher table flow entry
210 List<Instruction> instructions = new ArrayList<Instruction>();
211 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++instructionSize));
212 if (serviceInstructions != null && !serviceInstructions.isEmpty()) {
213 for (Instruction info : serviceInstructions) {
214 // Skip meta data write as that is handled already
215 if (info.getInstruction() instanceof WriteMetadataCase) {
218 instructions.add(info);
222 // build the flow and install it
223 String flowRef = getFlowRef(dpId, iface.getName(), boundService);
224 Flow ingressFlow = MDSALUtil.buildFlowNew(stypeOpenFlow.getDispatcherTableId(), flowRef,
225 boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches, instructions);
226 installFlow(dpId, ingressFlow, t);
229 public static void removeIngressFlow(Interface iface, BoundServices serviceOld, BigInteger dpId, WriteTransaction t) {
230 LOG.debug("Removing Ingress Flows");
231 String flowKeyStr = getFlowRef(dpId, iface.getName(), serviceOld);
232 FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
233 Node nodeDpn = buildInventoryDpnNode(dpId);
234 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
235 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
236 .child(Table.class, new TableKey(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
238 t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
241 public static void removeLPortDispatcherFlow(BigInteger dpId, Interface iface, BoundServices boundServicesOld, WriteTransaction t) {
242 LOG.debug("Removing LPort Dispatcher Flows {}, {}", dpId, iface);
244 StypeOpenflow stypeOpenFlow = boundServicesOld.getAugmentation(StypeOpenflow.class);
245 // build the flow and install it
246 String flowRef = getFlowRef(dpId, iface.getName(), boundServicesOld);
247 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
248 Node nodeDpn = buildInventoryDpnNode(dpId);
249 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
250 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
251 .child(Table.class, new TableKey(stypeOpenFlow.getDispatcherTableId())).child(Flow.class, flowKey).build();
253 t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
256 private static String getFlowRef(BigInteger dpnId, String iface, BoundServices service) {
257 return new StringBuffer().append(dpnId).append(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE).append(NwConstants.FLOWID_SEPARATOR)
258 .append(iface).append(NwConstants.FLOWID_SEPARATOR).append(service.getServiceName()).append(NwConstants.FLOWID_SEPARATOR)
259 .append(service.getServicePriority()).toString();