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.MatchFieldType;
26 import org.opendaylight.genius.mdsalutil.MatchInfo;
27 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
28 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
29 import org.opendaylight.genius.mdsalutil.NwConstants;
30 import org.opendaylight.genius.mdsalutil.NxMatchFieldType;
31 import org.opendaylight.genius.mdsalutil.NxMatchInfo;
32 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
33 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
34 import org.opendaylight.genius.utils.ServiceIndex;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteActionsCase;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteMetadataCase;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfExternal;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.SplitHorizon;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
68 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
72 public class FlowBasedServicesUtils {
73 private static final Logger LOG = LoggerFactory.getLogger(FlowBasedServicesUtils.class);
75 public enum ServiceMode {
80 public static final ImmutableBiMap SERVICE_MODE_MAP =
81 new ImmutableBiMap.Builder<ServiceMode, Class<? extends ServiceModeBase>>()
82 .put(ServiceMode.EGRESS, ServiceModeEgress.class)
83 .put(ServiceMode.INGRESS, ServiceModeIngress.class)
86 public static ServicesInfo getServicesInfoForInterface(String interfaceName, Class<? extends ServiceModeBase> serviceMode,
87 DataBroker dataBroker) {
88 ServicesInfoKey servicesInfoKey = new ServicesInfoKey(interfaceName,serviceMode);
89 InstanceIdentifier.InstanceIdentifierBuilder<ServicesInfo> servicesInfoIdentifierBuilder =
90 InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class, servicesInfoKey);
91 return IfmUtil.read(LogicalDatastoreType.CONFIGURATION, servicesInfoIdentifierBuilder.build(),
95 public static NodeConnectorId getNodeConnectorIdFromInterface(String interfaceName, DataBroker dataBroker) {
96 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState =
97 InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(interfaceName, dataBroker);
99 List<String> ofportIds = ifState.getLowerLayerIf();
100 return new NodeConnectorId(ofportIds.get(0));
105 public static NodeConnectorId getNodeConnectorIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState) {
106 if(ifState != null) {
107 List<String> ofportIds = ifState.getLowerLayerIf();
108 return new NodeConnectorId(ofportIds.get(0));
113 public static BigInteger getDpnIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState) {
114 NodeConnectorId nodeConnectorId = null;
115 if(ifState != null) {
116 List<String> ofportIds = ifState.getLowerLayerIf();
117 nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
119 return IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId);
122 public static List<MatchInfo> getMatchInfoForVlanPortAtIngressTable(BigInteger dpId, long portNo, Interface iface) {
123 List<MatchInfo> matches = new ArrayList<>();
124 matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {dpId, BigInteger.valueOf(portNo)}));
126 IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
127 if(l2vlan != null && l2vlan.getL2vlanMode() != IfL2vlan.L2vlanMode.Transparent){
128 vlanId = l2vlan.getVlanId() == null ? 0 : l2vlan.getVlanId().getValue();
131 matches.add(new MatchInfo(MatchFieldType.vlan_vid, new long[]{vlanId}));
136 public static List<MatchInfo> getMatchInfoForTunnelPortAtIngressTable(BigInteger dpId, long portNo) {
137 List<MatchInfo> matches = new ArrayList<>();
138 matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[]{dpId, BigInteger.valueOf(portNo)}));
142 public static List<MatchInfo> getMatchInfoForDispatcherTable(BigInteger dpId,
143 int interfaceTag, short servicePriority) {
144 List<MatchInfo> matches = new ArrayList<>();
145 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
146 MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, servicePriority),
147 MetaDataUtil.getMetaDataMaskForLPortDispatcher() }));
151 public static List<MatchInfoBase> getMatchInfoForEgressDispatcherTable(int interfaceTag, short serviceIndex) {
152 List<MatchInfoBase> matches = new ArrayList<>();
153 matches.add(new NxMatchInfo(NxMatchFieldType.nxm_reg_6, new long[] {
154 MetaDataUtil.getReg6ValueForLPortDispatcher(interfaceTag, serviceIndex)}));
158 public static void installInterfaceIngressFlow(BigInteger dpId, Interface iface,
159 BoundServices boundServiceNew,
161 List<MatchInfo> matches, int lportTag, short tableId) {
162 List<Instruction> instructions = boundServiceNew.getAugmentation(StypeOpenflow.class).getInstruction();
164 int serviceInstructionsSize = instructions.size();
165 List<Instruction> instructionSet = new ArrayList<>();
167 IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
168 if(l2vlan != null && l2vlan.getVlanId() != null){
169 vlanId = l2vlan.getVlanId().getValue();
172 // incrementing instructionSize and using it as actionKey. Because it won't clash with any other instructions
173 int actionKey = ++serviceInstructionsSize;
174 instructionSet.add(MDSALUtil.buildAndGetPopVlanActionInstruction(actionKey, ++serviceInstructionsSize));
177 if (lportTag != 0L) {
178 BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(instructions);
179 short sIndex = boundServiceNew.getServicePriority();
180 BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag,
181 ++sIndex, metadataValues[0], isExternal(iface));
182 BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(
183 MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
184 MetaDataUtil.METADATA_MASK_LPORT_TAG_SH_FLAG, metadataValues[1]);
185 instructionSet.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask,
186 ++serviceInstructionsSize));
189 if (instructions != null && !instructions.isEmpty()) {
190 for (Instruction info : instructions) {
191 // Skip meta data write as that is handled already
192 if (info.getInstruction() instanceof WriteMetadataCase) {
194 } else if (info.getInstruction() instanceof WriteActionsCase) {
195 info = MDSALUtil.buildWriteActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
196 ((WriteActionsCase)info.getInstruction()).getWriteActions().getAction()));
197 } else if (info.getInstruction() instanceof ApplyActionsCase) {
198 info = MDSALUtil.buildApplyActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
199 ((ApplyActionsCase)info.getInstruction()).getApplyActions().getAction()));
201 instructionSet.add(info);
205 String serviceRef = boundServiceNew.getServiceName();
206 String flowRef = getFlowRef(dpId, NwConstants.VLAN_INTERFACE_INGRESS_TABLE, iface.getName(),
207 boundServiceNew, boundServiceNew.getServicePriority());
208 StypeOpenflow stypeOpenflow = boundServiceNew.getAugmentation(StypeOpenflow.class);
209 Flow ingressFlow = MDSALUtil.buildFlowNew(tableId, flowRef,
210 stypeOpenflow.getFlowPriority(), serviceRef, 0, 0,
211 stypeOpenflow.getFlowCookie(), matches, instructionSet);
212 installFlow(dpId, ingressFlow, t);
215 public static void installFlow(BigInteger dpId, Flow flow, WriteTransaction t) {
216 FlowKey flowKey = new FlowKey(new FlowId(flow.getId()));
217 Node nodeDpn = buildInventoryDpnNode(dpId);
218 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
219 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
220 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class,flowKey).build();
222 t.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
225 public static void removeFlow(String flowRef, BigInteger dpId, WriteTransaction t) {
226 LOG.debug("Removing Ingress Flows");
227 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
228 Node nodeDpn = buildInventoryDpnNode(dpId);
229 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
230 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
231 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
233 t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
236 private static Node buildInventoryDpnNode(BigInteger dpnId) {
237 NodeId nodeId = new NodeId("openflow:" + dpnId);
238 Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
243 public static void installLPortDispatcherFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
244 WriteTransaction t, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
245 LOG.debug("Installing LPort Dispatcher Flow {}, {}", dpId, interfaceName);
246 String serviceRef = boundService.getServiceName();
247 List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForDispatcherTable(dpId, interfaceTag, currentServiceIndex);
249 // Get the metadata and mask from the service's write metadata instruction
250 StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
251 List<Instruction> serviceInstructions = stypeOpenFlow.getInstruction();
252 int instructionSize = serviceInstructions.size();
253 BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(serviceInstructions);
254 BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, nextServiceIndex, metadataValues[0]);
255 BigInteger metadataMask = MetaDataUtil.getWriteMetaDataMaskForDispatcherTable();
257 // build the final instruction for LPort Dispatcher table flow entry
258 List<Instruction> instructions = new ArrayList<>();
259 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++instructionSize));
260 if (serviceInstructions != null && !serviceInstructions.isEmpty()) {
261 for (Instruction info : serviceInstructions) {
262 // Skip meta data write as that is handled already
263 if (info.getInstruction() instanceof WriteMetadataCase) {
265 } else if (info.getInstruction() instanceof WriteActionsCase) {
266 info = MDSALUtil.buildWriteActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
267 ((WriteActionsCase)info.getInstruction()).getWriteActions().getAction()));
268 } else if (info.getInstruction() instanceof ApplyActionsCase) {
269 info = MDSALUtil.buildApplyActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
270 ((ApplyActionsCase)info.getInstruction()).getApplyActions().getAction()));
272 instructions.add(info);
276 // build the flow and install it
277 String flowRef = getFlowRef(dpId, NwConstants.LPORT_DISPATCHER_TABLE, interfaceName, boundService, currentServiceIndex);
278 Flow ingressFlow = MDSALUtil.buildFlowNew(NwConstants.LPORT_DISPATCHER_TABLE, flowRef,
279 boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches, instructions);
280 installFlow(dpId, ingressFlow, t);
283 public static void installEgressDispatcherFlows(BigInteger dpId, BoundServices boundService, String interfaceName,
284 WriteTransaction t, int interfaceTag, short currentServiceIndex,
285 short nextServiceIndex, Interface iface) {
286 LOG.debug("Installing Egress Dispatcher Flows {}, {}", dpId, interfaceName);
287 installEgressDispatcherFlow(dpId, boundService, interfaceName, t, interfaceTag, currentServiceIndex, nextServiceIndex);
289 // Install Split Horizon drop flow only for the default egress service - this flow drops traffic targeted to external interfaces if they arrived
290 // from an external interface (marked with the SH bit)
291 if (boundService.getServicePriority() == ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME, NwConstants.DEFAULT_EGRESS_SERVICE_INDEX)) {
292 installEgressDispatcherSplitHorizonFlow(dpId, boundService, interfaceName, t, interfaceTag, currentServiceIndex, iface);
296 private static void installEgressDispatcherFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
297 WriteTransaction t, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
298 String serviceRef = boundService.getServiceName();
299 List<? extends MatchInfoBase> matches = FlowBasedServicesUtils.getMatchInfoForEgressDispatcherTable(interfaceTag, currentServiceIndex);
301 // Get the metadata and mask from the service's write metadata instruction
302 StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
303 List<Instruction> serviceInstructions = stypeOpenFlow.getInstruction();
304 int instructionSize = serviceInstructions.size();
306 // build the final instruction for LPort Dispatcher table flow entry
307 List<Instruction> instructions = new ArrayList<>();
308 if(boundService.getServicePriority() != ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME, NwConstants.DEFAULT_EGRESS_SERVICE_INDEX)) {
309 BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(serviceInstructions);
310 BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, nextServiceIndex, metadataValues[0]);
311 BigInteger metadataMask = MetaDataUtil.getWriteMetaDataMaskForDispatcherTable();
312 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++instructionSize));
313 instructions.add(MDSALUtil.buildAndGetSetReg6ActionInstruction(0, ++instructionSize, 0, 31,
314 MetaDataUtil.getReg6ValueForLPortDispatcher(interfaceTag, nextServiceIndex)));
316 if (serviceInstructions != null && !serviceInstructions.isEmpty()) {
317 for (Instruction info : serviceInstructions) {
318 // Skip meta data write as that is handled already
319 if (info.getInstruction() instanceof WriteMetadataCase) {
321 } else if (info.getInstruction() instanceof WriteActionsCase) {
322 info = MDSALUtil.buildWriteActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
323 ((WriteActionsCase)info.getInstruction()).getWriteActions().getAction()));
324 } else if (info.getInstruction() instanceof ApplyActionsCase) {
325 info = MDSALUtil.buildApplyActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
326 ((ApplyActionsCase)info.getInstruction()).getApplyActions().getAction()));
328 instructions.add(info);
332 // build the flow and install it
333 String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, interfaceName, boundService, currentServiceIndex);
334 Flow egressFlow = MDSALUtil.buildFlowNew(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, flowRef,
335 boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches, instructions);
336 installFlow(dpId, egressFlow, t);
339 public static void installEgressDispatcherSplitHorizonFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
340 WriteTransaction t, int interfaceTag, short currentServiceIndex, Interface iface) {
341 // only install split horizon drop flows for external interfaces
342 if (!isExternal(iface)) {
346 if (LOG.isDebugEnabled()) {
347 LOG.debug("Installing split horizon drop flow for external interface {} on dpId {}", interfaceName, dpId);
350 BigInteger shFlagSet = BigInteger.ONE; // BigInteger.ONE is used for checking the Split-Horizon flag
351 StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
352 List<MatchInfoBase> shMatches = FlowBasedServicesUtils.getMatchInfoForEgressDispatcherTable(interfaceTag, currentServiceIndex);
353 shMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] { shFlagSet, MetaDataUtil.METADATA_MASK_SH_FLAG }));
354 List<InstructionInfo> shInstructions = new ArrayList<>();
355 List<ActionInfo> actionsInfos = new ArrayList<>();
356 actionsInfos.add(new ActionDrop());
357 shInstructions.add(new InstructionApplyActions(actionsInfos));
359 String flowRef = getSplitHorizonFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, interfaceName, currentServiceIndex, shFlagSet);
360 String serviceRef = boundService.getServiceName();
361 int splitHorizonFlowPriority = boundService.getServicePriority() + 1; // this must be higher priority than the egress flow
362 Flow egressSplitHorizonFlow = MDSALUtil.buildFlow(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, flowRef,
363 splitHorizonFlowPriority, serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), shMatches, shInstructions);
365 installFlow(dpId, egressSplitHorizonFlow, t);
368 public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
369 BigInteger cookie, List<Instruction> instructions) {
370 StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority).setInstruction(instructions);
371 return new BoundServicesBuilder().setKey(new BoundServicesKey(servicePriority))
372 .setServiceName(serviceName).setServicePriority(servicePriority)
373 .setServiceType(ServiceTypeFlowBased.class).addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
376 public static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short serviceIndex) {
377 return InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class,
378 new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
379 .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
382 public static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short serviceIndex, Class<? extends ServiceModeBase> serviceMode) {
383 return InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class,
384 new ServicesInfoKey(interfaceName, serviceMode))
385 .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
388 public static void unbindDefaultEgressDispatcherService(DataBroker dataBroker, String interfaceName) {
389 IfmUtil.unbindService(dataBroker, interfaceName, buildServiceId(interfaceName,
390 ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME, NwConstants.DEFAULT_EGRESS_SERVICE_INDEX),
391 ServiceModeEgress.class));
394 public static void bindDefaultEgressDispatcherService(DataBroker dataBroker, List<ListenableFuture<Void>> futures,
395 Interface interfaceInfo, String portNo,
396 String interfaceName, int ifIndex) {
397 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
398 int priority = ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME, NwConstants.DEFAULT_EGRESS_SERVICE_INDEX);
399 List<Instruction> instructions = IfmUtil.getEgressInstructionsForInterface(interfaceInfo, portNo, null, true, ifIndex);
402 getBoundServices(String.format("%s.%s", "default", interfaceName),
403 ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME, NwConstants.DEFAULT_EGRESS_SERVICE_INDEX), priority,
404 NwConstants.EGRESS_DISPATCHER_TABLE_COOKIE, instructions);
405 IfmUtil.bindService(tx, interfaceName, serviceInfo, ServiceModeEgress.class);
406 futures.add(tx.submit());
409 public static void removeIngressFlow(String name, BoundServices serviceOld, BigInteger dpId, WriteTransaction t) {
410 LOG.debug("Removing Ingress Flows");
411 String flowKeyStr = getFlowRef(dpId, NwConstants.VLAN_INTERFACE_INGRESS_TABLE, name, serviceOld, serviceOld.getServicePriority());
412 FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
413 Node nodeDpn = buildInventoryDpnNode(dpId);
414 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
415 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
416 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
418 t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
421 public static void removeLPortDispatcherFlow(BigInteger dpId, String iface, BoundServices boundServicesOld, WriteTransaction t, short currentServiceIndex) {
422 LOG.debug("Removing LPort Dispatcher Flows {}, {}", dpId, iface);
424 boundServicesOld.getAugmentation(StypeOpenflow.class);
425 // build the flow and install it
426 String flowRef = getFlowRef(dpId, NwConstants.LPORT_DISPATCHER_TABLE, iface, boundServicesOld, currentServiceIndex);
427 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
428 Node nodeDpn = buildInventoryDpnNode(dpId);
429 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
430 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
431 .child(Table.class, new TableKey(NwConstants.LPORT_DISPATCHER_TABLE)).child(Flow.class, flowKey).build();
433 t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
436 public static void removeEgressDispatcherFlows(BigInteger dpId, String iface, BoundServices boundServicesOld, WriteTransaction t, short currentServiceIndex) {
437 LOG.debug("Removing Egress Dispatcher Flows {}, {}", dpId, iface);
438 removeEgressDispatcherFlow(dpId, iface, t, currentServiceIndex, boundServicesOld);
439 removeEgressSplitHorizonDispatcherFlow(dpId, iface, t, currentServiceIndex);
442 private static void removeEgressDispatcherFlow(BigInteger dpId, String iface, WriteTransaction t,
443 short currentServiceIndex, BoundServices boundServicesOld) {
444 // build the flow and install it
445 String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, iface, boundServicesOld, currentServiceIndex);
446 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
447 Node nodeDpn = buildInventoryDpnNode(dpId);
448 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
449 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
450 .child(Table.class, new TableKey(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE)).child(Flow.class, flowKey).build();
452 t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
455 public static void removeEgressSplitHorizonDispatcherFlow(BigInteger dpId, String iface, WriteTransaction t, short currentServiceIndex) {
456 BigInteger shFlagSet = BigInteger.ONE; // BigInteger.ONE is used for checking the Split-Horizon flag
457 String shFlowRef = getSplitHorizonFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, iface, currentServiceIndex, shFlagSet);
458 FlowKey shFlowKey = new FlowKey(new FlowId(shFlowRef));
459 Node nodeDpn = buildInventoryDpnNode(dpId);
460 InstanceIdentifier<Flow> shFlowInstanceId = InstanceIdentifier.builder(Nodes.class)
461 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
462 .child(Table.class, new TableKey(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE)).child(Flow.class, shFlowKey).build();
464 t.delete(LogicalDatastoreType.CONFIGURATION, shFlowInstanceId);
467 private static String getFlowRef(BigInteger dpnId, short tableId, String iface, BoundServices service, short currentServiceIndex) {
468 return String.valueOf(dpnId) + tableId + NwConstants.FLOWID_SEPARATOR +
469 iface + NwConstants.FLOWID_SEPARATOR + currentServiceIndex;
472 private static String getSplitHorizonFlowRef(BigInteger dpnId, short tableId, String iface, short currentServiceIndex, BigInteger shFlag) {
473 return new StringBuffer().append(dpnId).append(tableId).append(NwConstants.FLOWID_SEPARATOR)
474 .append(iface).append(NwConstants.FLOWID_SEPARATOR).append(shFlag.toString()).toString();
477 * This util method returns an array of ServiceInfo in which index 0 will
478 * have the immediate lower priority service and index 1 will have the
479 * immediate higher priority service among the list of existing serviceInfos
481 * @param serviceInfos
482 * @param currentServiceInfo
485 public static BoundServices[] getHighAndLowPriorityService(
486 List<BoundServices> serviceInfos, BoundServices currentServiceInfo) {
487 BoundServices higher = null; // this will be used to hold the immediate higher service priority with respect to the currentServiceInfo
488 BoundServices lower = null; // this will be used to hold the immediate lower service priority with respect to the currentServiceInfo
489 if (serviceInfos == null || serviceInfos.isEmpty()) {
490 return new BoundServices[]{lower, higher};
492 List <BoundServices> availableServiceInfos = new ArrayList<>(serviceInfos);
493 Collections.sort(availableServiceInfos,
494 (serviceInfo1, serviceInfo2) -> serviceInfo1.getServicePriority().compareTo(serviceInfo2.getServicePriority()));
495 for (BoundServices availableServiceInfo: availableServiceInfos) {
496 if (currentServiceInfo.getServicePriority() < availableServiceInfo.getServicePriority()) {
497 lower = availableServiceInfo;
500 higher = availableServiceInfo;
503 return new BoundServices[]{lower,higher};
506 public static BoundServices getHighestPriorityService(List<BoundServices> serviceInfos) {
507 List <BoundServices> availableServiceInfos = new ArrayList<>(serviceInfos);
508 if (availableServiceInfos.isEmpty()) {
511 BoundServices highPriorityService = availableServiceInfos.get(0);
512 availableServiceInfos.remove(0);
513 for (BoundServices availableServiceInfo: availableServiceInfos) {
514 if (availableServiceInfo.getServicePriority() < highPriorityService.getServicePriority()) {
515 highPriorityService = availableServiceInfo;
518 return highPriorityService;
521 public static void installLportIngressFlow(BigInteger dpId, long portNo, Interface iface,
522 List<ListenableFuture<Void>> futures, DataBroker dataBroker,
525 boolean isVlanTransparent = false;
526 WriteTransaction inventoryConfigShardTransaction = dataBroker.newWriteOnlyTransaction();
527 List<MatchInfo> matches = getMatchInfoForVlanPortAtIngressTable(dpId, portNo, iface);
528 IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
530 vlanId = l2vlan.getVlanId() == null ? 0 : l2vlan.getVlanId().getValue();
531 isVlanTransparent = l2vlan.getL2vlanMode() == IfL2vlan.L2vlanMode.Transparent;
533 int instructionKey = 0;
534 BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, (short) 0, BigInteger.ZERO, isExternal(iface));
535 BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_LPORT_TAG_SH_FLAG);
536 List<Instruction> instructions = new ArrayList<>();
538 final SplitHorizon splitHorizon = iface.getAugmentation(SplitHorizon.class);
539 boolean overrideSplitHorizonProtection = splitHorizon != null && splitHorizon.isOverrideSplitHorizonProtection();
541 List<Action> actions = new ArrayList<>();
542 if (vlanId != 0 && !isVlanTransparent) {
543 actions.add(MDSALUtil.createPopVlanAction(actionKey++));
545 if (overrideSplitHorizonProtection) {
546 actions.add(MDSALUtil.createNxOfInPortAction(actionKey++,0));
548 if (actions.size() != 0) {
549 instructions.add(MDSALUtil.buildApplyActionsInstruction(actions,instructionKey++));
552 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, instructionKey++));
553 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.LPORT_DISPATCHER_TABLE, instructionKey++));
554 int priority = isVlanTransparent ? 1 : vlanId == 0 ? IfmConstants.FLOW_PRIORITY_FOR_UNTAGGED_VLAN : IfmConstants.FLOW_HIGH_PRIORITY;
555 String flowRef = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, iface.getName());
556 Flow ingressFlow = MDSALUtil.buildFlowNew(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, flowRef, priority, flowRef, 0, 0,
557 NwConstants.VLAN_TABLE_COOKIE, matches, instructions);
558 installFlow(dpId, ingressFlow, inventoryConfigShardTransaction);
559 futures.add(inventoryConfigShardTransaction.submit());
562 public static String getFlowRef(short tableId, BigInteger dpnId, String infName) {
563 return String.format("%d:%s:%s", tableId, dpnId, infName);
566 public static void removeIngressFlow(String interfaceName, BigInteger dpId, DataBroker dataBroker,
567 List<ListenableFuture<Void>> futures) {
571 LOG.debug("Removing Ingress Flows for {}", interfaceName);
572 WriteTransaction t = dataBroker.newWriteOnlyTransaction();
573 String flowKeyStr = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, interfaceName);
574 FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
575 Node nodeDpn = buildInventoryDpnNode(dpId);
576 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
577 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
578 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
580 t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
581 futures.add(t.submit());
584 private static boolean isExternal(Interface iface) {
588 IfExternal ifExternal = iface.getAugmentation(IfExternal.class);
589 return ifExternal != null && Boolean.TRUE.equals(ifExternal.isExternal());