2 * Copyright © 2016, 2017 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.collect.ImmutableBiMap;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 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.genius.interfacemanager.IfmConstants;
20 import org.opendaylight.genius.interfacemanager.IfmUtil;
21 import org.opendaylight.genius.interfacemanager.commons.InterfaceManagerCommonUtils;
22 import org.opendaylight.genius.mdsalutil.ActionInfo;
23 import org.opendaylight.genius.mdsalutil.InstructionInfo;
24 import org.opendaylight.genius.mdsalutil.MDSALUtil;
25 import org.opendaylight.genius.mdsalutil.MatchInfo;
26 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
27 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
28 import org.opendaylight.genius.mdsalutil.NwConstants;
29 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
30 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
31 import org.opendaylight.genius.mdsalutil.matches.MatchInPort;
32 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
33 import org.opendaylight.genius.mdsalutil.matches.MatchVlanVid;
34 import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchRegister;
35 import org.opendaylight.genius.utils.ServiceIndex;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteActionsCase;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteMetadataCase;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfExternal;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.SplitHorizon;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
70 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
74 public class FlowBasedServicesUtils {
75 private static final Logger LOG = LoggerFactory.getLogger(FlowBasedServicesUtils.class);
77 public enum ServiceMode {
81 public static final ImmutableBiMap<ServiceMode, Class<? extends ServiceModeBase>>
82 SERVICE_MODE_MAP = new ImmutableBiMap.Builder<ServiceMode, Class<? extends ServiceModeBase>>()
83 .put(ServiceMode.EGRESS, ServiceModeEgress.class).put(ServiceMode.INGRESS, ServiceModeIngress.class)
86 public static ServicesInfo getServicesInfoForInterface(String interfaceName,
87 Class<? extends ServiceModeBase> serviceMode, DataBroker dataBroker) {
88 ServicesInfoKey servicesInfoKey = new ServicesInfoKey(interfaceName, serviceMode);
89 InstanceIdentifier.InstanceIdentifierBuilder<ServicesInfo> servicesInfoIdentifierBuilder = InstanceIdentifier
90 .builder(ServiceBindings.class).child(ServicesInfo.class, servicesInfoKey);
91 return IfmUtil.read(LogicalDatastoreType.CONFIGURATION, servicesInfoIdentifierBuilder.build(), dataBroker)
95 public static NodeConnectorId getNodeConnectorIdFromInterface(String interfaceName, DataBroker dataBroker) {
96 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
97 .ietf.interfaces.rev140508.interfaces.state.Interface ifState = InterfaceManagerCommonUtils
98 .getInterfaceStateFromOperDS(interfaceName, dataBroker);
99 if (ifState != null) {
100 List<String> ofportIds = ifState.getLowerLayerIf();
101 return new NodeConnectorId(ofportIds.get(0));
106 public static NodeConnectorId getNodeConnectorIdFromInterface(
107 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
108 .ietf.interfaces.rev140508.interfaces.state.Interface ifState) {
109 if (ifState != null) {
110 List<String> ofportIds = ifState.getLowerLayerIf();
111 return new NodeConnectorId(ofportIds.get(0));
116 public static BigInteger getDpnIdFromInterface(
117 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
118 .ietf.interfaces.rev140508.interfaces.state.Interface ifState) {
119 NodeConnectorId nodeConnectorId = null;
120 if (ifState != null) {
121 List<String> ofportIds = ifState.getLowerLayerIf();
122 nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
124 return IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId);
127 public static List<MatchInfo> getMatchInfoForVlanPortAtIngressTable(BigInteger dpId, long portNo, Interface iface) {
128 List<MatchInfo> matches = new ArrayList<>();
129 matches.add(new MatchInPort(dpId, portNo));
131 IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
132 if (l2vlan != null && l2vlan.getL2vlanMode() != IfL2vlan.L2vlanMode.Transparent) {
133 vlanId = l2vlan.getVlanId() == null ? 0 : l2vlan.getVlanId().getValue();
136 matches.add(new MatchVlanVid(vlanId));
141 public static List<MatchInfo> getMatchInfoForTunnelPortAtIngressTable(BigInteger dpId, long portNo) {
142 List<MatchInfo> matches = new ArrayList<>();
143 matches.add(new MatchInPort(dpId, portNo));
147 public static List<MatchInfo> getMatchInfoForDispatcherTable(BigInteger dpId, int interfaceTag,
148 short servicePriority) {
149 List<MatchInfo> matches = new ArrayList<>();
150 matches.add(new MatchMetadata(MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, servicePriority),
151 MetaDataUtil.getMetaDataMaskForLPortDispatcher()));
155 public static List<MatchInfoBase> getMatchInfoForEgressDispatcherTable(int interfaceTag, short serviceIndex) {
156 List<MatchInfoBase> matches = new ArrayList<>();
157 matches.add(new NxMatchRegister(NxmNxReg6.class,
158 MetaDataUtil.getReg6ValueForLPortDispatcher(interfaceTag, serviceIndex)));
162 public static void installInterfaceIngressFlow(BigInteger dpId, Interface iface, BoundServices boundServiceNew,
163 WriteTransaction writeTransaction, List<MatchInfo> matches, int lportTag, short tableId) {
164 List<Instruction> instructions = boundServiceNew.getAugmentation(StypeOpenflow.class).getInstruction();
166 int serviceInstructionsSize = instructions.size();
167 List<Instruction> instructionSet = new ArrayList<>();
169 IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
170 if (l2vlan != null && l2vlan.getVlanId() != null) {
171 vlanId = l2vlan.getVlanId().getValue();
174 // incrementing instructionSize and using it as actionKey. Because
175 // it won't clash with any other instructions
176 int actionKey = ++serviceInstructionsSize;
177 instructionSet.add(MDSALUtil.buildAndGetPopVlanActionInstruction(actionKey, ++serviceInstructionsSize));
180 if (lportTag != 0L) {
181 BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(instructions);
182 short index = boundServiceNew.getServicePriority();
183 BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, ++index, metadataValues[0],
185 BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(
186 MetaDataUtil.METADATA_MASK_SERVICE_INDEX, MetaDataUtil.METADATA_MASK_LPORT_TAG_SH_FLAG,
189 MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++serviceInstructionsSize));
192 if (instructions != null && !instructions.isEmpty()) {
193 for (Instruction info : instructions) {
194 // Skip meta data write as that is handled already
195 if (info.getInstruction() instanceof WriteMetadataCase) {
197 } else if (info.getInstruction() instanceof WriteActionsCase) {
198 info = MDSALUtil.buildWriteActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
199 ((WriteActionsCase) info.getInstruction()).getWriteActions().getAction()));
200 } else if (info.getInstruction() instanceof ApplyActionsCase) {
201 info = MDSALUtil.buildApplyActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
202 ((ApplyActionsCase) info.getInstruction()).getApplyActions().getAction()));
204 instructionSet.add(info);
208 String serviceRef = boundServiceNew.getServiceName();
209 String flowRef = getFlowRef(dpId, NwConstants.VLAN_INTERFACE_INGRESS_TABLE, iface.getName(), boundServiceNew,
210 boundServiceNew.getServicePriority());
211 StypeOpenflow stypeOpenflow = boundServiceNew.getAugmentation(StypeOpenflow.class);
212 Flow ingressFlow = MDSALUtil.buildFlowNew(tableId, flowRef, stypeOpenflow.getFlowPriority(), serviceRef, 0, 0,
213 stypeOpenflow.getFlowCookie(), matches, instructionSet);
214 installFlow(dpId, ingressFlow, writeTransaction);
217 public static void installFlow(BigInteger dpId, Flow flow, WriteTransaction writeTransaction) {
218 FlowKey flowKey = new FlowKey(new FlowId(flow.getId()));
219 Node nodeDpn = buildInventoryDpnNode(dpId);
220 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
221 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
222 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
224 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
227 public static void removeFlow(String flowRef, BigInteger dpId, WriteTransaction writeTransaction) {
228 LOG.debug("Removing Ingress Flows");
229 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
230 Node nodeDpn = buildInventoryDpnNode(dpId);
231 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
232 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
233 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey)
236 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
239 private static Node buildInventoryDpnNode(BigInteger dpnId) {
240 NodeId nodeId = new NodeId("openflow:" + dpnId);
241 Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
246 public static void installLPortDispatcherFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
247 WriteTransaction writeTransaction, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
248 LOG.debug("Installing LPort Dispatcher Flow {}, {}", dpId, interfaceName);
249 String serviceRef = boundService.getServiceName();
250 List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForDispatcherTable(dpId, interfaceTag,
251 currentServiceIndex);
253 // Get the metadata and mask from the service's write metadata
255 StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
256 List<Instruction> serviceInstructions = stypeOpenFlow.getInstruction();
257 int instructionSize = serviceInstructions.size();
258 BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(serviceInstructions);
259 BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, nextServiceIndex,
261 BigInteger metadataMask = MetaDataUtil.getWriteMetaDataMaskForDispatcherTable();
263 // build the final instruction for LPort Dispatcher table flow entry
264 List<Instruction> instructions = new ArrayList<>();
265 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++instructionSize));
266 if (serviceInstructions != null && !serviceInstructions.isEmpty()) {
267 for (Instruction info : serviceInstructions) {
268 // Skip meta data write as that is handled already
269 if (info.getInstruction() instanceof WriteMetadataCase) {
271 } else if (info.getInstruction() instanceof WriteActionsCase) {
272 info = MDSALUtil.buildWriteActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
273 ((WriteActionsCase) info.getInstruction()).getWriteActions().getAction()));
274 } else if (info.getInstruction() instanceof ApplyActionsCase) {
275 info = MDSALUtil.buildApplyActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
276 ((ApplyActionsCase) info.getInstruction()).getApplyActions().getAction()));
278 instructions.add(info);
282 // build the flow and install it
283 String flowRef = getFlowRef(dpId, NwConstants.LPORT_DISPATCHER_TABLE, interfaceName, boundService,
284 currentServiceIndex);
285 Flow ingressFlow = MDSALUtil.buildFlowNew(NwConstants.LPORT_DISPATCHER_TABLE, flowRef,
286 boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches,
288 installFlow(dpId, ingressFlow, writeTransaction);
291 public static void installEgressDispatcherFlows(BigInteger dpId, BoundServices boundService, String interfaceName,
292 WriteTransaction writeTransaction, int interfaceTag, short currentServiceIndex, short nextServiceIndex,
294 LOG.debug("Installing Egress Dispatcher Flows {}, {}", dpId, interfaceName);
295 installEgressDispatcherFlow(dpId, boundService, interfaceName, writeTransaction, interfaceTag,
296 currentServiceIndex, nextServiceIndex);
298 // Install Split Horizon drop flow only for the default egress service -
299 // this flow drops traffic targeted to external interfaces if they
301 // from an external interface (marked with the SH bit)
302 if (boundService.getServicePriority() == ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
303 NwConstants.DEFAULT_EGRESS_SERVICE_INDEX)) {
304 installEgressDispatcherSplitHorizonFlow(dpId, boundService, interfaceName, writeTransaction, interfaceTag,
305 currentServiceIndex, iface);
309 private static void installEgressDispatcherFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
310 WriteTransaction writeTransaction, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
311 String serviceRef = boundService.getServiceName();
312 List<? extends MatchInfoBase> matches = FlowBasedServicesUtils
313 .getMatchInfoForEgressDispatcherTable(interfaceTag, currentServiceIndex);
315 // Get the metadata and mask from the service's write metadata
317 StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
318 List<Instruction> serviceInstructions = stypeOpenFlow.getInstruction();
319 int instructionSize = serviceInstructions.size();
321 // build the final instruction for LPort Dispatcher table flow entry
322 List<Instruction> instructions = new ArrayList<>();
323 if (boundService.getServicePriority() != ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
324 NwConstants.DEFAULT_EGRESS_SERVICE_INDEX)) {
325 BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(serviceInstructions);
326 BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, nextServiceIndex,
328 BigInteger metadataMask = MetaDataUtil.getWriteMetaDataMaskForDispatcherTable();
329 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++instructionSize));
330 instructions.add(MDSALUtil.buildAndGetSetReg6ActionInstruction(0, ++instructionSize, 0, 31,
331 MetaDataUtil.getReg6ValueForLPortDispatcher(interfaceTag, nextServiceIndex)));
333 if (serviceInstructions != null && !serviceInstructions.isEmpty()) {
334 for (Instruction info : serviceInstructions) {
335 // Skip meta data write as that is handled already
336 if (info.getInstruction() instanceof WriteMetadataCase) {
338 } else if (info.getInstruction() instanceof WriteActionsCase) {
339 info = MDSALUtil.buildWriteActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
340 ((WriteActionsCase) info.getInstruction()).getWriteActions().getAction()));
341 } else if (info.getInstruction() instanceof ApplyActionsCase) {
342 info = MDSALUtil.buildApplyActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
343 ((ApplyActionsCase) info.getInstruction()).getApplyActions().getAction()));
345 instructions.add(info);
349 // build the flow and install it
350 String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, interfaceName, boundService,
351 currentServiceIndex);
352 Flow egressFlow = MDSALUtil.buildFlowNew(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, flowRef,
353 boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches,
355 LOG.debug("Installing Egress Dispatcher Flow {}, {}", flowRef, interfaceName);
356 installFlow(dpId, egressFlow, writeTransaction);
359 public static void installEgressDispatcherSplitHorizonFlow(BigInteger dpId, BoundServices boundService,
360 String interfaceName, WriteTransaction writeTransaction, int interfaceTag, short currentServiceIndex,
362 // only install split horizon drop flows for external interfaces
363 if (!isExternal(iface)) {
367 if (LOG.isDebugEnabled()) {
368 LOG.debug("Installing split horizon drop flow for external interface {} on dpId {}", interfaceName, dpId);
371 BigInteger shFlagSet = BigInteger.ONE; // BigInteger.ONE is used for
372 // checking the Split-Horizon
374 List<MatchInfoBase> shMatches = FlowBasedServicesUtils.getMatchInfoForEgressDispatcherTable(interfaceTag,
375 currentServiceIndex);
376 shMatches.add(new MatchMetadata(shFlagSet, MetaDataUtil.METADATA_MASK_SH_FLAG));
377 List<InstructionInfo> shInstructions = new ArrayList<>();
378 List<ActionInfo> actionsInfos = new ArrayList<>();
379 actionsInfos.add(new ActionDrop());
380 shInstructions.add(new InstructionApplyActions(actionsInfos));
382 String flowRef = getSplitHorizonFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, interfaceName,
383 currentServiceIndex, shFlagSet);
384 String serviceRef = boundService.getServiceName();
385 // This must be higher priority than the egress flow
386 int splitHorizonFlowPriority = boundService.getServicePriority() + 1;
387 StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
388 Flow egressSplitHorizonFlow = MDSALUtil.buildFlow(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, flowRef,
389 splitHorizonFlowPriority, serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), shMatches, shInstructions);
391 installFlow(dpId, egressSplitHorizonFlow, writeTransaction);
394 public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
395 BigInteger cookie, List<Instruction> instructions) {
396 StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority)
397 .setInstruction(instructions);
398 return new BoundServicesBuilder().setKey(new BoundServicesKey(servicePriority)).setServiceName(serviceName)
399 .setServicePriority(servicePriority).setServiceType(ServiceTypeFlowBased.class)
400 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
403 public static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short serviceIndex) {
404 return InstanceIdentifier.builder(ServiceBindings.class)
405 .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
406 .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
409 public static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short serviceIndex,
410 Class<? extends ServiceModeBase> serviceMode) {
411 return InstanceIdentifier.builder(ServiceBindings.class)
412 .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, serviceMode))
413 .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
416 public static void unbindDefaultEgressDispatcherService(DataBroker dataBroker, String interfaceName) {
417 IfmUtil.unbindService(dataBroker, interfaceName,
418 buildServiceId(interfaceName, ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
419 NwConstants.DEFAULT_EGRESS_SERVICE_INDEX), ServiceModeEgress.class));
422 public static void bindDefaultEgressDispatcherService(DataBroker dataBroker, List<ListenableFuture<Void>> futures,
423 Interface interfaceInfo, String portNo, String interfaceName, int ifIndex) {
424 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
425 int priority = ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
426 NwConstants.DEFAULT_EGRESS_SERVICE_INDEX);
427 List<Instruction> instructions = IfmUtil.getEgressInstructionsForInterface(interfaceInfo, portNo, null, true,
429 BoundServices serviceInfo = getBoundServices(String.format("%s.%s", "default", interfaceName),
430 ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
431 NwConstants.DEFAULT_EGRESS_SERVICE_INDEX),
432 priority, NwConstants.EGRESS_DISPATCHER_TABLE_COOKIE, instructions);
433 IfmUtil.bindService(tx, interfaceName, serviceInfo, ServiceModeEgress.class);
434 futures.add(tx.submit());
437 public static void removeIngressFlow(String interfaceName, BigInteger dpId, DataBroker dataBroker,
438 List<ListenableFuture<Void>> futures) {
442 LOG.debug("Removing Ingress Flows for {}", interfaceName);
443 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
444 String flowKeyStr = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, interfaceName);
445 FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
446 Node nodeDpn = buildInventoryDpnNode(dpId);
447 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
448 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
449 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey)
452 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
453 futures.add(writeTransaction.submit());
456 public static void removeIngressFlow(String name, BoundServices serviceOld, BigInteger dpId,
457 WriteTransaction writeTransaction) {
458 String flowKeyStr = getFlowRef(dpId, NwConstants.VLAN_INTERFACE_INGRESS_TABLE, name, serviceOld,
459 serviceOld.getServicePriority());
460 LOG.debug("Removing Ingress Flow {}", flowKeyStr);
461 FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
462 Node nodeDpn = buildInventoryDpnNode(dpId);
463 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
464 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
465 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey)
468 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
471 public static void removeLPortDispatcherFlow(BigInteger dpId, String iface, BoundServices boundServicesOld,
472 WriteTransaction writeTransaction, short currentServiceIndex) {
473 LOG.debug("Removing LPort Dispatcher Flows {}, {}", dpId, iface);
475 boundServicesOld.getAugmentation(StypeOpenflow.class);
476 // build the flow and install it
477 String flowRef = getFlowRef(dpId, NwConstants.LPORT_DISPATCHER_TABLE, iface, boundServicesOld,
478 currentServiceIndex);
479 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
480 Node nodeDpn = buildInventoryDpnNode(dpId);
481 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
482 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
483 .child(Table.class, new TableKey(NwConstants.LPORT_DISPATCHER_TABLE)).child(Flow.class, flowKey)
486 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
489 public static void removeEgressDispatcherFlows(BigInteger dpId, String iface, BoundServices boundServicesOld,
490 WriteTransaction writeTransaction, short currentServiceIndex) {
491 LOG.debug("Removing Egress Dispatcher Flows {}, {}", dpId, iface);
492 removeEgressDispatcherFlow(dpId, iface, writeTransaction, currentServiceIndex, boundServicesOld);
493 removeEgressSplitHorizonDispatcherFlow(dpId, iface, writeTransaction, currentServiceIndex);
496 private static void removeEgressDispatcherFlow(BigInteger dpId, String iface, WriteTransaction writeTransaction,
497 short currentServiceIndex, BoundServices boundServicesOld) {
498 // build the flow and install it
499 String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, iface, boundServicesOld,
500 currentServiceIndex);
501 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
502 Node nodeDpn = buildInventoryDpnNode(dpId);
503 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
504 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
505 .child(Table.class, new TableKey(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE)).child(Flow.class, flowKey)
508 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
511 public static void removeEgressSplitHorizonDispatcherFlow(BigInteger dpId, String iface,
512 WriteTransaction writeTransaction, short currentServiceIndex) {
513 // BigInteger.ONE is used for checking the Split-Horizon flag
514 BigInteger shFlagSet = BigInteger.ONE;
515 String shFlowRef = getSplitHorizonFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, iface,
516 currentServiceIndex, shFlagSet);
517 FlowKey shFlowKey = new FlowKey(new FlowId(shFlowRef));
518 Node nodeDpn = buildInventoryDpnNode(dpId);
519 InstanceIdentifier<Flow> shFlowInstanceId = InstanceIdentifier.builder(Nodes.class)
520 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
521 .child(Table.class, new TableKey(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE))
522 .child(Flow.class, shFlowKey).build();
524 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, shFlowInstanceId);
527 public static String getFlowRef(short tableId, BigInteger dpnId, String infName) {
528 return String.format("%d:%s:%s", tableId, dpnId, infName);
531 private static String getFlowRef(BigInteger dpnId, short tableId, String iface, BoundServices service,
532 short currentServiceIndex) {
533 return String.valueOf(dpnId) + tableId + NwConstants.FLOWID_SEPARATOR + iface + NwConstants.FLOWID_SEPARATOR
534 + currentServiceIndex;
537 private static String getSplitHorizonFlowRef(BigInteger dpnId, short tableId, String iface,
538 short currentServiceIndex, BigInteger shFlag) {
539 return new StringBuffer().append(dpnId).append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(iface)
540 .append(NwConstants.FLOWID_SEPARATOR).append(shFlag.toString()).toString();
544 * This utility method returns an array of ServiceInfo in which index 0 will
545 * have the immediate lower priority service and index 1 will have the
546 * immediate higher priority service among the list of existing
549 * @param serviceInfos
550 * list of services bound
551 * @param currentServiceInfo
552 * current service bound
553 * @return array bound services
555 public static BoundServices[] getHighAndLowPriorityService(List<BoundServices> serviceInfos,
556 BoundServices currentServiceInfo) {
557 // This will be used to hold the immediate higher service priority with respect to the currentServiceInfo
558 BoundServices higher = null;
559 // This will be used to hold the immediate lower service priority with respect to the currentServiceInfo
560 BoundServices lower = null;
561 if (serviceInfos == null || serviceInfos.isEmpty()) {
562 return new BoundServices[] { lower, higher };
564 List<BoundServices> availableServiceInfos = new ArrayList<>(serviceInfos);
565 Collections.sort(availableServiceInfos, (serviceInfo1, serviceInfo2) -> serviceInfo1.getServicePriority()
566 .compareTo(serviceInfo2.getServicePriority()));
567 for (BoundServices availableServiceInfo : availableServiceInfos) {
568 if (currentServiceInfo.getServicePriority() < availableServiceInfo.getServicePriority()) {
569 lower = availableServiceInfo;
572 higher = availableServiceInfo;
575 return new BoundServices[] { lower, higher };
578 public static BoundServices getHighestPriorityService(List<BoundServices> serviceInfos) {
579 List<BoundServices> availableServiceInfos = new ArrayList<>(serviceInfos);
580 if (availableServiceInfos.isEmpty()) {
583 BoundServices highPriorityService = availableServiceInfos.get(0);
584 availableServiceInfos.remove(0);
585 for (BoundServices availableServiceInfo : availableServiceInfos) {
586 if (availableServiceInfo.getServicePriority() < highPriorityService.getServicePriority()) {
587 highPriorityService = availableServiceInfo;
590 return highPriorityService;
593 public static void installLportIngressFlow(BigInteger dpId, long portNo, Interface iface,
594 List<ListenableFuture<Void>> futures, DataBroker dataBroker, int lportTag) {
596 boolean isVlanTransparent = false;
598 IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
599 if (l2vlan != null) {
600 vlanId = l2vlan.getVlanId() == null ? 0 : l2vlan.getVlanId().getValue();
601 isVlanTransparent = l2vlan.getL2vlanMode() == IfL2vlan.L2vlanMode.Transparent;
603 int instructionKey = 0;
605 List<Instruction> instructions = new ArrayList<>();
607 final SplitHorizon splitHorizon = iface.getAugmentation(SplitHorizon.class);
608 boolean overrideSplitHorizonProtection = splitHorizon != null
609 && splitHorizon.isOverrideSplitHorizonProtection();
611 List<Action> actions = new ArrayList<>();
612 if (vlanId != 0 && !isVlanTransparent) {
613 actions.add(MDSALUtil.createPopVlanAction(actionKey++));
615 if (overrideSplitHorizonProtection) {
616 actions.add(MDSALUtil.createNxOfInPortAction(actionKey++, 0));
618 if (!actions.isEmpty()) {
619 instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, instructionKey++));
621 BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, (short) 0, BigInteger.ZERO,
623 BigInteger metadataMask = MetaDataUtil
624 .getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_LPORT_TAG_SH_FLAG);
625 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, instructionKey++));
627 .add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.LPORT_DISPATCHER_TABLE, instructionKey++));
628 int priority = isVlanTransparent ? 1
629 : vlanId == 0 ? IfmConstants.FLOW_PRIORITY_FOR_UNTAGGED_VLAN : IfmConstants.FLOW_HIGH_PRIORITY;
630 String flowRef = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, iface.getName());
631 List<MatchInfo> matches = getMatchInfoForVlanPortAtIngressTable(dpId, portNo, iface);
632 Flow ingressFlow = MDSALUtil.buildFlowNew(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, flowRef, priority, flowRef,
633 0, 0, NwConstants.VLAN_TABLE_COOKIE, matches, instructions);
634 LOG.debug("Installing ingress flow {} for {}", flowRef, iface.getName());
635 WriteTransaction inventoryConfigShardTransaction = dataBroker.newWriteOnlyTransaction();
636 installFlow(dpId, ingressFlow, inventoryConfigShardTransaction);
637 futures.add(inventoryConfigShardTransaction.submit());
640 private static boolean isExternal(Interface iface) {
644 IfExternal ifExternal = iface.getAugmentation(IfExternal.class);
645 return ifExternal != null && Boolean.TRUE.equals(ifExternal.isExternal());