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