Fix issues related to checkstyle enforcement for module
[genius.git] / interfacemanager / interfacemanager-impl / src / main / java / org / opendaylight / genius / interfacemanager / servicebindings / flowbased / utilities / FlowBasedServicesUtils.java
1 /*
2  * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.genius.interfacemanager.servicebindings.flowbased.utilities;
9
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;
73
74 public class FlowBasedServicesUtils {
75     private static final Logger LOG = LoggerFactory.getLogger(FlowBasedServicesUtils.class);
76
77     public enum ServiceMode {
78         INGRESS, EGRESS
79     }
80
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)
84             .build();
85
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)
92                 .orNull();
93     }
94
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));
102         }
103         return null;
104     }
105
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));
112         }
113         return null;
114     }
115
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));
123         }
124         return IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId);
125     }
126
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));
130         int vlanId = 0;
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();
134         }
135         if (vlanId > 0) {
136             matches.add(new MatchVlanVid(vlanId));
137         }
138         return matches;
139     }
140
141     public static List<MatchInfo> getMatchInfoForTunnelPortAtIngressTable(BigInteger dpId, long portNo) {
142         List<MatchInfo> matches = new ArrayList<>();
143         matches.add(new MatchInPort(dpId, portNo));
144         return matches;
145     }
146
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()));
152         return matches;
153     }
154
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)));
159         return matches;
160     }
161
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();
165
166         int serviceInstructionsSize = instructions.size();
167         List<Instruction> instructionSet = new ArrayList<>();
168         int vlanId = 0;
169         IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
170         if (l2vlan != null && l2vlan.getVlanId() != null) {
171             vlanId = l2vlan.getVlanId().getValue();
172         }
173         if (vlanId != 0) {
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));
178         }
179
180         if (lportTag != 0L) {
181             BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(instructions);
182             short index = boundServiceNew.getServicePriority();
183             BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, ++index, metadataValues[0],
184                     isExternal(iface));
185             BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(
186                     MetaDataUtil.METADATA_MASK_SERVICE_INDEX, MetaDataUtil.METADATA_MASK_LPORT_TAG_SH_FLAG,
187                     metadataValues[1]);
188             instructionSet.add(
189                     MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++serviceInstructionsSize));
190         }
191
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) {
196                     continue;
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()));
203                 }
204                 instructionSet.add(info);
205             }
206         }
207
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);
215     }
216
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();
223
224         writeTransaction.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
225     }
226
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)
234                 .build();
235
236         writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
237     }
238
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();
242
243         return nodeDpn;
244     }
245
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);
252
253         // Get the metadata and mask from the service's write metadata
254         // instruction
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,
260                 metadataValues[0]);
261         BigInteger metadataMask = MetaDataUtil.getWriteMetaDataMaskForDispatcherTable();
262
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) {
270                     continue;
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()));
277                 }
278                 instructions.add(info);
279             }
280         }
281
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,
287                 instructions);
288         installFlow(dpId, ingressFlow, writeTransaction);
289     }
290
291     public static void installEgressDispatcherFlows(BigInteger dpId, BoundServices boundService, String interfaceName,
292             WriteTransaction writeTransaction, int interfaceTag, short currentServiceIndex, short nextServiceIndex,
293             Interface iface) {
294         LOG.debug("Installing Egress Dispatcher Flows {}, {}", dpId, interfaceName);
295         installEgressDispatcherFlow(dpId, boundService, interfaceName, writeTransaction, interfaceTag,
296                 currentServiceIndex, nextServiceIndex);
297
298         // Install Split Horizon drop flow only for the default egress service -
299         // this flow drops traffic targeted to external interfaces if they
300         // arrived
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);
306         }
307     }
308
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);
314
315         // Get the metadata and mask from the service's write metadata
316         // instruction
317         StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
318         List<Instruction> serviceInstructions = stypeOpenFlow.getInstruction();
319         int instructionSize = serviceInstructions.size();
320
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,
327                     metadataValues[0]);
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)));
332         }
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) {
337                     continue;
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()));
344                 }
345                 instructions.add(info);
346             }
347         }
348
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,
354                 instructions);
355         LOG.debug("Installing Egress Dispatcher Flow {}, {}", flowRef, interfaceName);
356         installFlow(dpId, egressFlow, writeTransaction);
357     }
358
359     public static void installEgressDispatcherSplitHorizonFlow(BigInteger dpId, BoundServices boundService,
360             String interfaceName, WriteTransaction writeTransaction, int interfaceTag, short currentServiceIndex,
361             Interface iface) {
362         // only install split horizon drop flows for external interfaces
363         if (!isExternal(iface)) {
364             return;
365         }
366
367         if (LOG.isDebugEnabled()) {
368             LOG.debug("Installing split horizon drop flow for external interface {} on dpId {}", interfaceName, dpId);
369         }
370
371         BigInteger shFlagSet = BigInteger.ONE; // BigInteger.ONE is used for
372                                                 // checking the Split-Horizon
373                                                 // flag
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));
381
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);
390
391         installFlow(dpId, egressSplitHorizonFlow, writeTransaction);
392     }
393
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();
401     }
402
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();
407     }
408
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();
414     }
415
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));
420     }
421
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,
428                 ifIndex);
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());
435     }
436
437     public static void removeIngressFlow(String interfaceName, BigInteger dpId, DataBroker dataBroker,
438             List<ListenableFuture<Void>> futures) {
439         if (dpId == null) {
440             return;
441         }
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)
450                 .build();
451
452         writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
453         futures.add(writeTransaction.submit());
454     }
455
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)
466                 .build();
467
468         writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
469     }
470
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);
474
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)
484                 .build();
485
486         writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
487     }
488
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);
494     }
495
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)
506                 .build();
507
508         writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
509     }
510
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();
523
524         writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, shFlowInstanceId);
525     }
526
527     public static String getFlowRef(short tableId, BigInteger dpnId, String infName) {
528         return String.format("%d:%s:%s", tableId, dpnId, infName);
529     }
530
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;
535     }
536
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();
541     }
542
543     /**
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
547      * serviceInfos.
548      *
549      * @param serviceInfos
550      *            list of services bound
551      * @param currentServiceInfo
552      *            current service bound
553      * @return array bound services
554      */
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 };
563         }
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;
570                 break;
571             } else {
572                 higher = availableServiceInfo;
573             }
574         }
575         return new BoundServices[] { lower, higher };
576     }
577
578     public static BoundServices getHighestPriorityService(List<BoundServices> serviceInfos) {
579         List<BoundServices> availableServiceInfos = new ArrayList<>(serviceInfos);
580         if (availableServiceInfos.isEmpty()) {
581             return null;
582         }
583         BoundServices highPriorityService = availableServiceInfos.get(0);
584         availableServiceInfos.remove(0);
585         for (BoundServices availableServiceInfo : availableServiceInfos) {
586             if (availableServiceInfo.getServicePriority() < highPriorityService.getServicePriority()) {
587                 highPriorityService = availableServiceInfo;
588             }
589         }
590         return highPriorityService;
591     }
592
593     public static void installLportIngressFlow(BigInteger dpId, long portNo, Interface iface,
594             List<ListenableFuture<Void>> futures, DataBroker dataBroker, int lportTag) {
595         int vlanId = 0;
596         boolean isVlanTransparent = false;
597
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;
602         }
603         int instructionKey = 0;
604
605         List<Instruction> instructions = new ArrayList<>();
606
607         final SplitHorizon splitHorizon = iface.getAugmentation(SplitHorizon.class);
608         boolean overrideSplitHorizonProtection = splitHorizon != null
609                 && splitHorizon.isOverrideSplitHorizonProtection();
610         int actionKey = 0;
611         List<Action> actions = new ArrayList<>();
612         if (vlanId != 0 && !isVlanTransparent) {
613             actions.add(MDSALUtil.createPopVlanAction(actionKey++));
614         }
615         if (overrideSplitHorizonProtection) {
616             actions.add(MDSALUtil.createNxOfInPortAction(actionKey++, 0));
617         }
618         if (!actions.isEmpty()) {
619             instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, instructionKey++));
620         }
621         BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, (short) 0, BigInteger.ZERO,
622                 isExternal(iface));
623         BigInteger metadataMask = MetaDataUtil
624                 .getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_LPORT_TAG_SH_FLAG);
625         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, instructionKey++));
626         instructions
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());
638     }
639
640     private static boolean isExternal(Interface iface) {
641         if (iface == null) {
642             return false;
643         }
644         IfExternal ifExternal = iface.getAugmentation(IfExternal.class);
645         return ifExternal != null && Boolean.TRUE.equals(ifExternal.isExternal());
646     }
647 }