504fb74d83c078802992f7d933f214ac69f1e760
[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.annotation.Nullable;
20 import javax.inject.Inject;
21 import javax.inject.Singleton;
22 import org.apache.commons.lang3.StringUtils;
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     @Nullable
130     public org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
131         .Interface getInterface(String interfaceName) {
132         return read(LogicalDatastoreType.CONFIGURATION, getInterfaceIdentifier(interfaceName)).orNull();
133     }
134
135     /**
136      * Builds the interface identifier.
137      * @param interfaceName the interface name.
138      * @return the interface identifier.
139      */
140     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
141             .interfaces.Interface> getInterfaceIdentifier(String interfaceName) {
142         return InstanceIdentifier.builder(Interfaces.class)
143                 .child(
144                         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
145                                 .Interface.class, new InterfaceKey(interfaceName)).build();
146     }
147
148     /**
149      * Build the interface state.
150      * @param interfaceName the interface name.
151      * @return the interface state.
152      */
153     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
154             .interfaces.state.Interface> buildStateInterfaceId(String interfaceName) {
155         InstanceIdentifier.InstanceIdentifierBuilder<Interface> idBuilder =
156                 InstanceIdentifier.builder(InterfacesState.class)
157                 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
158                         .state.Interface.class,
159                         new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces
160                         .rev140508.interfaces.state.InterfaceKey(interfaceName));
161         return idBuilder.build();
162     }
163
164     /**
165      * Retrieves the interface state.
166      * @param interfaceName the interface name.
167      * @return the interface state.
168      */
169     @Nullable
170     public org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
171             .Interface getInterfaceStateFromOperDS(String interfaceName) {
172         return MDSALUtil.read(LogicalDatastoreType.OPERATIONAL, buildStateInterfaceId(interfaceName), broker).orNull();
173     }
174
175     private static List<MatchInfo> getIcmpv6RSMatch(Long elanTag) {
176         List<MatchInfo> matches = new ArrayList<>();
177         matches.add(MatchEthernetType.IPV6);
178         matches.add(MatchIpProtocol.ICMPV6);
179         matches.add(new MatchIcmpv6(Icmpv6Type.ROUTER_SOLICITATION.getValue(), (short) 0));
180         matches.add(new MatchMetadata(MetaDataUtil.getElanTagMetadata(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
181         return matches;
182     }
183
184     private List<MatchInfo> getIcmpv6NSMatch(Long elanTag, Ipv6Address ipv6Address) {
185         List<MatchInfo> matches = new ArrayList<>();
186         matches.add(MatchEthernetType.IPV6);
187         matches.add(MatchIpProtocol.ICMPV6);
188         matches.add(new MatchIcmpv6(Icmpv6Type.NEIGHBOR_SOLICITATION.getValue(), (short) 0));
189         matches.add(new MatchIpv6NdTarget(ipv6Address));
190         matches.add(new MatchMetadata(MetaDataUtil.getElanTagMetadata(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
191         return matches;
192     }
193
194     private List<MatchInfo> getIcmpv6NAMatch(Long elanTag) {
195         List<MatchInfo> matches = new ArrayList<>();
196         matches.add(MatchEthernetType.IPV6);
197         matches.add(MatchIpProtocol.ICMPV6);
198         matches.add(new MatchIcmpv6(Icmpv6Type.NEIGHBOR_ADVERTISEMENT.getValue(), (short) 0));
199         matches.add(new MatchMetadata(MetaDataUtil.getElanTagMetadata(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
200         return matches;
201     }
202
203     private static String getIPv6FlowRef(BigInteger dpId, Long elanTag, String flowType) {
204         return new StringBuffer().append(Ipv6ServiceConstants.FLOWID_PREFIX)
205                 .append(dpId).append(Ipv6ServiceConstants.FLOWID_SEPARATOR)
206                 .append(elanTag).append(Ipv6ServiceConstants.FLOWID_SEPARATOR)
207                 .append(flowType).toString();
208     }
209
210     public void installIcmpv6NsPuntFlow(short tableId, BigInteger dpId, Long elanTag, Ipv6Address ipv6Address,
211             int addOrRemove) {
212         String flowId = getIPv6FlowRef(dpId, elanTag, Ipv6Util.getFormattedIpv6Address(ipv6Address));
213
214         if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
215             LOG.trace("Removing IPv6 Neighbor Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
216             LoggingFutures
217                     .addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
218                         mdsalUtil.removeFlow(tx, dpId, flowId, tableId);
219                     }), LOG, "Error while removing flow={}", flowId);
220         } else {
221             List<ActionInfo> actionsInfos = new ArrayList<>();
222             actionsInfos.add(new ActionPuntToController());
223
224             int ndPuntTimeout = ipv6serviceConfig.getNeighborDiscoveryPuntTimeout();
225             if (isNdPuntProtectionEnabled(ndPuntTimeout)) {
226                 actionsInfos.add(getLearnActionForNsPuntProtection(ndPuntTimeout));
227             }
228             List<InstructionInfo> instructions = Arrays.asList(new InstructionApplyActions(actionsInfos));
229             List<MatchInfo> nsMatch = getIcmpv6NSMatch(elanTag, ipv6Address);
230             FlowEntity nsFlowEntity =
231                     MDSALUtil.buildFlowEntity(dpId, tableId, flowId, Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY,
232                             "IPv6NS", 0, 0, NwConstants.COOKIE_IPV6_TABLE, nsMatch, instructions);
233
234             LOG.trace("Installing IPv6 Neighbor Solicitation Flow DpId={}, elanTag={} ipv6Address={}", dpId, elanTag,
235                     ipv6Address.getValue());
236             LoggingFutures
237                     .addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
238                         mdsalUtil.addFlow(tx, nsFlowEntity);
239                     }), LOG, "Error while adding flow={}", nsFlowEntity);
240         }
241     }
242
243     private ActionLearn getLearnActionForNsPuntProtection(int ndPuntTimeout) {
244         List<FlowMod> flowMods = getFlowModsForIpv6PuntProtection(Icmpv6Type.NEIGHBOR_SOLICITATION);
245         flowMods.add(new ActionLearn.MatchFromField(NxmOfFieldType.NXM_NX_ND_TARGET.getType(),
246                 NxmOfFieldType.NXM_NX_ND_TARGET.getType(), NxmOfFieldType.NXM_NX_ND_TARGET.getFlowModHeaderLenInt()));
247
248         return new ActionLearn(0, ndPuntTimeout, Ipv6ServiceConstants.NS_PUNT_PROTECTION_FLOW_PRIORITY,
249                 NwConstants.COOKIE_IPV6_TABLE, 0, NwConstants.IPV6_TABLE, 0, 0, flowMods);
250     }
251
252     public void installIcmpv6RsPuntFlow(short tableId, BigInteger dpId, Long elanTag, int addOrRemove) {
253         if (dpId == null || dpId.equals(Ipv6ServiceConstants.INVALID_DPID)) {
254             return;
255         }
256         String flowId = getIPv6FlowRef(dpId, elanTag, "IPv6RS");
257         if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
258             LOG.trace("Removing IPv6 Router Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
259             LoggingFutures
260                     .addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
261                         mdsalUtil.removeFlow(tx, dpId, flowId, tableId);
262                     }), LOG, "Error while removing flow={}", flowId);
263         } else {
264             List<ActionInfo> actionsInfos = new ArrayList<>();
265             // Punt to controller
266             actionsInfos.add(new ActionPuntToController());
267
268             int rdPuntTimeout = ipv6serviceConfig.getRouterDiscoveryPuntTimeout();
269             if (isRdPuntProtectionEnabled(rdPuntTimeout)) {
270                 actionsInfos.add(getLearnActionForRsPuntProtection(rdPuntTimeout));
271             }
272             List<InstructionInfo> instructions = Arrays.asList(new InstructionApplyActions(actionsInfos));
273             List<MatchInfo> routerSolicitationMatch = getIcmpv6RSMatch(elanTag);
274             FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
275                     flowId,Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY, "IPv6RS", 0, 0,
276                     NwConstants.COOKIE_IPV6_TABLE, routerSolicitationMatch, instructions);
277
278             LOG.trace("Installing IPv6 Router Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
279             LoggingFutures
280                     .addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
281                         mdsalUtil.addFlow(tx, rsFlowEntity);
282                     }), LOG, "Error while adding flow={}", rsFlowEntity);
283         }
284     }
285
286     private ActionLearn getLearnActionForRsPuntProtection(int rdPuntTimeout) {
287         return new ActionLearn(0, rdPuntTimeout, Ipv6ServiceConstants.RS_PUNT_PROTECTION_FLOW_PRIORITY,
288                 NwConstants.COOKIE_IPV6_TABLE, 0, NwConstants.IPV6_TABLE, 0, 0,
289                 getFlowModsForIpv6PuntProtection(Icmpv6Type.ROUTER_SOLICITATION));
290     }
291
292     private List<FlowMod> getFlowModsForIpv6PuntProtection(Icmpv6Type icmpv6Type) {
293         return new ArrayList<>(Arrays.asList(
294                 new ActionLearn.MatchFromValue(NwConstants.ETHTYPE_IPV6, NxmOfFieldType.NXM_OF_ETH_TYPE.getType(),
295                         NxmOfFieldType.NXM_OF_ETH_TYPE.getFlowModHeaderLenInt()),
296                 new ActionLearn.MatchFromValue(IPProtocols.IPV6ICMP.shortValue(),
297                         NxmOfFieldType.NXM_OF_IP_PROTO.getType(),
298                         NxmOfFieldType.NXM_OF_IP_PROTO.getFlowModHeaderLenInt()),
299                 new ActionLearn.MatchFromValue(icmpv6Type.getValue(), NxmOfFieldType.NXM_OF_ICMPv6_TYPE.getType(),
300                         NxmOfFieldType.NXM_OF_ICMPv6_TYPE.getFlowModHeaderLenInt()),
301                 new ActionLearn.MatchFromField(NxmOfFieldType.NXM_OF_ICMPv6_CODE.getType(),
302                         NxmOfFieldType.NXM_OF_ICMPv6_CODE.getType(),
303                         NxmOfFieldType.NXM_OF_ICMPv6_CODE.getFlowModHeaderLenInt()),
304                 new ActionLearn.MatchFromField(NxmOfFieldType.OXM_OF_METADATA.getType(),
305                         MetaDataUtil.METADATA_LPORT_TAG_OFFSET, NxmOfFieldType.OXM_OF_METADATA.getType(),
306                         MetaDataUtil.METADATA_LPORT_TAG_OFFSET, MetaDataUtil.METADATA_LPORT_TAG_BITLEN)));
307     }
308
309     private boolean isRdPuntProtectionEnabled(int rdPuntTimeout) {
310         return rdPuntTimeout != 0;
311     }
312
313     private boolean isNdPuntProtectionEnabled(int ndPuntTimeout) {
314         return ndPuntTimeout != 0;
315     }
316
317     public void installIcmpv6NaForwardFlow(short tableId, IVirtualPort vmPort, BigInteger dpId, Long elanTag,
318             int addOrRemove) {
319         List<MatchInfo> matches = getIcmpv6NAMatch(elanTag);
320         List<InstructionInfo> instructions = new ArrayList<>();
321         List<ActionInfo> actionsInfos = new ArrayList<>();
322         actionsInfos.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
323         instructions.add(new InstructionApplyActions(actionsInfos));
324
325         for (Ipv6Address ipv6Address : vmPort.getIpv6Addresses()) {
326             matches.add(new MatchIpv6Source(ipv6Address.getValue() + NwConstants.IPV6PREFIX));
327             String flowId = getIPv6FlowRef(dpId, elanTag,
328                     vmPort.getIntfUUID().getValue() + Ipv6ServiceConstants.FLOWID_SEPARATOR + ipv6Address.getValue());
329             FlowEntity rsFlowEntity =
330                     MDSALUtil.buildFlowEntity(dpId, tableId, flowId, Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY,
331                             "IPv6NA", 0, 0, NwConstants.COOKIE_IPV6_TABLE, matches, instructions);
332             if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
333                 LOG.trace("Removing IPv6 Neighbor Advertisement Flow DpId {}, elanTag {}, ipv6Address {}", dpId,
334                         elanTag, ipv6Address.getValue());
335                 mdsalUtil.removeFlow(rsFlowEntity);
336             } else {
337                 LOG.trace("Installing IPv6 Neighbor Advertisement Flow DpId {}, elanTag {}, ipv6Address {}", dpId,
338                         elanTag, ipv6Address.getValue());
339                 mdsalUtil.installFlow(rsFlowEntity);
340             }
341         }
342     }
343
344     public void installIcmpv6NaPuntFlow(short tableId, Ipv6Prefix ipv6Prefix, BigInteger dpId, Long elanTag,
345             int addOrRemove) {
346         List<MatchInfo> naMatch = getIcmpv6NAMatch(elanTag);
347         naMatch.add(new MatchIpv6Source(ipv6Prefix));
348
349         List<InstructionInfo> instructions = new ArrayList<>();
350         List<ActionInfo> actionsInfos = new ArrayList<>();
351         actionsInfos.add(new ActionPuntToController());
352         actionsInfos.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
353         instructions.add(new InstructionApplyActions(actionsInfos));
354
355         String flowId = getIPv6FlowRef(dpId, elanTag, "IPv6NA." + ipv6Prefix.getValue());
356         FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
357                 flowId, Ipv6ServiceConstants.PUNT_NA_FLOW_PRIORITY,
358                 "IPv6NA", 0, 0, NwConstants.COOKIE_IPV6_TABLE, naMatch, instructions);
359         if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
360             LOG.trace("Removing IPv6 Neighbor Advertisement Flow DpId {}, elanTag {}", dpId, elanTag);
361             mdsalUtil.removeFlow(rsFlowEntity);
362         } else {
363             LOG.trace("Installing IPv6 Neighbor Advertisement Flow DpId {}, elanTag {}", dpId, elanTag);
364             mdsalUtil.installFlow(rsFlowEntity);
365         }
366     }
367
368     public BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
369                                           BigInteger cookie, List<Instruction> instructions) {
370         StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie)
371                 .setFlowPriority(flowPriority).setInstruction(instructions);
372         return new BoundServicesBuilder().withKey(new BoundServicesKey(servicePriority))
373                 .setServiceName(serviceName).setServicePriority(servicePriority)
374                 .setServiceType(ServiceTypeFlowBased.class)
375                 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
376     }
377
378     private InstanceIdentifier<BoundServices> buildServiceId(String interfaceName,
379                                               short priority) {
380         return InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class,
381                 new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
382                 .child(BoundServices.class, new BoundServicesKey(priority)).build();
383     }
384
385     public void bindIpv6Service(String interfaceName, Long elanTag, short tableId) {
386         int instructionKey = 0;
387         List<Instruction> instructions = new ArrayList<>();
388         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(MetaDataUtil.getElanTagMetadata(elanTag),
389                 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
390         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(tableId, ++instructionKey));
391         short serviceIndex = ServiceIndex.getIndex(NwConstants.IPV6_SERVICE_NAME, NwConstants.IPV6_SERVICE_INDEX);
392         BoundServices
393                 serviceInfo =
394                 getBoundServices(String.format("%s.%s", "ipv6", interfaceName),
395                         serviceIndex, Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY,
396                         NwConstants.COOKIE_IPV6_TABLE, instructions);
397         MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
398                 buildServiceId(interfaceName, serviceIndex), serviceInfo);
399     }
400
401     public void unbindIpv6Service(String interfaceName) {
402         MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION,
403                 buildServiceId(interfaceName, ServiceIndex.getIndex(NwConstants.IPV6_SERVICE_NAME,
404                         NwConstants.IPV6_SERVICE_INDEX)));
405     }
406
407     @Nullable
408     public BigInteger getDpIdFromInterfaceState(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
409             .interfaces.rev140508.interfaces.state.Interface interfaceState) {
410         BigInteger dpId = null;
411         List<String> ofportIds = interfaceState.getLowerLayerIf();
412         if (ofportIds != null && !ofportIds.isEmpty()) {
413             NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
414             dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
415         }
416         return dpId;
417     }
418
419     public static long getRemoteBCGroup(long elanTag) {
420         return Ipv6ServiceConstants.ELAN_GID_MIN + elanTag % Ipv6ServiceConstants.ELAN_GID_MIN * 2;
421     }
422
423     public static boolean isVmPort(String deviceOwner) {
424         // FIXME: Currently for VM ports, Neutron is sending deviceOwner as empty instead of "compute:nova".
425         // return Ipv6ServiceConstants.DEVICE_OWNER_COMPUTE_NOVA.equalsIgnoreCase(deviceOwner);
426         return Ipv6ServiceConstants.DEVICE_OWNER_COMPUTE_NOVA.equalsIgnoreCase(deviceOwner)
427                 || StringUtils.isEmpty(deviceOwner);
428     }
429
430     public static boolean isIpv6Subnet(VirtualSubnet subnet) {
431         if (subnet == null) {
432             return false;
433         }
434         return subnet.getIpVersion().equals(Ipv6ServiceConstants.IP_VERSION_V6) ? true : false;
435     }
436 }