MRI version bump for Aluminium
[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             instructionSet.put(MDSALUtil.buildAndGetPopVlanActionInstruction(actionKey,
211                     ++serviceInstructionsSize).key(), MDSALUtil.buildAndGetPopVlanActionInstruction(actionKey,
212                     ++serviceInstructionsSize));
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             instructionSet.put(
224                     MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask,
225                             ++serviceInstructionsSize).key(),
226                     MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++serviceInstructionsSize));
227         }
228
229         if (instructions != null && !instructions.isEmpty()) {
230             for (Instruction info : instructions.values()) {
231                 // Skip meta data write as that is handled already
232                 if (info.getInstruction() instanceof WriteMetadataCase) {
233                     continue;
234                 } else if (info.getInstruction() instanceof WriteActionsCase) {
235                     info = MDSALUtil.buildWriteActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
236                             ((WriteActionsCase) info.getInstruction()).getWriteActions().getAction()));
237                 } else if (info.getInstruction() instanceof ApplyActionsCase) {
238                     info = MDSALUtil.buildApplyActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
239                             ((ApplyActionsCase) info.getInstruction()).getApplyActions().getAction()));
240                 }
241                 instructions.put(info.key(),info);
242             }
243         }
244
245         String serviceRef = boundServiceNew.getServiceName();
246         String flowRef = getFlowRef(dpId, NwConstants.VLAN_INTERFACE_INGRESS_TABLE, iface.getName(),
247                 boundServiceNew.getServicePriority().toJava());
248         StypeOpenflow stypeOpenflow = boundServiceNew.augmentation(StypeOpenflow.class);
249         Flow ingressFlow = MDSALUtil.buildFlowNew(tableId, flowRef, stypeOpenflow.getFlowPriority().toJava(),
250                 serviceRef, 0, 0, stypeOpenflow.getFlowCookie(), matches, instructionSet);
251         installFlow(dpId, ingressFlow, tx);
252     }
253
254     public static void installFlow(Uint64 dpId, Flow flow, TypedWriteTransaction<Configuration> writeTransaction) {
255         FlowKey flowKey = new FlowKey(new FlowId(flow.getId()));
256         Node nodeDpn = buildInventoryDpnNode(dpId);
257         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
258                 .child(Node.class, nodeDpn.key()).augmentation(FlowCapableNode.class)
259                 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
260
261         writeTransaction.mergeParentStructurePut(flowInstanceId, flow);
262         EVENT_LOGGER.debug("IFM,InstallFlow {}", flow.getId());
263     }
264
265     private static Node buildInventoryDpnNode(Uint64 dpnId) {
266         NodeId nodeId = new NodeId("openflow:" + dpnId);
267         return new NodeBuilder().setId(nodeId).withKey(new NodeKey(nodeId)).build();
268     }
269
270     public static void installLPortDispatcherFlow(Uint64 dpId, BoundServices boundService, String interfaceName,
271             TypedWriteTransaction<Configuration> tx, int interfaceTag, short currentServiceIndex,
272             short nextServiceIndex) {
273         String serviceRef = boundService.getServiceName();
274         List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForDispatcherTable(interfaceTag,
275                 currentServiceIndex);
276
277         // Get the metadata and mask from the service's write metadata
278         // instruction
279         StypeOpenflow stypeOpenFlow = boundService.augmentation(StypeOpenflow.class);
280         @Nullable Map<InstructionKey, Instruction> serviceInstructions = stypeOpenFlow.getInstruction();
281         int instructionSize = serviceInstructions != null ? serviceInstructions.size() : 0;
282         Uint64[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(serviceInstructions);
283         Uint64 metadata = MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, nextServiceIndex, metadataValues[0]);
284         Uint64 metadataMask = MetaDataUtil.getWriteMetaDataMaskForDispatcherTable();
285
286         // build the final instruction for LPort Dispatcher table flow entry
287         Map<InstructionKey, Instruction> instructions = new HashMap<>();
288         instructions.put(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++instructionSize).key(),
289                 MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++instructionSize));
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                 instructions.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(), matches, instructions);
312         LOG.debug("Installing LPort Dispatcher Flow on DPN {}, for interface {}, with flowRef {}", dpId,
313             interfaceName, flowRef);
314         installFlow(dpId, ingressFlow, tx);
315     }
316
317     public static void installEgressDispatcherFlows(Uint64 dpId, BoundServices boundService, String interfaceName,
318             TypedWriteTransaction<Configuration> tx, int interfaceTag, short currentServiceIndex,
319             short nextServiceIndex, Interface iface) {
320         LOG.debug("Installing Egress Dispatcher Flows on dpn : {}, for interface : {}", dpId, interfaceName);
321         installEgressDispatcherFlow(dpId, boundService, interfaceName, tx, interfaceTag,
322                 currentServiceIndex, nextServiceIndex);
323
324         // Install Split Horizon drop flow only for the default egress service -
325         // this flow drops traffic targeted to external interfaces if they
326         // arrived
327         // from an external interface (marked with the SH bit)
328         if (boundService.getServicePriority().toJava() == ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
329                 NwConstants.DEFAULT_EGRESS_SERVICE_INDEX)) {
330             installEgressDispatcherSplitHorizonFlow(dpId, boundService, interfaceName, tx, interfaceTag,
331                     currentServiceIndex, iface);
332         }
333     }
334
335     private static void installEgressDispatcherFlow(Uint64 dpId, BoundServices boundService, String interfaceName,
336             TypedWriteTransaction<Configuration> tx, int interfaceTag, short currentServiceIndex,
337             short nextServiceIndex) {
338
339         // Get the metadata and mask from the service's write metadata instruction
340         StypeOpenflow stypeOpenflow = boundService.augmentation(StypeOpenflow.class);
341         if (stypeOpenflow == null) {
342             LOG.warn("Could not install egress dispatcher flow, missing service openflow configuration");
343             return;
344         }
345         Map<InstructionKey, Instruction> serviceInstructions = stypeOpenflow.getInstruction() != null
346                 ? stypeOpenflow.getInstruction()
347                 : Collections.emptyMap();
348
349         // build the final instruction for LPort Dispatcher table flow entry
350         List<Action> finalApplyActions = new ArrayList<>();
351         Map<InstructionKey, Instruction> instructions = new HashMap<>();
352         if (boundService.getServicePriority().toJava() != ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
353                 NwConstants.DEFAULT_EGRESS_SERVICE_INDEX)) {
354             Uint64[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(serviceInstructions);
355             Uint64 metadataMask = MetaDataUtil.getWriteMetaDataMaskForEgressDispatcherTable();
356             instructions.put(MDSALUtil.buildAndGetWriteMetadaInstruction(metadataValues[0], metadataMask,
357                     instructions.size()).key(),MDSALUtil.buildAndGetWriteMetadaInstruction(metadataValues[0],
358                     metadataMask, instructions.size()));
359             finalApplyActions.add(MDSALUtil.createSetReg6Action(finalApplyActions.size(), 0, 31,
360                     MetaDataUtil.getReg6ValueForLPortDispatcher(interfaceTag, nextServiceIndex)));
361         }
362
363         final int applyActionsOffset = finalApplyActions.size();
364         for (Instruction info : serviceInstructions.values()) {
365             if (info.getInstruction() instanceof WriteActionsCase) {
366                 List<Action> writeActions = ActionConverterUtil.convertServiceActionToFlowAction(
367                         ((WriteActionsCase) info.getInstruction()).getWriteActions().getAction());
368                 instructions.put(MDSALUtil.buildWriteActionsInstruction(writeActions, instructions.size()).key(),
369                         MDSALUtil.buildWriteActionsInstruction(writeActions, instructions.size()));
370             } else if (info.getInstruction() instanceof ApplyActionsCase) {
371                 List<Action> applyActions = ActionConverterUtil.convertServiceActionToFlowAction(
372                         ((ApplyActionsCase) info.getInstruction()).getApplyActions().getAction(),
373                         applyActionsOffset);
374                 finalApplyActions.addAll(applyActions);
375             } else if (!(info.getInstruction() instanceof WriteMetadataCase)) {
376                 // Skip meta data write as that is handled already
377                 instructions.put(MDSALUtil.buildInstruction(info, instructions.size()).key(),
378                         MDSALUtil.buildInstruction(info, instructions.size()));
379             }
380         }
381         if (!finalApplyActions.isEmpty()) {
382             instructions.put(MDSALUtil.buildApplyActionsInstruction(finalApplyActions, instructions.size()).key(),
383                     MDSALUtil.buildApplyActionsInstruction(finalApplyActions, instructions.size()));
384         }
385
386         // build the flow and install it
387         String serviceRef = boundService.getServiceName();
388         List<? extends MatchInfoBase> matches = FlowBasedServicesUtils
389                 .getMatchInfoForEgressDispatcherTable(interfaceTag, currentServiceIndex);
390         String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, interfaceName,
391                 currentServiceIndex);
392         Flow egressFlow = MDSALUtil.buildFlowNew(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, flowRef,
393                 boundService.getServicePriority().toJava(), serviceRef, 0, 0, stypeOpenflow.getFlowCookie(),
394                 matches, instructions);
395         LOG.debug("Installing Egress Dispatcher Flow for interface : {}, with flow-ref : {}", interfaceName, flowRef);
396         installFlow(dpId, egressFlow, tx);
397     }
398
399     public static void installEgressDispatcherSplitHorizonFlow(Uint64 dpId, BoundServices boundService,
400             String interfaceName, TypedWriteTransaction<Configuration> tx, int interfaceTag, short currentServiceIndex,
401             Interface iface) {
402         // only install split horizon drop flows for external interfaces
403         if (!isExternal(iface)) {
404             return;
405         }
406
407         if (LOG.isDebugEnabled()) {
408             LOG.debug("Installing split horizon drop flow for external interface {} on dpId {}", interfaceName, dpId);
409         }
410
411         // Uint64.ONE is used for checking the Split-Horizon flag
412         Uint64 shFlagSet = Uint64.ONE;
413         List<MatchInfoBase> shMatches = FlowBasedServicesUtils.getMatchInfoForEgressDispatcherTable(interfaceTag,
414                 currentServiceIndex);
415         shMatches.add(new MatchMetadata(shFlagSet, MetaDataUtil.METADATA_MASK_SH_FLAG));
416         List<InstructionInfo> shInstructions = new ArrayList<>();
417         List<ActionInfo> actionsInfos = new ArrayList<>();
418         actionsInfos.add(new ActionDrop());
419         shInstructions.add(new InstructionApplyActions(actionsInfos));
420
421         String flowRef = getSplitHorizonFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, interfaceName,
422                 shFlagSet);
423         String serviceRef = boundService.getServiceName();
424         // This must be higher priority than the egress flow
425         int splitHorizonFlowPriority = boundService.getServicePriority().toJava() + 1;
426         StypeOpenflow stypeOpenFlow = boundService.augmentation(StypeOpenflow.class);
427         Flow egressSplitHorizonFlow = MDSALUtil.buildFlow(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, flowRef,
428                 splitHorizonFlowPriority, serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(),
429                 shMatches, shInstructions);
430
431         installFlow(dpId, egressSplitHorizonFlow, tx);
432     }
433
434     public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
435             Uint64 cookie, List<Instruction> instructions) {
436         StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority)
437                 .setInstruction(instructions);
438         return new BoundServicesBuilder().withKey(new BoundServicesKey(servicePriority)).setServiceName(serviceName)
439                 .setServicePriority(servicePriority).setServiceType(ServiceTypeFlowBased.class)
440                 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
441     }
442
443     public static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short serviceIndex) {
444         return InstanceIdentifier.builder(ServiceBindings.class)
445                 .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
446                 .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
447     }
448
449     public static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short serviceIndex,
450             Class<? extends ServiceModeBase> serviceMode) {
451         return InstanceIdentifier.builder(ServiceBindings.class)
452                 .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, serviceMode))
453                 .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
454     }
455
456     public static InstanceIdentifier<BoundServices> buildDefaultServiceId(String interfaceName) {
457         return buildServiceId(interfaceName, ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
458                 NwConstants.DEFAULT_EGRESS_SERVICE_INDEX), ServiceModeEgress.class);
459     }
460
461     public static ListenableFuture<Void> bindDefaultEgressDispatcherService(ManagedNewTransactionRunner txRunner,
462             Interface interfaceInfo, String portNo, String interfaceName, int ifIndex) {
463         List<Instruction> instructions =
464                 IfmUtil.getEgressInstructionsForInterface(interfaceInfo, portNo, null, true, ifIndex, 0);
465         return bindDefaultEgressDispatcherService(txRunner, interfaceName, instructions);
466     }
467
468     public static void bindDefaultEgressDispatcherService(TypedWriteTransaction<Configuration> tx,
469         Interface interfaceInfo, String portNo, String interfaceName, int ifIndex) {
470         List<Instruction> instructions =
471             IfmUtil.getEgressInstructionsForInterface(interfaceInfo, portNo, null, true, ifIndex, 0);
472         bindDefaultEgressDispatcherService(tx, interfaceName, instructions);
473     }
474
475     public static ListenableFuture<Void> bindDefaultEgressDispatcherService(ManagedNewTransactionRunner txRunner,
476             Interface interfaceInfo, String interfaceName, int ifIndex, long groupId) {
477         List<Instruction> instructions =
478              IfmUtil.getEgressInstructionsForInterface(interfaceInfo, StringUtils.EMPTY, null, true, ifIndex, groupId);
479         return bindDefaultEgressDispatcherService(txRunner, interfaceName, instructions);
480     }
481
482     public static ListenableFuture<Void> bindDefaultEgressDispatcherService(ManagedNewTransactionRunner txRunner,
483             String interfaceName, List<Instruction> instructions) {
484         return txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
485             int priority = ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
486                     NwConstants.DEFAULT_EGRESS_SERVICE_INDEX);
487             BoundServices
488                     serviceInfo =
489                     getBoundServices(defaultInterfaceName(interfaceName),
490                             ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
491                                     NwConstants.DEFAULT_EGRESS_SERVICE_INDEX),
492                             priority, NwConstants.EGRESS_DISPATCHER_TABLE_COOKIE, instructions);
493             IfmUtil.bindService(tx, interfaceName, serviceInfo, ServiceModeEgress.class);
494         });
495     }
496
497     public static void bindDefaultEgressDispatcherService(TypedWriteTransaction<Configuration> tx,
498         String interfaceName, List<Instruction> instructions) {
499         int priority = ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
500             NwConstants.DEFAULT_EGRESS_SERVICE_INDEX);
501         BoundServices
502             serviceInfo =
503             getBoundServices(defaultInterfaceName(interfaceName),
504                 ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
505                     NwConstants.DEFAULT_EGRESS_SERVICE_INDEX),
506                 priority, NwConstants.EGRESS_DISPATCHER_TABLE_COOKIE, instructions);
507         IfmUtil.bindService(tx, interfaceName, serviceInfo, ServiceModeEgress.class);
508     }
509
510     private static String defaultInterfaceName(final String interfaceName) {
511         return "default." + interfaceName;
512     }
513
514     public static void removeIngressFlow(String interfaceName, Uint64 dpId, ManagedNewTransactionRunner txRunner,
515             List<ListenableFuture<Void>> futures) {
516         if (dpId == null) {
517             return;
518         }
519         LOG.debug("Removing Ingress Flows for {}", interfaceName);
520         futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
521             String flowKeyStr = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, interfaceName);
522             FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
523             Node nodeDpn = buildInventoryDpnNode(dpId);
524             InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
525                     .child(Node.class, nodeDpn.key()).augmentation(FlowCapableNode.class)
526                     .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class,
527                             flowKey)
528                     .build();
529
530             tx.delete(flowInstanceId);
531         }));
532     }
533
534     public static void removeIngressFlow(String name, BoundServices serviceOld, Uint64 dpId,
535             TypedWriteTransaction<Configuration> writeTransaction) {
536         String flowKeyStr = getFlowRef(dpId, NwConstants.VLAN_INTERFACE_INGRESS_TABLE, name,
537                 serviceOld.getServicePriority().toJava());
538         LOG.debug("Removing Ingress Flow {}", flowKeyStr);
539         FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
540         Node nodeDpn = buildInventoryDpnNode(dpId);
541         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
542                 .child(Node.class, nodeDpn.key()).augmentation(FlowCapableNode.class)
543                 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey)
544                 .build();
545
546         writeTransaction.delete(flowInstanceId);
547     }
548
549     public static void removeLPortDispatcherFlow(Uint64 dpId, String iface, BoundServices boundServicesOld,
550             TypedWriteTransaction<Configuration> writeTransaction, short currentServiceIndex) {
551         LOG.debug("Removing LPort Dispatcher Flows {}, {}", dpId, iface);
552
553         boundServicesOld.augmentation(StypeOpenflow.class);
554         // build the flow and install it
555         String flowRef = getFlowRef(dpId, NwConstants.LPORT_DISPATCHER_TABLE, iface,
556                 currentServiceIndex);
557         FlowKey flowKey = new FlowKey(new FlowId(flowRef));
558         Node nodeDpn = buildInventoryDpnNode(dpId);
559         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
560                 .child(Node.class, nodeDpn.key()).augmentation(FlowCapableNode.class)
561                 .child(Table.class, new TableKey(NwConstants.LPORT_DISPATCHER_TABLE)).child(Flow.class, flowKey)
562                 .build();
563
564         writeTransaction.delete(flowInstanceId);
565         EVENT_LOGGER.debug("IFM,removeFlow {}", flowRef);
566     }
567
568     public static void removeEgressDispatcherFlows(Uint64 dpId, String iface,
569             TypedWriteTransaction<Configuration> writeTransaction, short currentServiceIndex) {
570         LOG.debug("Removing Egress Dispatcher Flows {}, {}", dpId, iface);
571         removeEgressDispatcherFlow(dpId, iface, writeTransaction, currentServiceIndex);
572         removeEgressSplitHorizonDispatcherFlow(dpId, iface, writeTransaction);
573     }
574
575     private static void removeEgressDispatcherFlow(Uint64 dpId, String iface,
576             TypedWriteTransaction<Configuration> writeTransaction, short currentServiceIndex) {
577         // build the flow and install it
578         String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, iface,
579                 currentServiceIndex);
580         FlowKey flowKey = new FlowKey(new FlowId(flowRef));
581         Node nodeDpn = buildInventoryDpnNode(dpId);
582         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
583                 .child(Node.class, nodeDpn.key()).augmentation(FlowCapableNode.class)
584                 .child(Table.class, new TableKey(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE)).child(Flow.class, flowKey)
585                 .build();
586
587         writeTransaction.delete(flowInstanceId);
588         EVENT_LOGGER.debug("IFM,removeFlow {}", flowRef);
589     }
590
591     public static void removeEgressSplitHorizonDispatcherFlow(Uint64 dpId, String iface,
592             TypedWriteTransaction<Configuration> writeTransaction) {
593         // Uint64.ONE is used for checking the Split-Horizon flag
594         Uint64 shFlagSet = Uint64.ONE;
595         String shFlowRef = getSplitHorizonFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, iface,
596                 shFlagSet);
597         FlowKey shFlowKey = new FlowKey(new FlowId(shFlowRef));
598         Node nodeDpn = buildInventoryDpnNode(dpId);
599         InstanceIdentifier<Flow> shFlowInstanceId = InstanceIdentifier.builder(Nodes.class)
600                 .child(Node.class, nodeDpn.key()).augmentation(FlowCapableNode.class)
601                 .child(Table.class, new TableKey(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE))
602                 .child(Flow.class, shFlowKey).build();
603
604         writeTransaction.delete(shFlowInstanceId);
605     }
606
607     public static String getFlowRef(short tableId, Uint64 dpnId, String infName) {
608         return tableId + ":" + dpnId + ":" + infName;
609     }
610
611     private static String getFlowRef(Uint64 dpnId, short tableId, String iface, short currentServiceIndex) {
612         return String.valueOf(dpnId) + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + iface
613                 + NwConstants.FLOWID_SEPARATOR + currentServiceIndex;
614     }
615
616     private static String getSplitHorizonFlowRef(Uint64 dpnId, short tableId, String iface, Uint64 shFlag) {
617         return String.valueOf(dpnId) + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + iface
618                 + NwConstants.FLOWID_SEPARATOR + shFlag.toString();
619     }
620
621     /**
622      * This utility method returns an array of ServiceInfo in which index 0 will
623      * have the immediate lower priority service and index 1 will have the
624      * immediate higher priority service among the list of existing
625      * serviceInfos.
626      *
627      * @param serviceInfos
628      *            list of services bound
629      * @param currentServiceInfo
630      *            current service bound
631      * @return array bound services
632      */
633     public static BoundServices[] getHighAndLowPriorityService(List<BoundServices> serviceInfos,
634             BoundServices currentServiceInfo) {
635         if (serviceInfos == null || serviceInfos.isEmpty()) {
636             return new BoundServices[] { null, null };
637         }
638
639         // This will be used to hold the immediate higher service priority with respect to the currentServiceInfo
640         BoundServices higher = null;
641         // This will be used to hold the immediate lower service priority with respect to the currentServiceInfo
642         BoundServices lower = null;
643
644         List<BoundServices> availableServiceInfos = new ArrayList<>(serviceInfos);
645         availableServiceInfos.sort(Comparator.comparing(BoundServices::getServicePriority));
646         for (BoundServices availableServiceInfo : availableServiceInfos) {
647             if (currentServiceInfo.getServicePriority().toJava() < availableServiceInfo.getServicePriority().toJava()) {
648                 lower = availableServiceInfo;
649                 break;
650             } else {
651                 higher = availableServiceInfo;
652             }
653         }
654         return new BoundServices[] { lower, higher };
655     }
656
657     public static BoundServices getHighestPriorityService(List<BoundServices> serviceInfos) {
658         List<BoundServices> availableServiceInfos = new ArrayList<>(serviceInfos);
659         if (availableServiceInfos.isEmpty()) {
660             return null;
661         }
662         BoundServices highPriorityService = availableServiceInfos.get(0);
663         availableServiceInfos.remove(0);
664         for (BoundServices availableServiceInfo : availableServiceInfos) {
665             if (availableServiceInfo.getServicePriority().toJava()
666                     < highPriorityService.getServicePriority().toJava()) {
667                 highPriorityService = availableServiceInfo;
668             }
669         }
670         return highPriorityService;
671     }
672
673     public static void installLportIngressFlow(Uint64 dpId, long portNo, Interface iface,
674             List<ListenableFuture<Void>> futures, ManagedNewTransactionRunner txRunner, int lportTag) {
675         int vlanId = 0;
676         boolean isVlanTransparent = false;
677
678         IfL2vlan l2vlan = iface.augmentation(IfL2vlan.class);
679         if (l2vlan != null) {
680             vlanId = l2vlan.getVlanId() == null ? 0 : l2vlan.getVlanId().getValue().toJava();
681             isVlanTransparent = l2vlan.getL2vlanMode() == IfL2vlan.L2vlanMode.Transparent;
682         }
683         int instructionKey = 0;
684
685         Map<InstructionKey, Instruction> instructions = new HashMap<>();
686
687         final SplitHorizon splitHorizon = iface.augmentation(SplitHorizon.class);
688         boolean overrideSplitHorizonProtection = splitHorizon != null
689                 && splitHorizon.isOverrideSplitHorizonProtection();
690         int actionKey = -1;
691         List<Action> actions = new ArrayList<>();
692         if (vlanId != 0 && !isVlanTransparent) {
693             actions.add(MDSALUtil.createPopVlanAction(++actionKey));
694         }
695         if (overrideSplitHorizonProtection) {
696             actions.add(MDSALUtil.createNxOfInPortAction(++actionKey, 0));
697         }
698         if (!actions.isEmpty()) {
699             instructions.put(MDSALUtil.buildApplyActionsInstruction(actions, instructionKey++).key(),
700                     MDSALUtil.buildApplyActionsInstruction(actions, instructionKey++));
701         }
702         Uint64 metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, (short) 0, Uint64.ZERO,
703                 isExternal(iface));
704         Uint64 metadataMask = MetaDataUtil
705                 .getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_LPORT_TAG_SH_FLAG);
706         instructions.put(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, instructionKey++).key(),
707                 MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, instructionKey++));
708         instructions.put(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.LPORT_DISPATCHER_TABLE,
709                 instructionKey++).key(),
710                 MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.LPORT_DISPATCHER_TABLE, instructionKey++));
711         int priority = isVlanTransparent ? 1
712                 : vlanId == 0 ? IfmConstants.FLOW_PRIORITY_FOR_UNTAGGED_VLAN : IfmConstants.FLOW_HIGH_PRIORITY;
713         String flowRef = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, iface.getName());
714         List<MatchInfo> matches = getMatchInfoForVlanPortAtIngressTable(dpId, portNo, iface);
715         Flow ingressFlow = MDSALUtil.buildFlowNew(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, flowRef, priority, flowRef,
716                 0, 0, NwConstants.VLAN_TABLE_COOKIE, matches, instructions);
717         LOG.debug("Installing ingress flow {} for {}", flowRef, iface.getName());
718         futures.add(
719             txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> installFlow(dpId, ingressFlow, tx)));
720     }
721
722     public static BoundServicesState buildBoundServicesState(
723         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface
724             interfaceState, Class<? extends ServiceModeBase> serviceMode) {
725         NodeConnectorId nodeConnectorId = IfmUtil.getNodeConnectorIdFromInterface(interfaceState);
726         Uint64 dpId = IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId);
727         long portNo = IfmUtil.getPortNumberFromNodeConnectorId(nodeConnectorId);
728         BoundServicesStateKey boundServicesStateKey = new BoundServicesStateKey(interfaceState.getName(), serviceMode);
729         return new BoundServicesStateBuilder().setDpid(dpId).setIfIndex(interfaceState.getIfIndex())
730             .setInterfaceName(interfaceState.getName()).setInterfaceType(interfaceState.getType()).setPortNo(portNo)
731             .setServiceMode(serviceMode).withKey(boundServicesStateKey).build();
732     }
733
734     public static BoundServicesState getBoundServicesState(ReadTransaction tx,
735                                                            String interfaceName,
736                                                            Class<? extends ServiceModeBase> serviceMode)
737             throws ExecutionException, InterruptedException {
738         InstanceIdentifier<BoundServicesState> id = InstanceIdentifier.builder(BoundServicesStateList.class)
739             .child(BoundServicesState.class, new BoundServicesStateKey(interfaceName, serviceMode)).build();
740         return tx.read(LogicalDatastoreType.OPERATIONAL, id).get().orElse(null);
741     }
742
743     public static BoundServicesState getBoundServicesState(TypedReadTransaction<Operational> tx, String interfaceName,
744         Class<? extends ServiceModeBase> serviceMode) throws ExecutionException, InterruptedException {
745         InstanceIdentifier<BoundServicesState> id = InstanceIdentifier.builder(BoundServicesStateList.class)
746             .child(BoundServicesState.class, new BoundServicesStateKey(interfaceName, serviceMode)).build();
747         return tx.read(id).get().orElse(null);
748     }
749
750     public static void addBoundServicesState(TypedWriteTransaction<Operational> tx, String interfaceName,
751                                              BoundServicesState interfaceBoundServicesState) {
752         LOG.info("adding bound-service state information for interface : {}, service-mode : {}",
753             interfaceBoundServicesState.getInterfaceName(),
754                 interfaceBoundServicesState.getServiceMode().getSimpleName());
755         InstanceIdentifier<BoundServicesState> id = InstanceIdentifier.builder(BoundServicesStateList.class)
756             .child(BoundServicesState.class, new BoundServicesStateKey(interfaceName,
757                 interfaceBoundServicesState.getServiceMode())).build();
758         tx.mergeParentStructurePut(id, interfaceBoundServicesState);
759     }
760
761     public static  void removeBoundServicesState(TypedWriteTransaction<Operational> tx,
762                                                  String interfaceName, Class<? extends ServiceModeBase> serviceMode) {
763         LOG.info("remove bound-service state information for interface : {}, service-mode : {}", interfaceName,
764             serviceMode.getSimpleName());
765         InstanceIdentifier<BoundServicesState> id = InstanceIdentifier.builder(BoundServicesStateList.class)
766             .child(BoundServicesState.class, new BoundServicesStateKey(interfaceName, serviceMode)).build();
767         tx.delete(id);
768     }
769
770     public static boolean isInterfaceTypeBasedServiceBinding(String interfaceName) {
771         return INTERFACE_TYPE_BASED_SERVICE_BINDING_KEYWORDS.contains(interfaceName);
772     }
773
774     private static boolean isExternal(Interface iface) {
775         if (iface == null) {
776             return false;
777         }
778         IfExternal ifExternal = iface.augmentation(IfExternal.class);
779         return ifExternal != null && Boolean.TRUE.equals(ifExternal.isExternal());
780     }
781 }