Merge "VM Migration: Handle VM migration only for OFPT_PORT_STATUS/OFPPR_ADD"
[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.apache.commons.lang3.StringUtils;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.genius.interfacemanager.IfmConstants;
21 import org.opendaylight.genius.interfacemanager.IfmUtil;
22 import org.opendaylight.genius.interfacemanager.commons.InterfaceManagerCommonUtils;
23 import org.opendaylight.genius.mdsalutil.ActionInfo;
24 import org.opendaylight.genius.mdsalutil.InstructionInfo;
25 import org.opendaylight.genius.mdsalutil.MDSALUtil;
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.actions.ActionDrop;
31 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
32 import org.opendaylight.genius.mdsalutil.matches.MatchInPort;
33 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
34 import org.opendaylight.genius.mdsalutil.matches.MatchVlanVid;
35 import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchRegister;
36 import org.opendaylight.genius.utils.ServiceIndex;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteActionsCase;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteMetadataCase;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfExternal;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.SplitHorizon;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.BoundServicesStateList;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.bound.services.state.list.BoundServicesState;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.bound.services.state.list.BoundServicesStateBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.bound.services.state.list.BoundServicesStateKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
75 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
76 import org.slf4j.Logger;
77 import org.slf4j.LoggerFactory;
78
79 public class FlowBasedServicesUtils {
80     private static final Logger LOG = LoggerFactory.getLogger(FlowBasedServicesUtils.class);
81     private static final int DEFAULT_DISPATCHER_PRIORITY = 10;
82
83     public enum ServiceMode {
84         INGRESS, EGRESS
85     }
86
87     public static final ImmutableBiMap<ServiceMode, Class<? extends ServiceModeBase>>
88         SERVICE_MODE_MAP = new ImmutableBiMap.Builder<ServiceMode, Class<? extends ServiceModeBase>>()
89             .put(ServiceMode.EGRESS, ServiceModeEgress.class).put(ServiceMode.INGRESS, ServiceModeIngress.class)
90             .build();
91
92     public static ServicesInfo getServicesInfoForInterface(String interfaceName,
93             Class<? extends ServiceModeBase> serviceMode, DataBroker dataBroker) {
94         ServicesInfoKey servicesInfoKey = new ServicesInfoKey(interfaceName, serviceMode);
95         InstanceIdentifier.InstanceIdentifierBuilder<ServicesInfo> servicesInfoIdentifierBuilder = InstanceIdentifier
96                 .builder(ServiceBindings.class).child(ServicesInfo.class, servicesInfoKey);
97         return IfmUtil.read(LogicalDatastoreType.CONFIGURATION, servicesInfoIdentifierBuilder.build(), dataBroker)
98                 .orNull();
99     }
100
101     public static NodeConnectorId getNodeConnectorIdFromInterface(String interfaceName, DataBroker dataBroker) {
102         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
103             .ietf.interfaces.rev140508.interfaces.state.Interface ifState = InterfaceManagerCommonUtils
104                 .getInterfaceState(interfaceName, dataBroker);
105         if (ifState != null) {
106             List<String> ofportIds = ifState.getLowerLayerIf();
107             return new NodeConnectorId(ofportIds.get(0));
108         }
109         return null;
110     }
111
112     public static NodeConnectorId getNodeConnectorIdFromInterface(
113             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
114                 .ietf.interfaces.rev140508.interfaces.state.Interface ifState) {
115         if (ifState != null) {
116             List<String> ofportIds = ifState.getLowerLayerIf();
117             return new NodeConnectorId(ofportIds.get(0));
118         }
119         return null;
120     }
121
122     public static BigInteger getDpnIdFromInterface(
123             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
124                 .ietf.interfaces.rev140508.interfaces.state.Interface ifState) {
125         NodeConnectorId nodeConnectorId = null;
126         if (ifState != null) {
127             List<String> ofportIds = ifState.getLowerLayerIf();
128             nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
129         }
130         return IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId);
131     }
132
133     public static List<MatchInfo> getMatchInfoForVlanPortAtIngressTable(BigInteger dpId, long portNo, Interface iface) {
134         List<MatchInfo> matches = new ArrayList<>();
135         matches.add(new MatchInPort(dpId, portNo));
136         int vlanId = 0;
137         IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
138         if (l2vlan != null) {
139             vlanId = l2vlan.getVlanId() == null ? 0 : l2vlan.getVlanId().getValue();
140         }
141         if (vlanId >= 0  && l2vlan.getL2vlanMode() != IfL2vlan.L2vlanMode.Transparent) {
142             matches.add(new MatchVlanVid(vlanId));
143         }
144         return matches;
145     }
146
147     public static List<MatchInfo> getMatchInfoForTunnelPortAtIngressTable(BigInteger dpId, long portNo) {
148         List<MatchInfo> matches = new ArrayList<>();
149         matches.add(new MatchInPort(dpId, portNo));
150         return matches;
151     }
152
153     public static List<MatchInfo> getMatchInfoForDispatcherTable(BigInteger dpId, int interfaceTag,
154             short servicePriority) {
155         List<MatchInfo> matches = new ArrayList<>();
156         matches.add(new MatchMetadata(MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, servicePriority),
157                 MetaDataUtil.getMetaDataMaskForLPortDispatcher()));
158         return matches;
159     }
160
161     public static List<MatchInfoBase> getMatchInfoForEgressDispatcherTable(int interfaceTag, short serviceIndex) {
162         List<MatchInfoBase> matches = new ArrayList<>();
163         matches.add(new NxMatchRegister(NxmNxReg6.class,
164                 MetaDataUtil.getReg6ValueForLPortDispatcher(interfaceTag, serviceIndex)));
165         return matches;
166     }
167
168     public static void installInterfaceIngressFlow(BigInteger dpId, Interface iface, BoundServices boundServiceNew,
169             WriteTransaction writeTransaction, List<MatchInfo> matches, int lportTag, short tableId) {
170         List<Instruction> instructions = boundServiceNew.getAugmentation(StypeOpenflow.class).getInstruction();
171
172         int serviceInstructionsSize = instructions.size();
173         List<Instruction> instructionSet = new ArrayList<>();
174         int vlanId = 0;
175         IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
176         if (l2vlan != null && l2vlan.getVlanId() != null) {
177             vlanId = l2vlan.getVlanId().getValue();
178         }
179         if (vlanId != 0) {
180             // incrementing instructionSize and using it as actionKey. Because
181             // it won't clash with any other instructions
182             int actionKey = ++serviceInstructionsSize;
183             instructionSet.add(MDSALUtil.buildAndGetPopVlanActionInstruction(actionKey, ++serviceInstructionsSize));
184         }
185
186         if (lportTag != 0L) {
187             BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(instructions);
188             short index = boundServiceNew.getServicePriority();
189             BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, ++index, metadataValues[0],
190                     isExternal(iface));
191             BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(
192                     MetaDataUtil.METADATA_MASK_SERVICE_INDEX, MetaDataUtil.METADATA_MASK_LPORT_TAG_SH_FLAG,
193                     metadataValues[1]);
194             instructionSet.add(
195                     MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++serviceInstructionsSize));
196         }
197
198         if (instructions != null && !instructions.isEmpty()) {
199             for (Instruction info : instructions) {
200                 // Skip meta data write as that is handled already
201                 if (info.getInstruction() instanceof WriteMetadataCase) {
202                     continue;
203                 } else if (info.getInstruction() instanceof WriteActionsCase) {
204                     info = MDSALUtil.buildWriteActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
205                             ((WriteActionsCase) info.getInstruction()).getWriteActions().getAction()));
206                 } else if (info.getInstruction() instanceof ApplyActionsCase) {
207                     info = MDSALUtil.buildApplyActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
208                             ((ApplyActionsCase) info.getInstruction()).getApplyActions().getAction()));
209                 }
210                 instructionSet.add(info);
211             }
212         }
213
214         String serviceRef = boundServiceNew.getServiceName();
215         String flowRef = getFlowRef(dpId, NwConstants.VLAN_INTERFACE_INGRESS_TABLE, iface.getName(),
216                 boundServiceNew, boundServiceNew.getServicePriority());
217         StypeOpenflow stypeOpenflow = boundServiceNew.getAugmentation(StypeOpenflow.class);
218         Flow ingressFlow = MDSALUtil.buildFlowNew(tableId, flowRef, stypeOpenflow.getFlowPriority(), serviceRef, 0, 0,
219                 stypeOpenflow.getFlowCookie(), matches, instructionSet);
220         installFlow(dpId, ingressFlow, writeTransaction);
221     }
222
223     public static void installFlow(BigInteger dpId, Flow flow, WriteTransaction writeTransaction) {
224         FlowKey flowKey = new FlowKey(new FlowId(flow.getId()));
225         Node nodeDpn = buildInventoryDpnNode(dpId);
226         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
227                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
228                 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
229
230         writeTransaction.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
231     }
232
233     private static Node buildInventoryDpnNode(BigInteger dpnId) {
234         NodeId nodeId = new NodeId("openflow:" + dpnId);
235         Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
236
237         return nodeDpn;
238     }
239
240     public static void installLPortDispatcherFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
241             WriteTransaction writeTransaction, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
242         String serviceRef = boundService.getServiceName();
243         List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForDispatcherTable(dpId, interfaceTag,
244                 currentServiceIndex);
245
246         // Get the metadata and mask from the service's write metadata
247         // instruction
248         StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
249         List<Instruction> serviceInstructions = stypeOpenFlow.getInstruction();
250         int instructionSize = serviceInstructions.size();
251         BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(serviceInstructions);
252         BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, nextServiceIndex,
253                 metadataValues[0]);
254         BigInteger metadataMask = MetaDataUtil.getWriteMetaDataMaskForDispatcherTable();
255
256         // build the final instruction for LPort Dispatcher table flow entry
257         List<Instruction> instructions = new ArrayList<>();
258         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++instructionSize));
259         if (serviceInstructions != null && !serviceInstructions.isEmpty()) {
260             for (Instruction info : serviceInstructions) {
261                 // Skip meta data write as that is handled already
262                 if (info.getInstruction() instanceof WriteMetadataCase) {
263                     continue;
264                 } else if (info.getInstruction() instanceof WriteActionsCase) {
265                     info = MDSALUtil.buildWriteActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
266                             ((WriteActionsCase) info.getInstruction()).getWriteActions().getAction()));
267                 } else if (info.getInstruction() instanceof ApplyActionsCase) {
268                     info = MDSALUtil.buildApplyActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
269                             ((ApplyActionsCase) info.getInstruction()).getApplyActions().getAction()));
270                 }
271                 instructions.add(info);
272             }
273         }
274
275         // build the flow and install it
276         String flowRef = getFlowRef(dpId, NwConstants.LPORT_DISPATCHER_TABLE, interfaceName,
277             boundService, currentServiceIndex);
278         Flow ingressFlow = MDSALUtil.buildFlowNew(NwConstants.LPORT_DISPATCHER_TABLE, flowRef,
279                 DEFAULT_DISPATCHER_PRIORITY, serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches,
280                 instructions);
281         LOG.debug("Installing LPort Dispatcher Flow on DPN {}, for interface {}, with flowRef {}", dpId,
282             interfaceName, flowRef);
283         installFlow(dpId, ingressFlow, writeTransaction);
284     }
285
286     public static void installEgressDispatcherFlows(BigInteger dpId, BoundServices boundService, String interfaceName,
287             WriteTransaction writeTransaction, int interfaceTag, short currentServiceIndex, short nextServiceIndex,
288             Interface iface) {
289         LOG.debug("Installing Egress Dispatcher Flows on dpn : {}, for interface : {}", dpId, interfaceName);
290         installEgressDispatcherFlow(dpId, boundService, interfaceName, writeTransaction, interfaceTag,
291                 currentServiceIndex, nextServiceIndex);
292
293         // Install Split Horizon drop flow only for the default egress service -
294         // this flow drops traffic targeted to external interfaces if they
295         // arrived
296         // from an external interface (marked with the SH bit)
297         if (boundService.getServicePriority() == ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
298                 NwConstants.DEFAULT_EGRESS_SERVICE_INDEX)) {
299             installEgressDispatcherSplitHorizonFlow(dpId, boundService, interfaceName, writeTransaction, interfaceTag,
300                     currentServiceIndex, iface);
301         }
302     }
303
304     private static void installEgressDispatcherFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
305             WriteTransaction writeTransaction, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
306
307         // Get the metadata and mask from the service's write metadata instruction
308         StypeOpenflow stypeOpenflow = boundService.getAugmentation(StypeOpenflow.class);
309         if (stypeOpenflow == null) {
310             LOG.warn("Could not install egress dispatcher flow, missing service openflow configuration");
311             return;
312         }
313         List<Instruction> serviceInstructions = stypeOpenflow.getInstruction() != null
314                 ? stypeOpenflow.getInstruction()
315                 : Collections.emptyList();
316
317         // build the final instruction for LPort Dispatcher table flow entry
318         List<Action> finalApplyActions = new ArrayList<>();
319         List<Instruction> instructions = new ArrayList<>();
320         if (boundService.getServicePriority() != ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
321                 NwConstants.DEFAULT_EGRESS_SERVICE_INDEX)) {
322             BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(serviceInstructions);
323             BigInteger metadataMask = MetaDataUtil.getWriteMetaDataMaskForEgressDispatcherTable();
324             instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadataValues[0], metadataMask,
325                     instructions.size()));
326             finalApplyActions.add(MDSALUtil.createSetReg6Action(finalApplyActions.size(), 0, 31,
327                     MetaDataUtil.getReg6ValueForLPortDispatcher(interfaceTag, nextServiceIndex)));
328         }
329
330         final int applyActionsOffset = finalApplyActions.size();
331         for (Instruction info : serviceInstructions) {
332             if (info.getInstruction() instanceof WriteActionsCase) {
333                 List<Action> writeActions = ActionConverterUtil.convertServiceActionToFlowAction(
334                         ((WriteActionsCase) info.getInstruction()).getWriteActions().getAction());
335                 instructions.add(MDSALUtil.buildWriteActionsInstruction(writeActions, instructions.size()));
336             } else if (info.getInstruction() instanceof ApplyActionsCase) {
337                 List<Action> applyActions = ActionConverterUtil.convertServiceActionToFlowAction(
338                         ((ApplyActionsCase) info.getInstruction()).getApplyActions().getAction(),
339                         applyActionsOffset);
340                 finalApplyActions.addAll(applyActions);
341             } else if (!(info.getInstruction() instanceof WriteMetadataCase)) {
342                 // Skip meta data write as that is handled already
343                 instructions.add(MDSALUtil.buildInstruction(info, instructions.size()));
344             }
345         }
346         if (!finalApplyActions.isEmpty()) {
347             instructions.add(MDSALUtil.buildApplyActionsInstruction(finalApplyActions, instructions.size()));
348         }
349
350         // build the flow and install it
351         String serviceRef = boundService.getServiceName();
352         List<? extends MatchInfoBase> matches = FlowBasedServicesUtils
353                 .getMatchInfoForEgressDispatcherTable(interfaceTag, currentServiceIndex);
354         String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, interfaceName, boundService,
355             currentServiceIndex);
356         Flow egressFlow = MDSALUtil.buildFlowNew(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, flowRef,
357                 boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenflow.getFlowCookie(), matches,
358                 instructions);
359         LOG.debug("Installing Egress Dispatcher Flow for interface : {}, with flow-ref : {}", interfaceName, flowRef);
360         installFlow(dpId, egressFlow, writeTransaction);
361     }
362
363     public static void installEgressDispatcherSplitHorizonFlow(BigInteger dpId, BoundServices boundService,
364             String interfaceName, WriteTransaction writeTransaction, int interfaceTag, short currentServiceIndex,
365             Interface iface) {
366         // only install split horizon drop flows for external interfaces
367         if (!isExternal(iface)) {
368             return;
369         }
370
371         if (LOG.isDebugEnabled()) {
372             LOG.debug("Installing split horizon drop flow for external interface {} on dpId {}", interfaceName, dpId);
373         }
374
375         BigInteger shFlagSet = BigInteger.ONE; // BigInteger.ONE is used for
376                                                 // checking the Split-Horizon
377                                                 // flag
378         List<MatchInfoBase> shMatches = FlowBasedServicesUtils.getMatchInfoForEgressDispatcherTable(interfaceTag,
379                 currentServiceIndex);
380         shMatches.add(new MatchMetadata(shFlagSet, MetaDataUtil.METADATA_MASK_SH_FLAG));
381         List<InstructionInfo> shInstructions = new ArrayList<>();
382         List<ActionInfo> actionsInfos = new ArrayList<>();
383         actionsInfos.add(new ActionDrop());
384         shInstructions.add(new InstructionApplyActions(actionsInfos));
385
386         String flowRef = getSplitHorizonFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, interfaceName,
387                 currentServiceIndex, shFlagSet);
388         String serviceRef = boundService.getServiceName();
389         // This must be higher priority than the egress flow
390         int splitHorizonFlowPriority = boundService.getServicePriority() + 1;
391         StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
392         Flow egressSplitHorizonFlow = MDSALUtil.buildFlow(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, flowRef,
393                 splitHorizonFlowPriority, serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), shMatches, shInstructions);
394
395         installFlow(dpId, egressSplitHorizonFlow, writeTransaction);
396     }
397
398     public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
399             BigInteger cookie, List<Instruction> instructions) {
400         StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority)
401                 .setInstruction(instructions);
402         return new BoundServicesBuilder().setKey(new BoundServicesKey(servicePriority)).setServiceName(serviceName)
403                 .setServicePriority(servicePriority).setServiceType(ServiceTypeFlowBased.class)
404                 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
405     }
406
407     public static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short serviceIndex) {
408         return InstanceIdentifier.builder(ServiceBindings.class)
409                 .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
410                 .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
411     }
412
413     public static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short serviceIndex,
414             Class<? extends ServiceModeBase> serviceMode) {
415         return InstanceIdentifier.builder(ServiceBindings.class)
416                 .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, serviceMode))
417                 .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
418     }
419
420     public static void unbindDefaultEgressDispatcherService(DataBroker dataBroker, String interfaceName) {
421         IfmUtil.unbindService(dataBroker, interfaceName,
422                 buildServiceId(interfaceName, ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
423                         NwConstants.DEFAULT_EGRESS_SERVICE_INDEX), ServiceModeEgress.class));
424     }
425
426     public static void bindDefaultEgressDispatcherService(DataBroker dataBroker, List<ListenableFuture<Void>> futures,
427                                                           Interface interfaceInfo, String portNo,
428                                                           String interfaceName, int ifIndex) {
429         List<Instruction> instructions =
430                 IfmUtil.getEgressInstructionsForInterface(interfaceInfo, portNo, null, true, ifIndex, 0);
431         bindDefaultEgressDispatcherService(dataBroker, futures, interfaceName, instructions);
432     }
433
434     public static void bindDefaultEgressDispatcherService(DataBroker dataBroker, List<ListenableFuture<Void>> futures,
435             Interface interfaceInfo, String interfaceName, int ifIndex, long groupId) {
436         List<Instruction> instructions =
437              IfmUtil.getEgressInstructionsForInterface(interfaceInfo, StringUtils.EMPTY, null, true, ifIndex, groupId);
438         bindDefaultEgressDispatcherService(dataBroker, futures, interfaceName, instructions);
439     }
440
441     public static void bindDefaultEgressDispatcherService(DataBroker dataBroker, List<ListenableFuture<Void>> futures,
442             String interfaceName, List<Instruction> instructions) {
443         WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
444         int priority = ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
445                                              NwConstants.DEFAULT_EGRESS_SERVICE_INDEX);
446         BoundServices
447                 serviceInfo =
448                 getBoundServices(String.format("%s.%s", "default", interfaceName),
449                         ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
450                                               NwConstants.DEFAULT_EGRESS_SERVICE_INDEX),
451                         priority, NwConstants.EGRESS_DISPATCHER_TABLE_COOKIE, instructions);
452         IfmUtil.bindService(tx, interfaceName, serviceInfo, ServiceModeEgress.class);
453         futures.add(tx.submit());
454     }
455
456     public static void removeIngressFlow(String interfaceName, BigInteger dpId, DataBroker dataBroker,
457             List<ListenableFuture<Void>> futures) {
458         if (dpId == null) {
459             return;
460         }
461         LOG.debug("Removing Ingress Flows for {}", interfaceName);
462         WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
463         String flowKeyStr = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, interfaceName);
464         FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
465         Node nodeDpn = buildInventoryDpnNode(dpId);
466         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
467                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
468                 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey)
469                 .build();
470
471         writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
472         futures.add(writeTransaction.submit());
473     }
474
475     public static void removeIngressFlow(String name, BoundServices serviceOld, BigInteger dpId,
476             WriteTransaction writeTransaction) {
477         String flowKeyStr = getFlowRef(dpId, NwConstants.VLAN_INTERFACE_INGRESS_TABLE, name, serviceOld,
478                 serviceOld.getServicePriority());
479         LOG.debug("Removing Ingress Flow {}", flowKeyStr);
480         FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
481         Node nodeDpn = buildInventoryDpnNode(dpId);
482         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
483                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
484                 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey)
485                 .build();
486
487         writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
488     }
489
490     public static void removeLPortDispatcherFlow(BigInteger dpId, String iface, BoundServices boundServicesOld,
491             WriteTransaction writeTransaction, short currentServiceIndex) {
492         LOG.debug("Removing LPort Dispatcher Flows {}, {}", dpId, iface);
493
494         boundServicesOld.getAugmentation(StypeOpenflow.class);
495         // build the flow and install it
496         String flowRef = getFlowRef(dpId, NwConstants.LPORT_DISPATCHER_TABLE, iface, boundServicesOld,
497             currentServiceIndex);
498         FlowKey flowKey = new FlowKey(new FlowId(flowRef));
499         Node nodeDpn = buildInventoryDpnNode(dpId);
500         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
501                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
502                 .child(Table.class, new TableKey(NwConstants.LPORT_DISPATCHER_TABLE)).child(Flow.class, flowKey)
503                 .build();
504
505         writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
506     }
507
508     public static void removeEgressDispatcherFlows(BigInteger dpId, String iface, BoundServices boundServicesOld,
509             WriteTransaction writeTransaction, short currentServiceIndex) {
510         LOG.debug("Removing Egress Dispatcher Flows {}, {}", dpId, iface);
511         removeEgressDispatcherFlow(dpId, iface, writeTransaction, currentServiceIndex, boundServicesOld);
512         removeEgressSplitHorizonDispatcherFlow(dpId, iface, writeTransaction, currentServiceIndex);
513     }
514
515     private static void removeEgressDispatcherFlow(BigInteger dpId, String iface, WriteTransaction writeTransaction,
516             short currentServiceIndex, BoundServices boundServicesOld) {
517         // build the flow and install it
518         String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, iface, boundServicesOld,
519             currentServiceIndex);
520         FlowKey flowKey = new FlowKey(new FlowId(flowRef));
521         Node nodeDpn = buildInventoryDpnNode(dpId);
522         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
523                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
524                 .child(Table.class, new TableKey(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE)).child(Flow.class, flowKey)
525                 .build();
526
527         writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
528     }
529
530     public static void removeEgressSplitHorizonDispatcherFlow(BigInteger dpId, String iface,
531             WriteTransaction writeTransaction, short currentServiceIndex) {
532         // BigInteger.ONE is used for checking the Split-Horizon flag
533         BigInteger shFlagSet = BigInteger.ONE;
534         String shFlowRef = getSplitHorizonFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, iface,
535                 currentServiceIndex, shFlagSet);
536         FlowKey shFlowKey = new FlowKey(new FlowId(shFlowRef));
537         Node nodeDpn = buildInventoryDpnNode(dpId);
538         InstanceIdentifier<Flow> shFlowInstanceId = InstanceIdentifier.builder(Nodes.class)
539                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
540                 .child(Table.class, new TableKey(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE))
541                 .child(Flow.class, shFlowKey).build();
542
543         writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, shFlowInstanceId);
544     }
545
546     public static String getFlowRef(short tableId, BigInteger dpnId, String infName) {
547         return String.format("%d:%s:%s", tableId, dpnId, infName);
548     }
549
550     private static String getFlowRef(BigInteger dpnId, short tableId, String iface,BoundServices service,
551                                      short currentServiceIndex) {
552         return String.valueOf(dpnId) + tableId + NwConstants.FLOWID_SEPARATOR + iface + NwConstants.FLOWID_SEPARATOR
553                 + currentServiceIndex;
554     }
555
556     private static String getSplitHorizonFlowRef(BigInteger dpnId, short tableId, String iface,
557             short currentServiceIndex, BigInteger shFlag) {
558         return new StringBuffer().append(dpnId).append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(iface)
559                 .append(NwConstants.FLOWID_SEPARATOR).append(shFlag.toString()).toString();
560     }
561
562     /**
563      * This utility method returns an array of ServiceInfo in which index 0 will
564      * have the immediate lower priority service and index 1 will have the
565      * immediate higher priority service among the list of existing
566      * serviceInfos.
567      *
568      * @param serviceInfos
569      *            list of services bound
570      * @param currentServiceInfo
571      *            current service bound
572      * @return array bound services
573      */
574     public static BoundServices[] getHighAndLowPriorityService(List<BoundServices> serviceInfos,
575             BoundServices currentServiceInfo) {
576         // This will be used to hold the immediate higher service priority with respect to the currentServiceInfo
577         BoundServices higher = null;
578         // This will be used to hold the immediate lower service priority with respect to the currentServiceInfo
579         BoundServices lower = null;
580         if (serviceInfos == null || serviceInfos.isEmpty()) {
581             return new BoundServices[] { lower, higher };
582         }
583         List<BoundServices> availableServiceInfos = new ArrayList<>(serviceInfos);
584         Collections.sort(availableServiceInfos, (serviceInfo1, serviceInfo2) -> serviceInfo1.getServicePriority()
585                 .compareTo(serviceInfo2.getServicePriority()));
586         for (BoundServices availableServiceInfo : availableServiceInfos) {
587             if (currentServiceInfo.getServicePriority() < availableServiceInfo.getServicePriority()) {
588                 lower = availableServiceInfo;
589                 break;
590             } else {
591                 higher = availableServiceInfo;
592             }
593         }
594         return new BoundServices[] { lower, higher };
595     }
596
597     public static BoundServices getHighestPriorityService(List<BoundServices> serviceInfos) {
598         List<BoundServices> availableServiceInfos = new ArrayList<>(serviceInfos);
599         if (availableServiceInfos.isEmpty()) {
600             return null;
601         }
602         BoundServices highPriorityService = availableServiceInfos.get(0);
603         availableServiceInfos.remove(0);
604         for (BoundServices availableServiceInfo : availableServiceInfos) {
605             if (availableServiceInfo.getServicePriority() < highPriorityService.getServicePriority()) {
606                 highPriorityService = availableServiceInfo;
607             }
608         }
609         return highPriorityService;
610     }
611
612     public static void installLportIngressFlow(BigInteger dpId, long portNo, Interface iface,
613             List<ListenableFuture<Void>> futures, DataBroker dataBroker, int lportTag) {
614         int vlanId = 0;
615         boolean isVlanTransparent = false;
616
617         IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
618         if (l2vlan != null) {
619             vlanId = l2vlan.getVlanId() == null ? 0 : l2vlan.getVlanId().getValue();
620             isVlanTransparent = l2vlan.getL2vlanMode() == IfL2vlan.L2vlanMode.Transparent;
621         }
622         int instructionKey = 0;
623
624         List<Instruction> instructions = new ArrayList<>();
625
626         final SplitHorizon splitHorizon = iface.getAugmentation(SplitHorizon.class);
627         boolean overrideSplitHorizonProtection = splitHorizon != null
628                 && splitHorizon.isOverrideSplitHorizonProtection();
629         int actionKey = 0;
630         List<Action> actions = new ArrayList<>();
631         if (vlanId != 0 && !isVlanTransparent) {
632             actions.add(MDSALUtil.createPopVlanAction(actionKey++));
633         }
634         if (overrideSplitHorizonProtection) {
635             actions.add(MDSALUtil.createNxOfInPortAction(actionKey++, 0));
636         }
637         if (!actions.isEmpty()) {
638             instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, instructionKey++));
639         }
640         BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, (short) 0, BigInteger.ZERO,
641                 isExternal(iface));
642         BigInteger metadataMask = MetaDataUtil
643                 .getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_LPORT_TAG_SH_FLAG);
644         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, instructionKey++));
645         instructions
646                 .add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.LPORT_DISPATCHER_TABLE, instructionKey++));
647         int priority = isVlanTransparent ? 1
648                 : vlanId == 0 ? IfmConstants.FLOW_PRIORITY_FOR_UNTAGGED_VLAN : IfmConstants.FLOW_HIGH_PRIORITY;
649         String flowRef = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, iface.getName());
650         List<MatchInfo> matches = getMatchInfoForVlanPortAtIngressTable(dpId, portNo, iface);
651         Flow ingressFlow = MDSALUtil.buildFlowNew(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, flowRef, priority, flowRef,
652                 0, 0, NwConstants.VLAN_TABLE_COOKIE, matches, instructions);
653         LOG.debug("Installing ingress flow {} for {}", flowRef, iface.getName());
654         WriteTransaction inventoryConfigShardTransaction = dataBroker.newWriteOnlyTransaction();
655         installFlow(dpId, ingressFlow, inventoryConfigShardTransaction);
656         futures.add(inventoryConfigShardTransaction.submit());
657     }
658
659     public static BoundServicesState buildBoundServicesState(
660         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface
661             interfaceState, Class<? extends ServiceModeBase> serviceMode) {
662         NodeConnectorId nodeConnectorId = IfmUtil.getNodeConnectorIdFromInterface(interfaceState);
663         BigInteger dpId = IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId);
664         long portNo = IfmUtil.getPortNumberFromNodeConnectorId(nodeConnectorId);
665         BoundServicesStateKey boundServicesStateKey = new BoundServicesStateKey(interfaceState.getName(), serviceMode);
666         return new BoundServicesStateBuilder().setDpid(dpId).setIfIndex(interfaceState.getIfIndex())
667             .setInterfaceName(interfaceState.getName()).setInterfaceType(interfaceState.getType()).setPortNo(portNo)
668             .setServiceMode(serviceMode).setKey(boundServicesStateKey).build();
669     }
670
671     public static BoundServicesState getBoundServicesState(DataBroker dataBroker,
672                                                            String interfaceName,
673                                                            Class<? extends ServiceModeBase>
674                                                                                  serviceMode) {
675         InstanceIdentifier<BoundServicesState> id = InstanceIdentifier.builder(BoundServicesStateList.class)
676             .child(BoundServicesState.class, new BoundServicesStateKey(interfaceName, serviceMode)).build();
677         return IfmUtil.read(LogicalDatastoreType.OPERATIONAL, id, dataBroker).orNull();
678     }
679
680     public static void addBoundServicesState(DataBroker dataBroker, String interfaceName,
681                                              BoundServicesState interfaceBoundServicesState) {
682         LOG.info("adding bound-service state information for interface : {}", interfaceBoundServicesState);
683         InstanceIdentifier<BoundServicesState> id = InstanceIdentifier.builder(BoundServicesStateList.class)
684             .child(BoundServicesState.class, new BoundServicesStateKey(interfaceName,
685                 interfaceBoundServicesState.getServiceMode())).build();
686         WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
687         writeTransaction.put(LogicalDatastoreType.OPERATIONAL, id, interfaceBoundServicesState, true);
688         writeTransaction.submit();
689     }
690
691     public static  void removeBoundServicesState(DataBroker dataBroker, String interfaceName, Class<?
692         extends ServiceModeBase> serviceMode) {
693         LOG.info("remove bound-service state information for interface : {}", interfaceName);
694         InstanceIdentifier<BoundServicesState> id = InstanceIdentifier.builder(BoundServicesStateList.class)
695             .child(BoundServicesState.class, new BoundServicesStateKey(interfaceName, serviceMode)).build();
696         WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
697         writeTransaction.delete(LogicalDatastoreType.OPERATIONAL, id);
698         writeTransaction.submit();
699     }
700
701     private static boolean isExternal(Interface iface) {
702         if (iface == null) {
703             return false;
704         }
705         IfExternal ifExternal = iface.getAugmentation(IfExternal.class);
706         return ifExternal != null && Boolean.TRUE.equals(ifExternal.isExternal());
707     }
708 }