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 java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.Comparator;
14 import java.util.List;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.vpnservice.interfacemgr.IfmConstants;
20 import org.opendaylight.vpnservice.interfacemgr.IfmUtil;
21 import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceManagerCommonUtils;
22 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
23 import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
24 import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
25 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
26 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteMetadataCase;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.ServiceBindings;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.StypeOpenflow;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.ServicesInfo;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.ServicesInfoKey;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServices;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfL2vlan;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
52 import com.google.common.base.Optional;
54 public class FlowBasedServicesUtils {
55 private static final Logger LOG = LoggerFactory.getLogger(FlowBasedServicesUtils.class);
57 public static ServicesInfo getServicesInfoForInterface(String interfaceName, DataBroker dataBroker) {
58 ServicesInfoKey servicesInfoKey = new ServicesInfoKey(interfaceName);
59 InstanceIdentifier.InstanceIdentifierBuilder<ServicesInfo> servicesInfoIdentifierBuilder =
60 InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class, servicesInfoKey);
61 Optional<ServicesInfo> servicesInfoOptional = IfmUtil.read(LogicalDatastoreType.CONFIGURATION,
62 servicesInfoIdentifierBuilder.build(), dataBroker);
64 if (servicesInfoOptional.isPresent()) {
65 return servicesInfoOptional.get();
71 public static NodeConnectorId getNodeConnectorIdFromInterface(Interface iface, DataBroker dataBroker) {
72 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState =
73 InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(iface.getName(), dataBroker);
75 List<String> ofportIds = ifState.getLowerLayerIf();
76 return new NodeConnectorId(ofportIds.get(0));
81 public static List<MatchInfo> getMatchInfoForVlanPortAtIngressTable(BigInteger dpId, long portNo, Interface iface) {
82 List<MatchInfo> matches = new ArrayList<>();
83 matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {dpId, BigInteger.valueOf(portNo)}));
85 IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
86 if(l2vlan != null && l2vlan.getL2vlanMode() != IfL2vlan.L2vlanMode.Transparent){
87 vlanId = l2vlan.getVlanId() == null ? 0 : l2vlan.getVlanId().getValue();
90 matches.add(new MatchInfo(MatchFieldType.vlan_vid, new long[]{vlanId}));
95 public static List<MatchInfo> getMatchInfoForTunnelPortAtIngressTable(BigInteger dpId, long portNo, Interface iface) {
96 List<MatchInfo> matches = new ArrayList<MatchInfo>();
97 matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[]{dpId, BigInteger.valueOf(portNo)}));
101 public static List<MatchInfo> getMatchInfoForDispatcherTable(BigInteger dpId, Interface iface,
102 int interfaceTag, short servicePriority) {
103 List<MatchInfo> matches = new ArrayList<MatchInfo>();
104 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
105 MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, servicePriority),
106 MetaDataUtil.getMetaDataMaskForLPortDispatcher() }));
110 public static Long getLPortTag(Interface iface, DataBroker dataBroker) {
111 /*ParentRefs parentRefs = iface.getAugmentation(ParentRefs.class);
112 String portName = parentRefs.getParentInterface();
113 BigInteger dpIdFromInterface = parentRefs.getDatapathNodeIdentifier();
114 String portKey = FlowBasedServicesUtils.getInterfaceRefInfo(dpIdFromInterface.toString(), portName);
115 if (iface.getType().isAssignableFrom(L2vlan.class)) {
116 InterfacesMetaKey interfacesMetaKey = new InterfacesMetaKey(portKey);
117 InterfacesInfoKey interfacesInfoKey = new InterfacesInfoKey(iface.getName());
118 InterfacesInfo interfacesInfo = VlanInterfaceUtilities.getInterfacesInfoFromConfigDS(interfacesMetaKey,
119 interfacesInfoKey, dataBroker);
120 return interfacesInfo.getLporttag();
121 } else if (iface.getType().isAssignableFrom(Tunnel.class)) {
122 TunnelInterfaceRefInfoKey tunnelInterfaceRefInfoKey = new TunnelInterfaceRefInfoKey(portKey);
123 TunnelInterfaceEntries tunnelInterfaceEntries =
124 TunnelInterfaceUtilities.getTunnelInterfaceRefEntriesFromConfigDs(
125 tunnelInterfaceRefInfoKey, iface.getName(), dataBroker);
126 return tunnelInterfaceEntries.getLportTag();
131 public static void installInterfaceIngressFlow(BigInteger dpId, Interface iface,
132 BoundServices boundServiceNew,
134 List<MatchInfo> matches, int lportTag, short tableId) {
135 List<Instruction> instructions = boundServiceNew.getAugmentation(StypeOpenflow.class).getInstruction();
137 int serviceInstructionsSize = instructions.size();
138 List<Instruction> instructionSet = new ArrayList<Instruction>();
140 IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
141 if(l2vlan != null && l2vlan.getVlanId() != null){
142 vlanId = l2vlan.getVlanId().getValue();
145 // incrementing instructionSize and using it as actionKey. Because it won't clash with any other instructions
146 int actionKey = ++serviceInstructionsSize;
147 instructionSet.add(MDSALUtil.buildAndGetPopVlanActionInstruction(actionKey, ++serviceInstructionsSize));
150 if (lportTag != 0L) {
151 BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(instructions);
152 short sIndex = boundServiceNew.getServicePriority();
153 BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag,
154 ++sIndex, metadataValues[0]);
155 BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(
156 MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
157 MetaDataUtil.METADATA_MASK_LPORT_TAG, metadataValues[1]);
158 instructionSet.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask,
159 ++serviceInstructionsSize));
162 if (instructions != null && !instructions.isEmpty()) {
163 for (Instruction info : instructions) {
164 // Skip meta data write as that is handled already
165 if (info.getInstruction() instanceof WriteMetadataCase) {
168 instructionSet.add(info);
172 String serviceRef = boundServiceNew.getServiceName();
173 String flowRef = getFlowRef(dpId, iface.getName(), boundServiceNew, boundServiceNew.getServicePriority());
174 StypeOpenflow stypeOpenflow = boundServiceNew.getAugmentation(StypeOpenflow.class);
175 Flow ingressFlow = MDSALUtil.buildFlowNew(tableId, flowRef,
176 stypeOpenflow.getFlowPriority(), serviceRef, 0, 0,
177 stypeOpenflow.getFlowCookie(), matches, instructionSet);
178 installFlow(dpId, ingressFlow, t);
181 public static void installFlow(BigInteger dpId, Flow flow, WriteTransaction t) {
182 FlowKey flowKey = new FlowKey(new FlowId(flow.getId()));
183 Node nodeDpn = buildInventoryDpnNode(dpId);
184 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
185 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
186 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class,flowKey).build();
188 t.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
191 public static void removeFlow(String flowRef, BigInteger dpId, WriteTransaction t) {
192 LOG.debug("Removing Ingress Flows");
193 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
194 Node nodeDpn = buildInventoryDpnNode(dpId);
195 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
196 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
197 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
199 t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
202 private static Node buildInventoryDpnNode(BigInteger dpnId) {
203 NodeId nodeId = new NodeId("openflow:" + dpnId);
204 Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
209 public static void installLPortDispatcherFlow(BigInteger dpId, BoundServices boundService, Interface iface,
210 WriteTransaction t, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
211 LOG.debug("Installing LPort Dispatcher Flows {}, {}", dpId, iface);
212 String serviceRef = boundService.getServiceName();
213 List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForDispatcherTable(dpId, iface,
214 interfaceTag, currentServiceIndex);
216 // Get the metadata and mask from the service's write metadata instruction
217 StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
218 List<Instruction> serviceInstructions = stypeOpenFlow.getInstruction();
219 int instructionSize = serviceInstructions.size();
220 BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(serviceInstructions);
221 BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, nextServiceIndex, metadataValues[0]);
222 BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
223 MetaDataUtil.METADATA_MASK_LPORT_TAG, metadataValues[1]);
225 // build the final instruction for LPort Dispatcher table flow entry
226 List<Instruction> instructions = new ArrayList<Instruction>();
227 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++instructionSize));
228 if (serviceInstructions != null && !serviceInstructions.isEmpty()) {
229 for (Instruction info : serviceInstructions) {
230 // Skip meta data write as that is handled already
231 if (info.getInstruction() instanceof WriteMetadataCase) {
234 instructions.add(info);
238 // build the flow and install it
239 String flowRef = getFlowRef(dpId, iface.getName(), boundService, currentServiceIndex);
240 Flow ingressFlow = MDSALUtil.buildFlowNew(NwConstants.LPORT_DISPATCHER_TABLE, flowRef,
241 boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches, instructions);
242 installFlow(dpId, ingressFlow, t);
245 public static void removeIngressFlow(String name, BoundServices serviceOld, BigInteger dpId, WriteTransaction t) {
246 LOG.debug("Removing Ingress Flows");
247 String flowKeyStr = getFlowRef(dpId, name, serviceOld, serviceOld.getServicePriority());
248 FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
249 Node nodeDpn = buildInventoryDpnNode(dpId);
250 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
251 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
252 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
254 t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
257 public static void removeLPortDispatcherFlow(BigInteger dpId, String iface, BoundServices boundServicesOld, WriteTransaction t, short currentServiceIndex) {
258 LOG.debug("Removing LPort Dispatcher Flows {}, {}", dpId, iface);
260 StypeOpenflow stypeOpenFlow = boundServicesOld.getAugmentation(StypeOpenflow.class);
261 // build the flow and install it
262 String flowRef = getFlowRef(dpId, iface, boundServicesOld, currentServiceIndex);
263 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
264 Node nodeDpn = buildInventoryDpnNode(dpId);
265 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
266 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
267 .child(Table.class, new TableKey(NwConstants.LPORT_DISPATCHER_TABLE)).child(Flow.class, flowKey).build();
269 t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
272 private static String getFlowRef(BigInteger dpnId, String iface, BoundServices service, short currentServiceIndex) {
273 return new StringBuffer().append(dpnId).append(NwConstants.VLAN_INTERFACE_INGRESS_TABLE).append(NwConstants.FLOWID_SEPARATOR)
274 .append(iface).append(NwConstants.FLOWID_SEPARATOR).append(currentServiceIndex).toString();
278 * This util method returns an array of ServiceInfo in which index 0 will
279 * have the immediate lower priority service and index 1 will have the
280 * immediate higher priority service among the list of existing serviceInfos
282 * @param serviceInfos
283 * @param currentServiceInfo
286 public static BoundServices[] getHighAndLowPriorityService(
287 List<BoundServices> serviceInfos, BoundServices currentServiceInfo) {
288 BoundServices higher = null; // this will be used to hold the immediate higher service priority with respect to the currentServiceInfo
289 BoundServices lower = null; // this will be used to hold the immediate lower service priority with respect to the currentServiceInfo
290 if (serviceInfos == null || serviceInfos.isEmpty()) {
291 return new BoundServices[]{lower, higher};
293 List <BoundServices> availableServiceInfos = new ArrayList<BoundServices>(serviceInfos);
294 Collections.sort(availableServiceInfos, new Comparator<BoundServices>() {
296 public int compare(BoundServices serviceInfo1, BoundServices serviceInfo2) {
297 return serviceInfo1.getServicePriority().compareTo(serviceInfo2.getServicePriority());
300 for (BoundServices availableServiceInfo: availableServiceInfos) {
301 if (currentServiceInfo.getServicePriority() < availableServiceInfo.getServicePriority()) {
302 lower = availableServiceInfo;
305 higher = availableServiceInfo;
308 return new BoundServices[]{lower,higher};
311 public static BoundServices getHighestPriorityService(List<BoundServices> serviceInfos) {
312 List <BoundServices> availableServiceInfos = new ArrayList<BoundServices>(serviceInfos);
313 if (availableServiceInfos.isEmpty()) {
316 BoundServices highPriorityService = availableServiceInfos.get(0);
317 availableServiceInfos.remove(0);
318 for (BoundServices availableServiceInfo: availableServiceInfos) {
319 if (availableServiceInfo.getServicePriority() < highPriorityService.getServicePriority()) {
320 highPriorityService = availableServiceInfo;
323 return highPriorityService;
326 public static void installVlanFlow(BigInteger dpId, long portNo, Interface iface,
327 WriteTransaction t, List<MatchInfo> matches, int lportTag) {
329 boolean isVlanTransparent = false;
330 IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
332 vlanId = l2vlan.getVlanId() == null ? 0 : l2vlan.getVlanId().getValue();
333 isVlanTransparent = l2vlan.getL2vlanMode() == IfL2vlan.L2vlanMode.Transparent;
335 int instructionKey = 0;
336 BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, (short) 0);
337 BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher();
338 List<Instruction> instructions = new ArrayList<Instruction>();
339 if (vlanId != 0 && !isVlanTransparent) {
340 instructions.add(MDSALUtil.buildAndGetPopVlanActionInstruction(lportTag, instructionKey++));
342 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, instructionKey++));
343 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.DHCP_TABLE, instructionKey++));
344 int priority = isVlanTransparent ? 1 : vlanId == 0 ? IfmConstants.FLOW_PRIORITY_FOR_UNTAGGED_VLAN : IfmConstants.FLOW_HIGH_PRIORITY;
345 String flowRef = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, iface.getName());
346 Flow ingressFlow = MDSALUtil.buildFlowNew(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, flowRef, priority, flowRef, 0, 0,
347 IfmConstants.VLAN_TABLE_COOKIE, matches, instructions);
348 installFlow(dpId, ingressFlow, t);
351 public static String getFlowRef(short tableId, BigInteger dpnId, String infName) {
352 return String.format("%d:%s:%s", tableId, dpnId, infName);
355 public static void removeIngressFlow(String interfaceName, BigInteger dpId, WriteTransaction t) {
356 LOG.debug("Removing Ingress Flows");
357 String flowKeyStr = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, interfaceName);
358 FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
359 Node nodeDpn = buildInventoryDpnNode(dpId);
360 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
361 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
362 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
364 t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);