2 * Copyright (c) 2016 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.genius.interfacemanager.servicebindings.flowbased.utilities;
10 import com.google.common.base.Optional;
11 import com.google.common.collect.ImmutableBiMap;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.Comparator;
16 import java.util.List;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.genius.interfacemanager.IfmConstants;
21 import org.opendaylight.genius.interfacemanager.IfmUtil;
22 import org.opendaylight.genius.interfacemanager.commons.InterfaceManagerCommonUtils;
23 import org.opendaylight.genius.mdsalutil.MDSALUtil;
24 import org.opendaylight.genius.mdsalutil.MatchFieldType;
25 import org.opendaylight.genius.mdsalutil.MatchInfo;
26 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
27 import org.opendaylight.genius.mdsalutil.NwConstants;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteMetadataCase;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
52 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
56 public class FlowBasedServicesUtils {
57 private static final Logger LOG = LoggerFactory.getLogger(FlowBasedServicesUtils.class);
59 public enum ServiceMode {
64 public static final ImmutableBiMap SERVICE_MODE_MAP =
65 new ImmutableBiMap.Builder<ServiceMode, Class<? extends ServiceModeBase>>()
66 .put(ServiceMode.EGRESS, ServiceModeEgress.class)
67 .put(ServiceMode.INGRESS, ServiceModeIngress.class)
70 public static ServicesInfo getServicesInfoForInterface(String interfaceName, Class<? extends ServiceModeBase> serviceMode,
71 DataBroker dataBroker) {
72 ServicesInfoKey servicesInfoKey = new ServicesInfoKey(interfaceName,serviceMode);
73 InstanceIdentifier.InstanceIdentifierBuilder<ServicesInfo> servicesInfoIdentifierBuilder =
74 InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class, servicesInfoKey);
75 Optional<ServicesInfo> servicesInfoOptional = IfmUtil.read(LogicalDatastoreType.CONFIGURATION,
76 servicesInfoIdentifierBuilder.build(), dataBroker);
78 if (servicesInfoOptional.isPresent()) {
79 return servicesInfoOptional.get();
85 public static NodeConnectorId getNodeConnectorIdFromInterface(String interfaceName, DataBroker dataBroker) {
86 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState =
87 InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(interfaceName, dataBroker);
89 List<String> ofportIds = ifState.getLowerLayerIf();
90 return new NodeConnectorId(ofportIds.get(0));
95 public static NodeConnectorId getNodeConnectorIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState) {
97 List<String> ofportIds = ifState.getLowerLayerIf();
98 return new NodeConnectorId(ofportIds.get(0));
103 public static BigInteger getDpnIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState) {
104 NodeConnectorId nodeConnectorId = null;
105 if(ifState != null) {
106 List<String> ofportIds = ifState.getLowerLayerIf();
107 nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
109 return new BigInteger(IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId));
112 public static List<MatchInfo> getMatchInfoForVlanPortAtIngressTable(BigInteger dpId, long portNo, Interface iface) {
113 List<MatchInfo> matches = new ArrayList<>();
114 matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {dpId, BigInteger.valueOf(portNo)}));
116 IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
117 if(l2vlan != null && l2vlan.getL2vlanMode() != IfL2vlan.L2vlanMode.Transparent){
118 vlanId = l2vlan.getVlanId() == null ? 0 : l2vlan.getVlanId().getValue();
121 matches.add(new MatchInfo(MatchFieldType.vlan_vid, new long[]{vlanId}));
126 public static List<MatchInfo> getMatchInfoForTunnelPortAtIngressTable(BigInteger dpId, long portNo) {
127 List<MatchInfo> matches = new ArrayList<>();
128 matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[]{dpId, BigInteger.valueOf(portNo)}));
132 public static List<MatchInfo> getMatchInfoForDispatcherTable(BigInteger dpId,
133 int interfaceTag, short servicePriority) {
134 List<MatchInfo> matches = new ArrayList<>();
135 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
136 MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, servicePriority),
137 MetaDataUtil.getMetaDataMaskForLPortDispatcher() }));
141 public static void installInterfaceIngressFlow(BigInteger dpId, Interface iface,
142 BoundServices boundServiceNew,
144 List<MatchInfo> matches, int lportTag, short tableId) {
145 List<Instruction> instructions = boundServiceNew.getAugmentation(StypeOpenflow.class).getInstruction();
147 int serviceInstructionsSize = instructions.size();
148 List<Instruction> instructionSet = new ArrayList<>();
150 IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
151 if(l2vlan != null && l2vlan.getVlanId() != null){
152 vlanId = l2vlan.getVlanId().getValue();
155 // incrementing instructionSize and using it as actionKey. Because it won't clash with any other instructions
156 int actionKey = ++serviceInstructionsSize;
157 instructionSet.add(MDSALUtil.buildAndGetPopVlanActionInstruction(actionKey, ++serviceInstructionsSize));
160 if (lportTag != 0L) {
161 BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(instructions);
162 short sIndex = boundServiceNew.getServicePriority();
163 BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag,
164 ++sIndex, metadataValues[0]);
165 BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(
166 MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
167 MetaDataUtil.METADATA_MASK_LPORT_TAG, metadataValues[1]);
168 instructionSet.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask,
169 ++serviceInstructionsSize));
172 if (instructions != null && !instructions.isEmpty()) {
173 for (Instruction info : instructions) {
174 // Skip meta data write as that is handled already
175 if (info.getInstruction() instanceof WriteMetadataCase) {
178 instructionSet.add(info);
182 String serviceRef = boundServiceNew.getServiceName();
183 String flowRef = getFlowRef(dpId, iface.getName(), boundServiceNew, boundServiceNew.getServicePriority());
184 StypeOpenflow stypeOpenflow = boundServiceNew.getAugmentation(StypeOpenflow.class);
185 Flow ingressFlow = MDSALUtil.buildFlowNew(tableId, flowRef,
186 stypeOpenflow.getFlowPriority(), serviceRef, 0, 0,
187 stypeOpenflow.getFlowCookie(), matches, instructionSet);
188 installFlow(dpId, ingressFlow, t);
191 public static void installFlow(BigInteger dpId, Flow flow, WriteTransaction t) {
192 FlowKey flowKey = new FlowKey(new FlowId(flow.getId()));
193 Node nodeDpn = buildInventoryDpnNode(dpId);
194 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
195 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
196 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class,flowKey).build();
198 t.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
201 public static void removeFlow(String flowRef, BigInteger dpId, WriteTransaction t) {
202 LOG.debug("Removing Ingress Flows");
203 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
204 Node nodeDpn = buildInventoryDpnNode(dpId);
205 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
206 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
207 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
209 t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
212 private static Node buildInventoryDpnNode(BigInteger dpnId) {
213 NodeId nodeId = new NodeId("openflow:" + dpnId);
214 Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
219 public static void installLPortDispatcherFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
220 WriteTransaction t, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
221 LOG.debug("Installing LPort Dispatcher Flows {}, {}", dpId, interfaceName);
222 String serviceRef = boundService.getServiceName();
223 List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForDispatcherTable(dpId,
224 interfaceTag, currentServiceIndex);
226 // Get the metadata and mask from the service's write metadata instruction
227 StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
228 List<Instruction> serviceInstructions = stypeOpenFlow.getInstruction();
229 int instructionSize = serviceInstructions.size();
230 BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(serviceInstructions);
231 BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, nextServiceIndex, metadataValues[0]);
232 BigInteger metadataMask = MetaDataUtil.getWriteMetaDataMaskForDispatcherTable();
234 // build the final instruction for LPort Dispatcher table flow entry
235 List<Instruction> instructions = new ArrayList<>();
236 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++instructionSize));
237 if (serviceInstructions != null && !serviceInstructions.isEmpty()) {
238 for (Instruction info : serviceInstructions) {
239 // Skip meta data write as that is handled already
240 if (info.getInstruction() instanceof WriteMetadataCase) {
243 instructions.add(info);
247 // build the flow and install it
248 String flowRef = getFlowRef(dpId, interfaceName, boundService, currentServiceIndex);
249 Flow ingressFlow = MDSALUtil.buildFlowNew(NwConstants.LPORT_DISPATCHER_TABLE, flowRef,
250 boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches, instructions);
251 installFlow(dpId, ingressFlow, t);
254 public static void removeIngressFlow(String name, BoundServices serviceOld, BigInteger dpId, WriteTransaction t) {
255 LOG.debug("Removing Ingress Flows");
256 String flowKeyStr = getFlowRef(dpId, name, serviceOld, serviceOld.getServicePriority());
257 FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
258 Node nodeDpn = buildInventoryDpnNode(dpId);
259 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
260 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
261 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
263 t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
266 public static void removeLPortDispatcherFlow(BigInteger dpId, String iface, BoundServices boundServicesOld, WriteTransaction t, short currentServiceIndex) {
267 LOG.debug("Removing LPort Dispatcher Flows {}, {}", dpId, iface);
269 boundServicesOld.getAugmentation(StypeOpenflow.class);
270 // build the flow and install it
271 String flowRef = getFlowRef(dpId, iface, boundServicesOld, currentServiceIndex);
272 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
273 Node nodeDpn = buildInventoryDpnNode(dpId);
274 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
275 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
276 .child(Table.class, new TableKey(NwConstants.LPORT_DISPATCHER_TABLE)).child(Flow.class, flowKey).build();
278 t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
281 private static String getFlowRef(BigInteger dpnId, String iface, BoundServices service, short currentServiceIndex) {
282 return new StringBuffer().append(dpnId).append(NwConstants.VLAN_INTERFACE_INGRESS_TABLE).append(NwConstants.FLOWID_SEPARATOR)
283 .append(iface).append(NwConstants.FLOWID_SEPARATOR).append(currentServiceIndex).toString();
287 * This util method returns an array of ServiceInfo in which index 0 will
288 * have the immediate lower priority service and index 1 will have the
289 * immediate higher priority service among the list of existing serviceInfos
291 * @param serviceInfos
292 * @param currentServiceInfo
295 public static BoundServices[] getHighAndLowPriorityService(
296 List<BoundServices> serviceInfos, BoundServices currentServiceInfo) {
297 BoundServices higher = null; // this will be used to hold the immediate higher service priority with respect to the currentServiceInfo
298 BoundServices lower = null; // this will be used to hold the immediate lower service priority with respect to the currentServiceInfo
299 if (serviceInfos == null || serviceInfos.isEmpty()) {
300 return new BoundServices[]{lower, higher};
302 List <BoundServices> availableServiceInfos = new ArrayList<>(serviceInfos);
303 Collections.sort(availableServiceInfos, new Comparator<BoundServices>() {
305 public int compare(BoundServices serviceInfo1, BoundServices serviceInfo2) {
306 return serviceInfo1.getServicePriority().compareTo(serviceInfo2.getServicePriority());
309 for (BoundServices availableServiceInfo: availableServiceInfos) {
310 if (currentServiceInfo.getServicePriority() < availableServiceInfo.getServicePriority()) {
311 lower = availableServiceInfo;
314 higher = availableServiceInfo;
317 return new BoundServices[]{lower,higher};
320 public static BoundServices getHighestPriorityService(List<BoundServices> serviceInfos) {
321 List <BoundServices> availableServiceInfos = new ArrayList<>(serviceInfos);
322 if (availableServiceInfos.isEmpty()) {
325 BoundServices highPriorityService = availableServiceInfos.get(0);
326 availableServiceInfos.remove(0);
327 for (BoundServices availableServiceInfo: availableServiceInfos) {
328 if (availableServiceInfo.getServicePriority() < highPriorityService.getServicePriority()) {
329 highPriorityService = availableServiceInfo;
332 return highPriorityService;
335 public static void installVlanFlow(BigInteger dpId, long portNo, Interface iface,
336 WriteTransaction t, List<MatchInfo> matches, int lportTag) {
338 boolean isVlanTransparent = false;
339 IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
341 vlanId = l2vlan.getVlanId() == null ? 0 : l2vlan.getVlanId().getValue();
342 isVlanTransparent = l2vlan.getL2vlanMode() == IfL2vlan.L2vlanMode.Transparent;
344 int instructionKey = 0;
345 BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, (short) 0);
346 BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher();
347 List<Instruction> instructions = new ArrayList<>();
348 if (vlanId != 0 && !isVlanTransparent) {
349 instructions.add(MDSALUtil.buildAndGetPopVlanActionInstruction(lportTag, instructionKey++));
351 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, instructionKey++));
352 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.LPORT_DISPATCHER_TABLE, instructionKey++));
353 int priority = isVlanTransparent ? 1 : vlanId == 0 ? IfmConstants.FLOW_PRIORITY_FOR_UNTAGGED_VLAN : IfmConstants.FLOW_HIGH_PRIORITY;
354 String flowRef = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, iface.getName());
355 Flow ingressFlow = MDSALUtil.buildFlowNew(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, flowRef, priority, flowRef, 0, 0,
356 IfmConstants.VLAN_TABLE_COOKIE, matches, instructions);
357 installFlow(dpId, ingressFlow, t);
360 public static String getFlowRef(short tableId, BigInteger dpnId, String infName) {
361 return String.format("%d:%s:%s", tableId, dpnId, infName);
364 public static void removeIngressFlow(String interfaceName, BigInteger dpId, WriteTransaction t) {
368 LOG.debug("Removing Ingress Flows for {}", interfaceName);
369 String flowKeyStr = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, interfaceName);
370 FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
371 Node nodeDpn = buildInventoryDpnNode(dpId);
372 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
373 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
374 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
376 t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);