fdcdf151eb49439cf884ad2bbe1ab18a5aa815af
[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 com.google.common.net.InetAddresses;
13 import java.math.BigInteger;
14 import java.net.InetAddress;
15 import java.net.UnknownHostException;
16 import java.nio.ByteBuffer;
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 import java.util.List;
20 import java.util.concurrent.ExecutionException;
21 import javax.inject.Inject;
22 import javax.inject.Singleton;
23 import org.apache.commons.lang3.StringUtils;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.genius.mdsalutil.ActionInfo;
28 import org.opendaylight.genius.mdsalutil.FlowEntity;
29 import org.opendaylight.genius.mdsalutil.InstructionInfo;
30 import org.opendaylight.genius.mdsalutil.MDSALUtil;
31 import org.opendaylight.genius.mdsalutil.MatchInfo;
32 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
33 import org.opendaylight.genius.mdsalutil.NwConstants;
34 import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
35 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
36 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
37 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
38 import org.opendaylight.genius.mdsalutil.matches.MatchIcmpv6;
39 import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
40 import org.opendaylight.genius.mdsalutil.matches.MatchIpv6NdTarget;
41 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
42 import org.opendaylight.genius.utils.ServiceIndex;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.EthernetHeader;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.Ipv6Header;
62 import org.opendaylight.yangtools.yang.binding.DataObject;
63 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66
67 @Singleton
68 public class Ipv6ServiceUtils {
69     private static final Logger LOG = LoggerFactory.getLogger(Ipv6ServiceUtils.class);
70     public static final Ipv6Address ALL_NODES_MCAST_ADDR = newIpv6Address("FF02::1");
71     public static final Ipv6Address UNSPECIFIED_ADDR = newIpv6Address("0:0:0:0:0:0:0:0");
72
73     private static Ipv6Address newIpv6Address(String ip) {
74         try {
75             return Ipv6Address.getDefaultInstance(InetAddress.getByName(ip).getHostAddress());
76         } catch (UnknownHostException e) {
77             LOG.error("Ipv6ServiceUtils: Error instantiating ipv6 address", e);
78             return null;
79         }
80     }
81
82     private final DataBroker broker;
83     private final IMdsalApiManager mdsalUtil;
84
85     @Inject
86     public Ipv6ServiceUtils(DataBroker broker, IMdsalApiManager mdsalUtil) {
87         this.broker = broker;
88         this.mdsalUtil = mdsalUtil;
89     }
90
91     /**
92      * Retrieves the object from the datastore.
93      * @param datastoreType the data store type.
94      * @param path the wild card path.
95      * @return the required object.
96      */
97     public <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
98         try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) {
99             return tx.read(datastoreType, path).get();
100         } catch (InterruptedException | ExecutionException e) {
101             throw new RuntimeException(e);
102         }
103     }
104
105     /**
106      * Retrieves the Interface from the datastore.
107      * @param interfaceName the interface name
108      * @return the interface.
109      */
110     public org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
111         .Interface getInterface(String interfaceName) {
112         Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
113             .Interface> optInterface =
114                 read(LogicalDatastoreType.CONFIGURATION, getInterfaceIdentifier(interfaceName));
115         if (optInterface.isPresent()) {
116             return optInterface.get();
117         }
118         return null;
119     }
120
121     /**
122      * Builds the interface identifier.
123      * @param interfaceName the interface name.
124      * @return the interface identifier.
125      */
126     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
127             .interfaces.Interface> getInterfaceIdentifier(String interfaceName) {
128         return InstanceIdentifier.builder(Interfaces.class)
129                 .child(
130                         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
131                                 .Interface.class, new InterfaceKey(interfaceName)).build();
132     }
133
134     /**
135      * Build the interface state.
136      * @param interfaceName the interface name.
137      * @return the interface state.
138      */
139     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
140             .interfaces.state.Interface> buildStateInterfaceId(String interfaceName) {
141         InstanceIdentifier.InstanceIdentifierBuilder<Interface> idBuilder =
142                 InstanceIdentifier.builder(InterfacesState.class)
143                 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
144                         .state.Interface.class,
145                         new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces
146                         .rev140508.interfaces.state.InterfaceKey(interfaceName));
147         return idBuilder.build();
148     }
149
150     /**
151      * Retrieves the interface state.
152      * @param interfaceName the interface name.
153      * @return the interface state.
154      */
155     public org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
156             .Interface getInterfaceStateFromOperDS(String interfaceName) {
157         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
158                 .interfaces.state.Interface> ifStateId = buildStateInterfaceId(interfaceName);
159         return MDSALUtil.read(LogicalDatastoreType.OPERATIONAL, ifStateId, broker).orNull();
160     }
161
162     public static String bytesToHexString(byte[] bytes) {
163         if (bytes == null) {
164             return "null";
165         }
166         StringBuilder buf = new StringBuilder();
167         for (int i = 0; i < bytes.length; i++) {
168             if (i > 0) {
169                 buf.append(":");
170             }
171             short u8byte = (short) (bytes[i] & 0xff);
172             String tmp = Integer.toHexString(u8byte);
173             if (tmp.length() == 1) {
174                 buf.append("0");
175             }
176             buf.append(tmp);
177         }
178         return buf.toString();
179     }
180
181     public static byte[] bytesFromHexString(String values) {
182         String target = "";
183         if (values != null) {
184             target = values;
185         }
186         String[] octets = target.split(":");
187
188         byte[] ret = new byte[octets.length];
189         for (int i = 0; i < octets.length; i++) {
190             ret[i] = Integer.valueOf(octets[i], 16).byteValue();
191         }
192         return ret;
193     }
194
195     public static int calcIcmpv6Checksum(byte[] packet, Ipv6Header ip6Hdr) {
196         long checksum = getSummation(ip6Hdr.getSourceIpv6());
197         checksum += getSummation(ip6Hdr.getDestinationIpv6());
198         checksum = normalizeChecksum(checksum);
199
200         checksum += ip6Hdr.getIpv6Length();
201         checksum += ip6Hdr.getNextHeader();
202
203         int icmp6Offset = Ipv6Constants.ICMPV6_OFFSET;
204         long value = (packet[icmp6Offset] & 0xff) << 8 | packet[icmp6Offset + 1] & 0xff;
205         checksum += value;
206         checksum = normalizeChecksum(checksum);
207         icmp6Offset += 2;
208
209         //move to icmp6 payload skipping the checksum field
210         icmp6Offset += 2;
211         int length = packet.length - icmp6Offset;
212         while (length > 1) {
213             value = (packet[icmp6Offset] & 0xff) << 8 | packet[icmp6Offset + 1] & 0xff;
214             checksum += value;
215             checksum = normalizeChecksum(checksum);
216             icmp6Offset += 2;
217             length -= 2;
218         }
219
220         if (length > 0) {
221             checksum += packet[icmp6Offset];
222             checksum = normalizeChecksum(checksum);
223         }
224
225         int finalChecksum = (int)(~checksum & 0xffff);
226         return finalChecksum;
227     }
228
229     public static boolean validateChecksum(byte[] packet, Ipv6Header ip6Hdr, int recvChecksum) {
230         return calcIcmpv6Checksum(packet, ip6Hdr) == recvChecksum;
231     }
232
233     private static long getSummation(Ipv6Address addr) {
234         byte[] baddr = null;
235         try {
236             baddr = InetAddress.getByName(addr.getValue()).getAddress();
237         } catch (UnknownHostException e) {
238             LOG.error("getSummation: Failed to deserialize address {}", addr.getValue(), e);
239             return 0;
240         }
241
242         long sum = 0;
243         int len = 0;
244         long value = 0;
245         while (len < baddr.length) {
246             value = (baddr[len] & 0xff) << 8 | baddr[len + 1] & 0xff;
247             sum += value;
248             sum = normalizeChecksum(sum);
249             len += 2;
250         }
251         return sum;
252     }
253
254     private static  long normalizeChecksum(long value) {
255         if ((value & 0xffff0000) != 0) {
256             value = value & 0xffff;
257             value += 1;
258         }
259         return value;
260     }
261
262     public static byte[] convertEthernetHeaderToByte(EthernetHeader ethPdu) {
263         byte[] data = new byte[16];
264         Arrays.fill(data, (byte)0);
265
266         ByteBuffer buf = ByteBuffer.wrap(data);
267         buf.put(bytesFromHexString(ethPdu.getDestinationMac().getValue()));
268         buf.put(bytesFromHexString(ethPdu.getSourceMac().getValue()));
269         buf.putShort((short)ethPdu.getEthertype().intValue());
270         return data;
271     }
272
273     public static byte[] convertIpv6HeaderToByte(Ipv6Header ip6Pdu) {
274         byte[] data = new byte[128];
275         Arrays.fill(data, (byte)0);
276
277         ByteBuffer buf = ByteBuffer.wrap(data);
278         long flowLabel = (long)(ip6Pdu.getVersion() & 0x0f) << 28
279                 | ip6Pdu.getFlowLabel() & 0x0fffffff;
280         buf.putInt((int)flowLabel);
281         buf.putShort((short)ip6Pdu.getIpv6Length().intValue());
282         buf.put((byte)ip6Pdu.getNextHeader().shortValue());
283         buf.put((byte)ip6Pdu.getHopLimit().shortValue());
284         try {
285             byte[] baddr = InetAddress.getByName(ip6Pdu.getSourceIpv6().getValue()).getAddress();
286             buf.put(baddr);
287             baddr = InetAddress.getByName(ip6Pdu.getDestinationIpv6().getValue()).getAddress();
288             buf.put(baddr);
289         } catch (UnknownHostException e) {
290             LOG.error("convertIpv6HeaderToByte: Failed to serialize src, dest address", e);
291         }
292         return data;
293     }
294
295     public static Ipv6Address getIpv6LinkLocalAddressFromMac(MacAddress mac) {
296         byte[] octets = bytesFromHexString(mac.getValue());
297
298         /* As per the RFC2373, steps involved to generate a LLA include
299            1. Convert the 48 bit MAC address to 64 bit value by inserting 0xFFFE
300               between OUI and NIC Specific part.
301            2. Invert the Universal/Local flag in the OUI portion of the address.
302            3. Use the prefix "FE80::/10" along with the above 64 bit Interface
303               identifier to generate the IPv6 LLA. */
304
305         StringBuilder interfaceID = new StringBuilder();
306         short u8byte = (short) (octets[0] & 0xff);
307         u8byte ^= 1 << 1;
308         interfaceID.append(Integer.toHexString(0xFF & u8byte));
309         interfaceID.append(StringUtils.leftPad(Integer.toHexString(0xFF & octets[1]), 2, "0"));
310         interfaceID.append(":");
311         interfaceID.append(Integer.toHexString(0xFF & octets[2]));
312         interfaceID.append("ff:fe");
313         interfaceID.append(StringUtils.leftPad(Integer.toHexString(0xFF & octets[3]), 2, "0"));
314         interfaceID.append(":");
315         interfaceID.append(Integer.toHexString(0xFF & octets[4]));
316         interfaceID.append(StringUtils.leftPad(Integer.toHexString(0xFF & octets[5]), 2, "0"));
317
318         // Return the address in its fully expanded format.
319         Ipv6Address ipv6LLA = new Ipv6Address(InetAddresses.forString(
320                 "fe80:0:0:0:" + interfaceID.toString()).getHostAddress());
321         return ipv6LLA;
322     }
323
324     public static Ipv6Address getIpv6SolicitedNodeMcastAddress(Ipv6Address ipv6Address) {
325
326         /* According to RFC 4291, a Solicited Node Multicast Address is derived by adding the 24
327            lower order bits with the Solicited Node multicast prefix (i.e., FF02::1:FF00:0/104).
328            Example: For IPv6Address of FE80::2AA:FF:FE28:9C5A, the corresponding solicited node
329            multicast address would be FF02::1:FF28:9C5A
330          */
331
332         byte[] octets;
333         try {
334             octets = InetAddress.getByName(ipv6Address.getValue()).getAddress();
335         } catch (UnknownHostException e) {
336             LOG.error("getIpv6SolicitedNodeMcastAddress: Failed to serialize ipv6Address ", e);
337             return null;
338         }
339
340         // Return the address in its fully expanded format.
341         Ipv6Address solictedV6Address = new Ipv6Address(InetAddresses.forString("ff02::1:ff"
342                  + StringUtils.leftPad(Integer.toHexString(0xFF & octets[13]), 2, "0") + ":"
343                  + StringUtils.leftPad(Integer.toHexString(0xFF & octets[14]), 2, "0")
344                  + StringUtils.leftPad(Integer.toHexString(0xFF & octets[15]), 2, "0")).getHostAddress());
345
346         return solictedV6Address;
347     }
348
349     public static MacAddress getIpv6MulticastMacAddress(Ipv6Address ipv6Address) {
350
351         /* According to RFC 2464, a Multicast MAC address is derived by concatenating 32 lower
352            order bits of IPv6 Multicast Address with the multicast prefix (i.e., 33:33).
353            Example: For Multicast IPv6Address of FF02::1:FF28:9C5A, the corresponding L2 multicast
354            address would be 33:33:28:9C:5A
355          */
356         byte[] octets;
357         try {
358             octets = InetAddress.getByName(ipv6Address.getValue()).getAddress();
359         } catch (UnknownHostException e) {
360             LOG.error("getIpv6MulticastMacAddress: Failed to serialize ipv6Address ", e);
361             return null;
362         }
363
364         String macAddress = "33:33:"
365                 + StringUtils.leftPad(Integer.toHexString(0xFF & octets[12]), 2, "0") + ":"
366                 + StringUtils.leftPad(Integer.toHexString(0xFF & octets[13]), 2, "0") + ":"
367                 + StringUtils.leftPad(Integer.toHexString(0xFF & octets[14]), 2, "0") + ":"
368                 + StringUtils.leftPad(Integer.toHexString(0xFF & octets[15]), 2, "0");
369
370         return new MacAddress(macAddress);
371     }
372
373     private static List<MatchInfo> getIcmpv6RSMatch(Long elanTag) {
374         List<MatchInfo> matches = new ArrayList<>();
375         matches.add(MatchEthernetType.IPV6);
376         matches.add(MatchIpProtocol.ICMPV6);
377         matches.add(new MatchIcmpv6(Ipv6Constants.ICMP_V6_RS_CODE, (short) 0));
378         matches.add(new MatchMetadata(MetaDataUtil.getElanTagMetadata(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
379         return matches;
380     }
381
382     private List<MatchInfo> getIcmpv6NSMatch(Long elanTag, String ndTarget) {
383         List<MatchInfo> matches = new ArrayList<>();
384         matches.add(MatchEthernetType.IPV6);
385         matches.add(MatchIpProtocol.ICMPV6);
386         matches.add(new MatchIcmpv6(Ipv6Constants.ICMP_V6_NS_CODE, (short) 0));
387         matches.add(new MatchIpv6NdTarget(new Ipv6Address(ndTarget)));
388         matches.add(new MatchMetadata(MetaDataUtil.getElanTagMetadata(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
389         return matches;
390     }
391
392     private static String getIPv6FlowRef(BigInteger dpId, Long elanTag, String flowType) {
393         return new StringBuffer().append(Ipv6Constants.FLOWID_PREFIX)
394                 .append(dpId).append(Ipv6Constants.FLOWID_SEPARATOR)
395                 .append(elanTag).append(Ipv6Constants.FLOWID_SEPARATOR)
396                 .append(flowType).toString();
397     }
398
399     public void installIcmpv6NsPuntFlow(short tableId, BigInteger dpId,  Long elanTag, String ipv6Address,
400             int addOrRemove) {
401         List<MatchInfo> neighborSolicitationMatch = getIcmpv6NSMatch(elanTag, ipv6Address);
402         List<InstructionInfo> instructions = new ArrayList<>();
403         List<ActionInfo> actionsInfos = new ArrayList<>();
404         actionsInfos.add(new ActionPuntToController());
405         instructions.add(new InstructionApplyActions(actionsInfos));
406         FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
407                 getIPv6FlowRef(dpId, elanTag, ipv6Address),Ipv6Constants.DEFAULT_FLOW_PRIORITY, "IPv6NS",
408                 0, 0, NwConstants.COOKIE_IPV6_TABLE, neighborSolicitationMatch, instructions);
409         if (addOrRemove == Ipv6Constants.DEL_FLOW) {
410             LOG.trace("Removing IPv6 Neighbor Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
411             mdsalUtil.removeFlow(rsFlowEntity);
412         } else {
413             LOG.trace("Installing IPv6 Neighbor Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
414             mdsalUtil.installFlow(rsFlowEntity);
415         }
416     }
417
418     public void installIcmpv6RsPuntFlow(short tableId, BigInteger dpId, Long elanTag, int addOrRemove) {
419         if (dpId == null || dpId.equals(Ipv6Constants.INVALID_DPID)) {
420             return;
421         }
422         List<MatchInfo> routerSolicitationMatch = getIcmpv6RSMatch(elanTag);
423         List<InstructionInfo> instructions = new ArrayList<>();
424         List<ActionInfo> actionsInfos = new ArrayList<>();
425         // Punt to controller
426         actionsInfos.add(new ActionPuntToController());
427         instructions.add(new InstructionApplyActions(actionsInfos));
428         FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
429                 getIPv6FlowRef(dpId, elanTag, "IPv6RS"),Ipv6Constants.DEFAULT_FLOW_PRIORITY, "IPv6RS", 0, 0,
430                 NwConstants.COOKIE_IPV6_TABLE, routerSolicitationMatch, instructions);
431         if (addOrRemove == Ipv6Constants.DEL_FLOW) {
432             LOG.trace("Removing IPv6 Router Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
433             mdsalUtil.removeFlow(rsFlowEntity);
434         } else {
435             LOG.trace("Installing IPv6 Router Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
436             mdsalUtil.installFlow(rsFlowEntity);
437         }
438     }
439
440     public BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
441                                           BigInteger cookie, List<Instruction> instructions) {
442         StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie)
443                 .setFlowPriority(flowPriority).setInstruction(instructions);
444         return new BoundServicesBuilder().setKey(new BoundServicesKey(servicePriority))
445                 .setServiceName(serviceName).setServicePriority(servicePriority)
446                 .setServiceType(ServiceTypeFlowBased.class)
447                 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
448     }
449
450     private InstanceIdentifier<BoundServices> buildServiceId(String interfaceName,
451                                               short priority) {
452         return InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class,
453                 new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
454                 .child(BoundServices.class, new BoundServicesKey(priority)).build();
455     }
456
457     public void bindIpv6Service(String interfaceName, Long elanTag, short tableId) {
458         int instructionKey = 0;
459         List<Instruction> instructions = new ArrayList<>();
460         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(MetaDataUtil.getElanTagMetadata(elanTag),
461                 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
462         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(tableId, ++instructionKey));
463         short serviceIndex = ServiceIndex.getIndex(NwConstants.IPV6_SERVICE_NAME, NwConstants.IPV6_SERVICE_INDEX);
464         BoundServices
465                 serviceInfo =
466                 getBoundServices(String.format("%s.%s", "ipv6", interfaceName),
467                         serviceIndex, Ipv6Constants.DEFAULT_FLOW_PRIORITY,
468                         NwConstants.COOKIE_IPV6_TABLE, instructions);
469         MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
470                 buildServiceId(interfaceName, serviceIndex), serviceInfo);
471     }
472
473     public void unbindIpv6Service(String interfaceName) {
474         MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION,
475                 buildServiceId(interfaceName, ServiceIndex.getIndex(NwConstants.IPV6_SERVICE_NAME,
476                         NwConstants.IPV6_SERVICE_INDEX)));
477     }
478 }