Remove use of StringBuffer
[netvirt.git] / ipv6service / impl / src / main / java / org / opendaylight / netvirt / ipv6service / utils / Ipv6ServiceUtils.java
1 /*
2  * Copyright © 2016, 2017 Red Hat, Inc. 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
9 package org.opendaylight.netvirt.ipv6service.utils;
10
11 import com.google.common.base.Optional;
12 import java.math.BigInteger;
13 import java.net.InetAddress;
14 import java.net.UnknownHostException;
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.List;
18 import java.util.concurrent.ExecutionException;
19 import javax.inject.Inject;
20 import javax.inject.Singleton;
21 import org.apache.commons.lang3.StringUtils;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.genius.infra.Datastore;
27 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
28 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
29 import org.opendaylight.genius.ipv6util.api.Icmpv6Type;
30 import org.opendaylight.genius.ipv6util.api.Ipv6Constants;
31 import org.opendaylight.genius.ipv6util.api.Ipv6Util;
32 import org.opendaylight.genius.mdsalutil.ActionInfo;
33 import org.opendaylight.genius.mdsalutil.FlowEntity;
34 import org.opendaylight.genius.mdsalutil.InstructionInfo;
35 import org.opendaylight.genius.mdsalutil.MDSALUtil;
36 import org.opendaylight.genius.mdsalutil.MatchInfo;
37 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
38 import org.opendaylight.genius.mdsalutil.NwConstants;
39 import org.opendaylight.genius.mdsalutil.NwConstants.NxmOfFieldType;
40 import org.opendaylight.genius.mdsalutil.actions.ActionLearn;
41 import org.opendaylight.genius.mdsalutil.actions.ActionLearn.FlowMod;
42 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
43 import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
44 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
45 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
46 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
47 import org.opendaylight.genius.mdsalutil.matches.MatchIcmpv6;
48 import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
49 import org.opendaylight.genius.mdsalutil.matches.MatchIpv6NdTarget;
50 import org.opendaylight.genius.mdsalutil.matches.MatchIpv6Source;
51 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
52 import org.opendaylight.genius.mdsalutil.packet.IPProtocols;
53 import org.opendaylight.genius.utils.ServiceIndex;
54 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
55 import org.opendaylight.netvirt.ipv6service.VirtualSubnet;
56 import org.opendaylight.netvirt.ipv6service.api.IVirtualPort;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
60 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
61 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
62 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.config.rev181010.Ipv6serviceConfig;
76 import org.opendaylight.yangtools.yang.binding.DataObject;
77 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
80
81 @Singleton
82 public class Ipv6ServiceUtils {
83     private static final Logger LOG = LoggerFactory.getLogger(Ipv6ServiceUtils.class);
84     public static final Ipv6Address ALL_NODES_MCAST_ADDR = newIpv6Address(Ipv6Constants.ALL_NODES_MCAST_ADDRESS);
85     public static final Ipv6Address UNSPECIFIED_ADDR = newIpv6Address("0:0:0:0:0:0:0:0");
86
87     @Nullable
88     private static Ipv6Address newIpv6Address(String ip) {
89         try {
90             return Ipv6Address.getDefaultInstance(InetAddress.getByName(ip).getHostAddress());
91         } catch (UnknownHostException e) {
92             LOG.error("Ipv6ServiceUtils: Error instantiating ipv6 address", e);
93             return null;
94         }
95     }
96
97     private final DataBroker broker;
98     private final IMdsalApiManager mdsalUtil;
99     private final ManagedNewTransactionRunner txRunner;
100     private final Ipv6serviceConfig ipv6serviceConfig;
101
102     @Inject
103     public Ipv6ServiceUtils(DataBroker broker, IMdsalApiManager mdsalUtil, Ipv6serviceConfig ipv6ServiceConfig) {
104         this.broker = broker;
105         this.mdsalUtil = mdsalUtil;
106         this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
107         this.ipv6serviceConfig = ipv6ServiceConfig;
108     }
109
110     /**
111      * Retrieves the object from the datastore.
112      * @param datastoreType the data store type.
113      * @param path the wild card path.
114      * @return the required object.
115      */
116     public <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
117         try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) {
118             return tx.read(datastoreType, path).get();
119         } catch (InterruptedException | ExecutionException e) {
120             throw new RuntimeException(e);
121         }
122     }
123
124     /**
125      * Retrieves the Interface from the datastore.
126      * @param interfaceName the interface name
127      * @return the interface.
128      */
129     public org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
130         .@Nullable Interface getInterface(String interfaceName) {
131         return read(LogicalDatastoreType.CONFIGURATION, getInterfaceIdentifier(interfaceName)).orNull();
132     }
133
134     /**
135      * Builds the interface identifier.
136      * @param interfaceName the interface name.
137      * @return the interface identifier.
138      */
139     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
140             .interfaces.Interface> getInterfaceIdentifier(String interfaceName) {
141         return InstanceIdentifier.builder(Interfaces.class)
142                 .child(
143                         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
144                                 .Interface.class, new InterfaceKey(interfaceName)).build();
145     }
146
147     /**
148      * Build the interface state.
149      * @param interfaceName the interface name.
150      * @return the interface state.
151      */
152     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
153             .interfaces.state.Interface> buildStateInterfaceId(String interfaceName) {
154         InstanceIdentifier.InstanceIdentifierBuilder<Interface> idBuilder =
155                 InstanceIdentifier.builder(InterfacesState.class)
156                 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
157                         .state.Interface.class,
158                         new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces
159                         .rev140508.interfaces.state.InterfaceKey(interfaceName));
160         return idBuilder.build();
161     }
162
163     /**
164      * Retrieves the interface state.
165      * @param interfaceName the interface name.
166      * @return the interface state.
167      */
168     public org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
169             .@Nullable Interface getInterfaceStateFromOperDS(String interfaceName) {
170         return MDSALUtil.read(LogicalDatastoreType.OPERATIONAL, buildStateInterfaceId(interfaceName), broker).orNull();
171     }
172
173     private static List<MatchInfo> getIcmpv6RSMatch(Long elanTag) {
174         List<MatchInfo> matches = new ArrayList<>();
175         matches.add(MatchEthernetType.IPV6);
176         matches.add(MatchIpProtocol.ICMPV6);
177         matches.add(new MatchIcmpv6(Icmpv6Type.ROUTER_SOLICITATION.getValue(), (short) 0));
178         matches.add(new MatchMetadata(MetaDataUtil.getElanTagMetadata(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
179         return matches;
180     }
181
182     private List<MatchInfo> getIcmpv6NSMatch(Long elanTag, Ipv6Address ipv6Address) {
183         List<MatchInfo> matches = new ArrayList<>();
184         matches.add(MatchEthernetType.IPV6);
185         matches.add(MatchIpProtocol.ICMPV6);
186         matches.add(new MatchIcmpv6(Icmpv6Type.NEIGHBOR_SOLICITATION.getValue(), (short) 0));
187         matches.add(new MatchIpv6NdTarget(ipv6Address));
188         matches.add(new MatchMetadata(MetaDataUtil.getElanTagMetadata(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
189         return matches;
190     }
191
192     private List<MatchInfo> getIcmpv6NAMatch(Long elanTag) {
193         List<MatchInfo> matches = new ArrayList<>();
194         matches.add(MatchEthernetType.IPV6);
195         matches.add(MatchIpProtocol.ICMPV6);
196         matches.add(new MatchIcmpv6(Icmpv6Type.NEIGHBOR_ADVERTISEMENT.getValue(), (short) 0));
197         matches.add(new MatchMetadata(MetaDataUtil.getElanTagMetadata(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
198         return matches;
199     }
200
201     private static String getIPv6FlowRef(BigInteger dpId, Long elanTag, String flowType) {
202         return new StringBuilder().append(Ipv6ServiceConstants.FLOWID_PREFIX)
203                 .append(dpId).append(Ipv6ServiceConstants.FLOWID_SEPARATOR)
204                 .append(elanTag).append(Ipv6ServiceConstants.FLOWID_SEPARATOR)
205                 .append(flowType).toString();
206     }
207
208     public void installIcmpv6NsPuntFlow(short tableId, BigInteger dpId, Long elanTag, Ipv6Address ipv6Address,
209             int addOrRemove) {
210         String flowId = getIPv6FlowRef(dpId, elanTag, Ipv6Util.getFormattedIpv6Address(ipv6Address));
211
212         if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
213             LOG.trace("Removing IPv6 Neighbor Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
214             LoggingFutures
215                     .addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
216                         mdsalUtil.removeFlow(tx, dpId, flowId, tableId);
217                     }), LOG, "Error while removing flow={}", flowId);
218         } else {
219             List<ActionInfo> actionsInfos = new ArrayList<>();
220             actionsInfos.add(new ActionPuntToController());
221
222             int ndPuntTimeout = ipv6serviceConfig.getNeighborDiscoveryPuntTimeout();
223             if (isNdPuntProtectionEnabled(ndPuntTimeout)) {
224                 actionsInfos.add(getLearnActionForNsPuntProtection(ndPuntTimeout));
225             }
226             List<InstructionInfo> instructions = Arrays.asList(new InstructionApplyActions(actionsInfos));
227             List<MatchInfo> nsMatch = getIcmpv6NSMatch(elanTag, ipv6Address);
228             FlowEntity nsFlowEntity =
229                     MDSALUtil.buildFlowEntity(dpId, tableId, flowId, Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY,
230                             "IPv6NS", 0, 0, NwConstants.COOKIE_IPV6_TABLE, nsMatch, instructions);
231
232             LOG.trace("Installing IPv6 Neighbor Solicitation Flow DpId={}, elanTag={} ipv6Address={}", dpId, elanTag,
233                     ipv6Address.getValue());
234             LoggingFutures
235                     .addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
236                         mdsalUtil.addFlow(tx, nsFlowEntity);
237                     }), LOG, "Error while adding flow={}", nsFlowEntity);
238         }
239     }
240
241     private ActionLearn getLearnActionForNsPuntProtection(int ndPuntTimeout) {
242         List<FlowMod> flowMods = getFlowModsForIpv6PuntProtection(Icmpv6Type.NEIGHBOR_SOLICITATION);
243         flowMods.add(new ActionLearn.MatchFromField(NxmOfFieldType.NXM_NX_ND_TARGET.getType(),
244                 NxmOfFieldType.NXM_NX_ND_TARGET.getType(), NxmOfFieldType.NXM_NX_ND_TARGET.getFlowModHeaderLenInt()));
245
246         return new ActionLearn(0, ndPuntTimeout, Ipv6ServiceConstants.NS_PUNT_PROTECTION_FLOW_PRIORITY,
247                 NwConstants.COOKIE_IPV6_TABLE, 0, NwConstants.IPV6_TABLE, 0, 0, flowMods);
248     }
249
250     public void installIcmpv6RsPuntFlow(short tableId, BigInteger dpId, Long elanTag, int addOrRemove) {
251         if (dpId == null || dpId.equals(Ipv6ServiceConstants.INVALID_DPID)) {
252             return;
253         }
254         String flowId = getIPv6FlowRef(dpId, elanTag, "IPv6RS");
255         if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
256             LOG.trace("Removing IPv6 Router Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
257             LoggingFutures
258                     .addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
259                         mdsalUtil.removeFlow(tx, dpId, flowId, tableId);
260                     }), LOG, "Error while removing flow={}", flowId);
261         } else {
262             List<ActionInfo> actionsInfos = new ArrayList<>();
263             // Punt to controller
264             actionsInfos.add(new ActionPuntToController());
265
266             int rdPuntTimeout = ipv6serviceConfig.getRouterDiscoveryPuntTimeout();
267             if (isRdPuntProtectionEnabled(rdPuntTimeout)) {
268                 actionsInfos.add(getLearnActionForRsPuntProtection(rdPuntTimeout));
269             }
270             List<InstructionInfo> instructions = Arrays.asList(new InstructionApplyActions(actionsInfos));
271             List<MatchInfo> routerSolicitationMatch = getIcmpv6RSMatch(elanTag);
272             FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
273                     flowId,Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY, "IPv6RS", 0, 0,
274                     NwConstants.COOKIE_IPV6_TABLE, routerSolicitationMatch, instructions);
275
276             LOG.trace("Installing IPv6 Router Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
277             LoggingFutures
278                     .addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
279                         mdsalUtil.addFlow(tx, rsFlowEntity);
280                     }), LOG, "Error while adding flow={}", rsFlowEntity);
281         }
282     }
283
284     private ActionLearn getLearnActionForRsPuntProtection(int rdPuntTimeout) {
285         return new ActionLearn(0, rdPuntTimeout, Ipv6ServiceConstants.RS_PUNT_PROTECTION_FLOW_PRIORITY,
286                 NwConstants.COOKIE_IPV6_TABLE, 0, NwConstants.IPV6_TABLE, 0, 0,
287                 getFlowModsForIpv6PuntProtection(Icmpv6Type.ROUTER_SOLICITATION));
288     }
289
290     private List<FlowMod> getFlowModsForIpv6PuntProtection(Icmpv6Type icmpv6Type) {
291         return new ArrayList<>(Arrays.asList(
292                 new ActionLearn.MatchFromValue(NwConstants.ETHTYPE_IPV6, NxmOfFieldType.NXM_OF_ETH_TYPE.getType(),
293                         NxmOfFieldType.NXM_OF_ETH_TYPE.getFlowModHeaderLenInt()),
294                 new ActionLearn.MatchFromValue(IPProtocols.IPV6ICMP.shortValue(),
295                         NxmOfFieldType.NXM_OF_IP_PROTO.getType(),
296                         NxmOfFieldType.NXM_OF_IP_PROTO.getFlowModHeaderLenInt()),
297                 new ActionLearn.MatchFromValue(icmpv6Type.getValue(), NxmOfFieldType.NXM_OF_ICMPv6_TYPE.getType(),
298                         NxmOfFieldType.NXM_OF_ICMPv6_TYPE.getFlowModHeaderLenInt()),
299                 new ActionLearn.MatchFromField(NxmOfFieldType.NXM_OF_ICMPv6_CODE.getType(),
300                         NxmOfFieldType.NXM_OF_ICMPv6_CODE.getType(),
301                         NxmOfFieldType.NXM_OF_ICMPv6_CODE.getFlowModHeaderLenInt()),
302                 new ActionLearn.MatchFromField(NxmOfFieldType.OXM_OF_METADATA.getType(),
303                         MetaDataUtil.METADATA_LPORT_TAG_OFFSET, NxmOfFieldType.OXM_OF_METADATA.getType(),
304                         MetaDataUtil.METADATA_LPORT_TAG_OFFSET, MetaDataUtil.METADATA_LPORT_TAG_BITLEN)));
305     }
306
307     private boolean isRdPuntProtectionEnabled(int rdPuntTimeout) {
308         return rdPuntTimeout != 0;
309     }
310
311     private boolean isNdPuntProtectionEnabled(int ndPuntTimeout) {
312         return ndPuntTimeout != 0;
313     }
314
315     public void installIcmpv6NaForwardFlow(short tableId, IVirtualPort vmPort, BigInteger dpId, Long elanTag,
316             int addOrRemove) {
317         List<MatchInfo> matches = getIcmpv6NAMatch(elanTag);
318         List<InstructionInfo> instructions = new ArrayList<>();
319         List<ActionInfo> actionsInfos = new ArrayList<>();
320         actionsInfos.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
321         instructions.add(new InstructionApplyActions(actionsInfos));
322
323         for (Ipv6Address ipv6Address : vmPort.getIpv6Addresses()) {
324             matches.add(new MatchIpv6Source(ipv6Address.getValue() + NwConstants.IPV6PREFIX));
325             String flowId = getIPv6FlowRef(dpId, elanTag,
326                     vmPort.getIntfUUID().getValue() + Ipv6ServiceConstants.FLOWID_SEPARATOR + ipv6Address.getValue());
327             FlowEntity rsFlowEntity =
328                     MDSALUtil.buildFlowEntity(dpId, tableId, flowId, Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY,
329                             "IPv6NA", 0, 0, NwConstants.COOKIE_IPV6_TABLE, matches, instructions);
330             if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
331                 LOG.trace("Removing IPv6 Neighbor Advertisement Flow DpId {}, elanTag {}, ipv6Address {}", dpId,
332                         elanTag, ipv6Address.getValue());
333                 mdsalUtil.removeFlow(rsFlowEntity);
334             } else {
335                 LOG.trace("Installing IPv6 Neighbor Advertisement Flow DpId {}, elanTag {}, ipv6Address {}", dpId,
336                         elanTag, ipv6Address.getValue());
337                 mdsalUtil.installFlow(rsFlowEntity);
338             }
339         }
340     }
341
342     public void installIcmpv6NaPuntFlow(short tableId, Ipv6Prefix ipv6Prefix, BigInteger dpId, Long elanTag,
343             int addOrRemove) {
344         List<MatchInfo> naMatch = getIcmpv6NAMatch(elanTag);
345         naMatch.add(new MatchIpv6Source(ipv6Prefix));
346
347         List<InstructionInfo> instructions = new ArrayList<>();
348         List<ActionInfo> actionsInfos = new ArrayList<>();
349         actionsInfos.add(new ActionPuntToController());
350         actionsInfos.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
351         instructions.add(new InstructionApplyActions(actionsInfos));
352
353         String flowId = getIPv6FlowRef(dpId, elanTag, "IPv6NA." + ipv6Prefix.getValue());
354         FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
355                 flowId, Ipv6ServiceConstants.PUNT_NA_FLOW_PRIORITY,
356                 "IPv6NA", 0, 0, NwConstants.COOKIE_IPV6_TABLE, naMatch, instructions);
357         if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
358             LOG.trace("Removing IPv6 Neighbor Advertisement Flow DpId {}, elanTag {}", dpId, elanTag);
359             mdsalUtil.removeFlow(rsFlowEntity);
360         } else {
361             LOG.trace("Installing IPv6 Neighbor Advertisement Flow DpId {}, elanTag {}", dpId, elanTag);
362             mdsalUtil.installFlow(rsFlowEntity);
363         }
364     }
365
366     public BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
367                                           BigInteger cookie, List<Instruction> instructions) {
368         StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie)
369                 .setFlowPriority(flowPriority).setInstruction(instructions);
370         return new BoundServicesBuilder().withKey(new BoundServicesKey(servicePriority))
371                 .setServiceName(serviceName).setServicePriority(servicePriority)
372                 .setServiceType(ServiceTypeFlowBased.class)
373                 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
374     }
375
376     private InstanceIdentifier<BoundServices> buildServiceId(String interfaceName,
377                                               short priority) {
378         return InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class,
379                 new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
380                 .child(BoundServices.class, new BoundServicesKey(priority)).build();
381     }
382
383     public void bindIpv6Service(String interfaceName, Long elanTag, short tableId) {
384         int instructionKey = 0;
385         List<Instruction> instructions = new ArrayList<>();
386         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(MetaDataUtil.getElanTagMetadata(elanTag),
387                 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
388         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(tableId, ++instructionKey));
389         short serviceIndex = ServiceIndex.getIndex(NwConstants.IPV6_SERVICE_NAME, NwConstants.IPV6_SERVICE_INDEX);
390         BoundServices
391                 serviceInfo =
392                 getBoundServices(String.format("%s.%s", "ipv6", interfaceName),
393                         serviceIndex, Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY,
394                         NwConstants.COOKIE_IPV6_TABLE, instructions);
395         MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
396                 buildServiceId(interfaceName, serviceIndex), serviceInfo);
397     }
398
399     public void unbindIpv6Service(String interfaceName) {
400         MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION,
401                 buildServiceId(interfaceName, ServiceIndex.getIndex(NwConstants.IPV6_SERVICE_NAME,
402                         NwConstants.IPV6_SERVICE_INDEX)));
403     }
404
405     @Nullable
406     public BigInteger getDpIdFromInterfaceState(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
407             .interfaces.rev140508.interfaces.state.Interface interfaceState) {
408         BigInteger dpId = null;
409         List<String> ofportIds = interfaceState.getLowerLayerIf();
410         if (ofportIds != null && !ofportIds.isEmpty()) {
411             NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
412             dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
413         }
414         return dpId;
415     }
416
417     public static long getRemoteBCGroup(long elanTag) {
418         return Ipv6ServiceConstants.ELAN_GID_MIN + elanTag % Ipv6ServiceConstants.ELAN_GID_MIN * 2;
419     }
420
421     public static boolean isVmPort(String deviceOwner) {
422         // FIXME: Currently for VM ports, Neutron is sending deviceOwner as empty instead of "compute:nova".
423         // return Ipv6ServiceConstants.DEVICE_OWNER_COMPUTE_NOVA.equalsIgnoreCase(deviceOwner);
424         return Ipv6ServiceConstants.DEVICE_OWNER_COMPUTE_NOVA.equalsIgnoreCase(deviceOwner)
425                 || StringUtils.isEmpty(deviceOwner);
426     }
427
428     public static boolean isIpv6Subnet(VirtualSubnet subnet) {
429         if (subnet == null) {
430             return false;
431         }
432         return subnet.getIpVersion().equals(Ipv6ServiceConstants.IP_VERSION_V6) ? true : false;
433     }
434 }