e8584cd78e247f1a67c0a75cc0308375f789b5f0
[netvirt.git] / ipv6service / impl / src / main / java / org / opendaylight / netvirt / ipv6service / IfMgr.java
1 /*
2  * Copyright (c) 2015 Dell 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;
10
11 import com.google.common.base.Strings;
12 import com.google.common.collect.Lists;
13 import com.google.common.collect.Sets;
14 import com.google.common.net.InetAddresses;
15 import io.netty.util.Timeout;
16 import java.math.BigInteger;
17 import java.util.ArrayList;
18 import java.util.Collection;
19 import java.util.Collections;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Set;
23 import java.util.concurrent.ConcurrentHashMap;
24 import java.util.concurrent.ConcurrentMap;
25 import java.util.concurrent.ExecutionException;
26 import java.util.concurrent.Future;
27 import java.util.concurrent.TimeUnit;
28 import javax.annotation.Nullable;
29 import javax.annotation.PreDestroy;
30 import javax.inject.Inject;
31 import javax.inject.Singleton;
32 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
33 import org.opendaylight.genius.ipv6util.api.Ipv6Constants.Ipv6RouterAdvertisementType;
34 import org.opendaylight.genius.ipv6util.api.Ipv6Util;
35 import org.opendaylight.genius.mdsalutil.MDSALUtil;
36 import org.opendaylight.genius.mdsalutil.NwConstants;
37 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
38 import org.opendaylight.netvirt.elanmanager.api.IElanService;
39 import org.opendaylight.netvirt.ipv6service.api.ElementCache;
40 import org.opendaylight.netvirt.ipv6service.api.IVirtualNetwork;
41 import org.opendaylight.netvirt.ipv6service.api.IVirtualPort;
42 import org.opendaylight.netvirt.ipv6service.api.IVirtualRouter;
43 import org.opendaylight.netvirt.ipv6service.api.IVirtualSubnet;
44 import org.opendaylight.netvirt.ipv6service.utils.Ipv6PeriodicTrQueue;
45 import org.opendaylight.netvirt.ipv6service.utils.Ipv6ServiceConstants;
46 import org.opendaylight.netvirt.ipv6service.utils.Ipv6ServiceUtils;
47 import org.opendaylight.netvirt.ipv6service.utils.Ipv6TimerWheel;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInput;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInputBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexOutput;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
66 import org.opendaylight.yangtools.yang.common.RpcResult;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
69
70 @Singleton
71 public class IfMgr implements ElementCache, AutoCloseable {
72
73     private static final Logger LOG = LoggerFactory.getLogger(IfMgr.class);
74
75     private final ConcurrentMap<Uuid, VirtualRouter> vrouters = new ConcurrentHashMap<>();
76     private final ConcurrentMap<Uuid, VirtualNetwork> vnetworks = new ConcurrentHashMap<>();
77     private final ConcurrentMap<Uuid, VirtualSubnet> vsubnets = new ConcurrentHashMap<>();
78     private final ConcurrentMap<Uuid, VirtualPort> vintfs = new ConcurrentHashMap<>();
79     private final ConcurrentMap<Uuid, VirtualPort> vrouterv6IntfMap = new ConcurrentHashMap<>();
80     private final ConcurrentMap<Uuid, Set<VirtualPort>> unprocessedRouterIntfs = new ConcurrentHashMap<>();
81     private final ConcurrentMap<Uuid, Set<VirtualPort>> unprocessedSubnetIntfs = new ConcurrentHashMap<>();
82     private static ConcurrentMap<Uuid, Set<VirtualPort>> unprocessedNetIntfs = new ConcurrentHashMap<>();
83     private static ConcurrentMap<Uuid, Integer> unprocessedNetRSFlowIntfs = new ConcurrentHashMap<>();
84     private static ConcurrentMap<Uuid, Set<Ipv6Address>> unprocessedNetNSFlowIntfs = new ConcurrentHashMap<>();
85     private static ConcurrentMap<Uuid, Set<VirtualSubnet>> unprocessedNetNaFlowIntfs = new ConcurrentHashMap<>();
86     private final OdlInterfaceRpcService interfaceManagerRpc;
87     private final IElanService elanProvider;
88     private final Ipv6ServiceUtils ipv6ServiceUtils;
89     private final DataBroker dataBroker;
90     private final Ipv6ServiceEosHandler ipv6ServiceEosHandler;
91     private final PacketProcessingService packetService;
92     private final Ipv6PeriodicTrQueue ipv6Queue = new Ipv6PeriodicTrQueue(this::transmitUnsolicitedRA);
93     private final Ipv6TimerWheel timer = new Ipv6TimerWheel();
94     private final JobCoordinator jobCoordinator;
95
96     @Inject
97     public IfMgr(DataBroker dataBroker, IElanService elanProvider, OdlInterfaceRpcService interfaceManagerRpc,
98                  PacketProcessingService packetService, Ipv6ServiceUtils ipv6ServiceUtils,
99                  Ipv6ServiceEosHandler ipv6ServiceEosHandler, JobCoordinator jobCoordinator) {
100         this.dataBroker = dataBroker;
101         this.elanProvider = elanProvider;
102         this.interfaceManagerRpc = interfaceManagerRpc;
103         this.packetService = packetService;
104         this.ipv6ServiceUtils = ipv6ServiceUtils;
105         this.ipv6ServiceEosHandler = ipv6ServiceEosHandler;
106         this.jobCoordinator = jobCoordinator;
107         LOG.info("IfMgr is enabled");
108     }
109
110     @Override
111     @PreDestroy
112     public void close() {
113         timer.close();
114     }
115
116     /**
117      * Add router.
118      *
119      * @param rtrUuid router uuid
120      * @param rtrName router name
121      * @param tenantId tenant id
122      */
123     public void addRouter(Uuid rtrUuid, String rtrName, Uuid tenantId) {
124
125         VirtualRouter rtr = VirtualRouter.builder().routerUUID(rtrUuid).tenantID(tenantId).name(rtrName).build();
126         vrouters.put(rtrUuid, rtr);
127
128         Set<VirtualPort> intfList = unprocessedRouterIntfs.remove(rtrUuid);
129         if (intfList == null) {
130             LOG.debug("No unprocessed interfaces for the router {}", rtrUuid);
131             return;
132         }
133
134         synchronized (intfList) {
135             for (VirtualPort intf : intfList) {
136                 if (intf != null) {
137                     intf.setRouter(rtr);
138                     rtr.addInterface(intf);
139
140                     for (VirtualSubnet snet : intf.getSubnets()) {
141                         rtr.addSubnet(snet);
142                     }
143                 }
144             }
145         }
146     }
147
148     /**
149      * Remove Router.
150      *
151      * @param rtrUuid router uuid
152      */
153     public void removeRouter(Uuid rtrUuid) {
154
155         VirtualRouter rtr = rtrUuid != null ? vrouters.remove(rtrUuid) : null;
156         if (rtr != null) {
157             rtr.removeSelf();
158             removeUnprocessed(unprocessedRouterIntfs, rtrUuid);
159         } else {
160             LOG.error("Delete router failed for :{}", rtrUuid);
161         }
162     }
163
164     /**
165      * Add Subnet.
166      *
167      * @param snetId subnet id
168      * @param name subnet name
169      * @param tenantId tenant id
170      * @param gatewayIp gateway ip address
171      * @param ipVersion IP Version "IPv4 or IPv6"
172      * @param subnetCidr subnet CIDR
173      * @param ipV6AddressMode Address Mode of IPv6 Subnet
174      * @param ipV6RaMode RA Mode of IPv6 Subnet.
175      */
176     public void addSubnet(Uuid snetId, String name, Uuid tenantId,
177                           IpAddress gatewayIp, String ipVersion, IpPrefix subnetCidr,
178                           String ipV6AddressMode, String ipV6RaMode) {
179
180         // Save the gateway ipv6 address in its fully expanded format. We always store the v6Addresses
181         // in expanded form and are used during Neighbor Discovery Support.
182         if (gatewayIp != null) {
183             Ipv6Address addr = new Ipv6Address(InetAddresses
184                     .forString(gatewayIp.getIpv6Address().getValue()).getHostAddress());
185             gatewayIp = new IpAddress(addr);
186         }
187
188         VirtualSubnet snet = VirtualSubnet.builder().subnetUUID(snetId).tenantID(tenantId).name(name)
189                 .gatewayIp(gatewayIp).subnetCidr(subnetCidr).ipVersion(ipVersion).ipv6AddressMode(ipV6AddressMode)
190                 .ipv6RAMode(ipV6RaMode).build();
191
192         vsubnets.put(snetId, snet);
193
194         Set<VirtualPort> intfList = unprocessedSubnetIntfs.remove(snetId);
195         if (intfList == null) {
196             LOG.debug("No unprocessed interfaces for the subnet {}", snetId);
197             return;
198         }
199
200         synchronized (intfList) {
201             for (VirtualPort intf : intfList) {
202                 if (intf != null) {
203                     intf.setSubnet(snetId, snet);
204                     snet.addInterface(intf);
205
206                     VirtualRouter rtr = intf.getRouter();
207                     if (rtr != null) {
208                         rtr.addSubnet(snet);
209                     }
210                     updateInterfaceDpidOfPortInfo(intf.getIntfUUID());
211                 }
212             }
213         }
214     }
215
216     /**
217      * Remove Subnet.
218      *
219      * @param snetId subnet id
220      */
221     public void removeSubnet(Uuid snetId) {
222         VirtualSubnet snet = snetId != null ? vsubnets.remove(snetId) : null;
223         if (snet != null) {
224             LOG.info("removeSubnet is invoked for {}", snetId);
225             snet.removeSelf();
226             removeUnprocessed(unprocessedSubnetIntfs, snetId);
227         }
228     }
229
230     @Nullable
231     private VirtualRouter getRouter(Uuid rtrId) {
232         return rtrId != null ? vrouters.get(rtrId) : null;
233     }
234
235     public void addRouterIntf(Uuid portId, Uuid rtrId, Uuid snetId,
236                               Uuid networkId, IpAddress fixedIp, String macAddress,
237                               String deviceOwner) {
238         LOG.debug("addRouterIntf portId {}, rtrId {}, snetId {}, networkId {}, ip {}, mac {}",
239                 portId, rtrId, snetId, networkId, fixedIp, macAddress);
240         /* Added the below logic for supporting neutron router interface creation.
241          * Since when neutron port is created with fixed Ipv6 address, that time it will be
242          * treated as a host port and it will be added into the vintfs map through
243          * NeutronPortChangeListener ADD() event.
244          * Later the same neutron port is added to router this time it will be treated as
245          * a router_interface through NeutronPortChangeListener UPDATE() event.
246          */
247         VirtualPort virInterface = vintfs.get(portId);
248         if (virInterface != null && Strings.isNullOrEmpty(virInterface.getDeviceOwner())) {
249             vintfs.remove(portId);
250         }
251         //Save the interface ipv6 address in its fully expanded format
252         Ipv6Address addr = new Ipv6Address(InetAddresses
253                 .forString(fixedIp.getIpv6Address().getValue()).getHostAddress());
254         fixedIp = new IpAddress(addr);
255
256         VirtualPort intf = VirtualPort.builder().intfUUID(portId).networkID(networkId).macAddress(macAddress)
257                 .routerIntfFlag(true).deviceOwner(deviceOwner).build();
258         intf.setSubnetInfo(snetId, fixedIp);
259         intf.setPeriodicTimer(ipv6Queue);
260         int networkMtu = getNetworkMtu(networkId);
261         if (networkMtu != 0) {
262             intf.setMtu(networkMtu);
263         }
264
265         boolean newIntf = false;
266         VirtualPort prevIntf = vintfs.putIfAbsent(portId, intf);
267         if (prevIntf == null) {
268             newIntf = true;
269             MacAddress ifaceMac = MacAddress.getDefaultInstance(macAddress);
270             Ipv6Address llAddr = Ipv6Util.getIpv6LinkLocalAddressFromMac(ifaceMac);
271             /* A new router interface is created. This is basically triggered when an
272             IPv6 subnet is associated to the router. Check if network is already hosting
273             any VMs. If so, on all the hosts that have VMs on the network, program the
274             icmpv6 punt flows in IPV6_TABLE(45).
275              */
276             programIcmpv6RSPuntFlows(intf.getNetworkID(), Ipv6ServiceConstants.ADD_FLOW);
277             programIcmpv6NSPuntFlowForAddress(intf.getNetworkID(), llAddr, Ipv6ServiceConstants.ADD_FLOW);
278             programIcmpv6NaForwardFlows(intf.getNetworkID(), getSubnet(snetId), Ipv6ServiceConstants.ADD_FLOW);
279         } else {
280             intf = prevIntf;
281             intf.setSubnetInfo(snetId, fixedIp);
282         }
283
284         VirtualRouter rtr = getRouter(rtrId);
285         VirtualSubnet snet = getSubnet(snetId);
286
287         if (rtr != null && snet != null) {
288             snet.setRouter(rtr);
289             intf.setSubnet(snetId, snet);
290             rtr.addSubnet(snet);
291         } else if (snet != null) {
292             intf.setSubnet(snetId, snet);
293             addUnprocessed(unprocessedRouterIntfs, rtrId, intf);
294         } else {
295             addUnprocessed(unprocessedRouterIntfs, rtrId, intf);
296             addUnprocessed(unprocessedSubnetIntfs, snetId, intf);
297         }
298
299         if (networkId != null) {
300             vrouterv6IntfMap.put(networkId, intf);
301         }
302
303         programIcmpv6NSPuntFlowForAddress(intf.getNetworkID(), fixedIp.getIpv6Address(), Ipv6ServiceConstants.ADD_FLOW);
304         programIcmpv6NaPuntFlow(networkId, intf.getSubnets(), Ipv6ServiceConstants.ADD_FLOW);
305
306         if (newIntf) {
307             LOG.debug("start the periodic RA Timer for routerIntf {}", portId);
308             transmitUnsolicitedRA(intf);
309         }
310     }
311
312     public void updateRouterIntf(Uuid portId, Uuid rtrId, List<FixedIps> fixedIpsList, Set<FixedIps> deletedIps) {
313         LOG.info("updateRouterIntf portId {}, fixedIpsList {} ", portId, fixedIpsList);
314         VirtualPort intf = getPort(portId);
315         if (intf == null) {
316             LOG.info("Skip Router interface update for non-ipv6 port {}", portId);
317             return;
318         }
319         Uuid networkID = intf.getNetworkID();
320         intf.clearSubnetInfo();
321         for (FixedIps fip : fixedIpsList) {
322             IpAddress fixedIp = fip.getIpAddress();
323
324             if (fixedIp.getIpv4Address() != null) {
325                 continue;
326             }
327
328             //Save the interface ipv6 address in its fully expanded format
329             Ipv6Address addr = new Ipv6Address(InetAddresses
330                     .forString(fixedIp.getIpv6Address().getValue()).getHostAddress());
331             fixedIp = new IpAddress(addr);
332             Uuid subnetId = fip.getSubnetId();
333             intf.setSubnetInfo(subnetId, fixedIp);
334
335             VirtualRouter rtr = getRouter(rtrId);
336             VirtualSubnet snet = getSubnet(subnetId);
337
338             if (rtr != null && snet != null) {
339                 snet.setRouter(rtr);
340                 intf.setSubnet(subnetId, snet);
341                 rtr.addSubnet(snet);
342             } else if (snet != null) {
343                 intf.setSubnet(subnetId, snet);
344                 addUnprocessed(unprocessedRouterIntfs, rtrId, intf);
345             } else {
346                 addUnprocessed(unprocessedRouterIntfs, rtrId, intf);
347                 addUnprocessed(unprocessedSubnetIntfs, subnetId, intf);
348             }
349
350             if (networkID != null) {
351                 vrouterv6IntfMap.put(networkID, intf);
352             }
353         }
354
355         /*
356          * This is a port update event for routerPort. Check if any IPv6 subnet is added or removed from the
357          * router port. Depending on subnet added/removed, we add/remove the corresponding flows from
358          * IPV6_TABLE(45). Add is handled in addInterfaceInfo(), delete case is handled here.
359          */
360         for (FixedIps ips : deletedIps) {
361             VirtualSubnet snet = getSubnet(ips.getSubnetId());
362             programIcmpv6NaPuntFlow(networkID, Lists.newArrayList(snet), Ipv6ServiceConstants.DEL_FLOW);
363             programIcmpv6NSPuntFlowForAddress(networkID, ips.getIpAddress().getIpv6Address(),
364                     Ipv6ServiceConstants.DEL_FLOW);
365         }
366     }
367
368     @Nullable
369     private VirtualSubnet getSubnet(Uuid snetId) {
370         return snetId != null ? vsubnets.get(snetId) : null;
371     }
372
373     public void addHostIntf(Uuid portId, Uuid snetId, Uuid networkId,
374                             IpAddress fixedIp, String macAddress, String deviceOwner) {
375         LOG.debug("addHostIntf portId {}, snetId {}, networkId {}, ip {}, mac {}",
376                 portId, snetId, networkId, fixedIp, macAddress);
377
378         //Save the interface ipv6 address in its fully expanded format
379         Ipv6Address addr = new Ipv6Address(InetAddresses
380                 .forString(fixedIp.getIpv6Address().getValue()).getHostAddress());
381         fixedIp = new IpAddress(addr);
382
383         VirtualPort intf = VirtualPort.builder().intfUUID(portId).networkID(networkId).macAddress(macAddress)
384                 .routerIntfFlag(false).deviceOwner(deviceOwner).build();
385         intf.setSubnetInfo(snetId, fixedIp);
386
387         VirtualPort prevIntf = vintfs.putIfAbsent(portId, intf);
388         if (prevIntf == null) {
389             Long elanTag = getNetworkElanTag(networkId);
390             VirtualPort virtIntf = intf;
391             jobCoordinator.enqueueJob("IPv6-" + String.valueOf(portId), () -> {
392                 // Do service binding for the port and set the serviceBindingStatus to true.
393                 ipv6ServiceUtils.bindIpv6Service(portId.getValue(), elanTag, NwConstants.IPV6_TABLE);
394                 virtIntf.setServiceBindingStatus(true);
395
396                 /* Update the intf dpnId/ofPort from the Operational Store */
397                 updateInterfaceDpidOfPortInfo(portId);
398                 return Collections.emptyList();
399             });
400
401         } else {
402             intf = prevIntf;
403             intf.setSubnetInfo(snetId, fixedIp);
404         }
405
406         VirtualSubnet snet = getSubnet(snetId);
407
408         if (snet != null) {
409             intf.setSubnet(snetId, snet);
410         } else {
411             addUnprocessed(unprocessedSubnetIntfs, snetId, intf);
412         }
413     }
414
415     @Nullable
416     private VirtualPort getPort(Uuid portId) {
417         return portId != null ? vintfs.get(portId) : null;
418     }
419
420     public void clearAnyExistingSubnetInfo(Uuid portId) {
421         VirtualPort intf = getPort(portId);
422         if (intf != null) {
423             intf.clearSubnetInfo();
424         }
425     }
426
427     public void updateHostIntf(Uuid portId, Boolean portIncludesV6Address) {
428         VirtualPort intf = getPort(portId);
429         if (intf == null) {
430             LOG.debug("Update Host interface failed. Could not get Host interface details {}", portId);
431             return;
432         }
433
434         /* If the VMPort initially included an IPv6 address (along with IPv4 address) and IPv6 address
435          was removed, we will have to unbind the service on the VM port. Similarly we do a ServiceBind
436          if required.
437           */
438         if (portIncludesV6Address) {
439             if (!intf.getServiceBindingStatus()) {
440                 Long elanTag = getNetworkElanTag(intf.getNetworkID());
441                 LOG.info("In updateHostIntf, service binding for portId {}", portId);
442                 jobCoordinator.enqueueJob("IPv6-" + String.valueOf(portId), () -> {
443                     ipv6ServiceUtils.bindIpv6Service(portId.getValue(), elanTag, NwConstants.IPV6_TABLE);
444                     intf.setServiceBindingStatus(true);
445                     return Collections.emptyList();
446                 });
447             }
448         } else {
449             LOG.info("In updateHostIntf, removing service binding for portId {}", portId);
450             jobCoordinator.enqueueJob("IPv6-" + String.valueOf(portId), () -> {
451                 ipv6ServiceUtils.unbindIpv6Service(portId.getValue());
452                 intf.setServiceBindingStatus(false);
453                 return Collections.emptyList();
454             });
455         }
456     }
457
458     public void updateDpnInfo(Uuid portId, BigInteger dpId, Long ofPort) {
459         LOG.info("In updateDpnInfo portId {}, dpId {}, ofPort {}",
460                 portId, dpId, ofPort);
461         VirtualPort intf = getPort(portId);
462         if (intf != null) {
463             intf.setDpId(dpId);
464             intf.setOfPort(ofPort);
465
466             // Update the network <--> List[dpnIds, List<ports>] cache.
467             VirtualNetwork vnet = getNetwork(intf.getNetworkID());
468             if (null != vnet) {
469                 vnet.updateDpnPortInfo(dpId, ofPort, Ipv6ServiceConstants.ADD_ENTRY);
470             } else {
471                 LOG.error("In updateDpnInfo networks NOT FOUND: networkID {}, portId {}, dpId {}, ofPort {}",
472                            intf.getNetworkID(), portId, dpId, ofPort);
473                 addUnprocessed(unprocessedNetIntfs, intf.getNetworkID(), intf);
474             }
475         } else {
476             LOG.error("In updateDpnInfo port NOT FOUND: portId {}, dpId {}, ofPort {}",
477                     portId, dpId, ofPort);
478         }
479     }
480
481
482     public void updateInterfaceDpidOfPortInfo(Uuid portId) {
483         LOG.debug("In updateInterfaceDpidOfPortInfo portId {}", portId);
484         Interface interfaceState = ipv6ServiceUtils.getInterfaceStateFromOperDS(portId.getValue());
485         if (interfaceState == null) {
486             LOG.warn("In updateInterfaceDpidOfPortInfo, port info not found in Operational Store {}.", portId);
487             return;
488         }
489
490         List<String> ofportIds = interfaceState.getLowerLayerIf();
491         NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
492         BigInteger dpId = ipv6ServiceUtils.getDpIdFromInterfaceState(interfaceState);
493         if (!dpId.equals(Ipv6ServiceConstants.INVALID_DPID)) {
494             Long ofPort = MDSALUtil.getOfPortNumberFromPortName(nodeConnectorId);
495             updateDpnInfo(portId, dpId, ofPort);
496         }
497     }
498
499
500     public void removePort(Uuid portId) {
501         VirtualPort intf = portId != null ? vintfs.remove(portId) : null;
502         if (intf != null) {
503             intf.removeSelf();
504             Uuid networkID = intf.getNetworkID();
505             if (intf.getDeviceOwner().equalsIgnoreCase(Ipv6ServiceConstants.NETWORK_ROUTER_INTERFACE)) {
506                 LOG.info("In removePort for router interface, portId {}", portId);
507
508                 if (networkID != null) {
509                     vrouterv6IntfMap.remove(networkID, intf);
510                 }
511
512                 /* Router port is deleted. Remove the corresponding icmpv6 punt flows on all
513                 the dpnIds which were hosting the VMs on the network.
514                  */
515                 programIcmpv6RSPuntFlows(intf.getNetworkID(), Ipv6ServiceConstants.DEL_FLOW);
516                 programIcmpv6NaPuntFlow(networkID, intf.getSubnets(), Ipv6ServiceConstants.DEL_FLOW);
517                 for (Ipv6Address ipv6Address: intf.getIpv6Addresses()) {
518                     programIcmpv6NSPuntFlowForAddress(intf.getNetworkID(), ipv6Address, Ipv6ServiceConstants.DEL_FLOW);
519                 }
520                 for (VirtualSubnet subnet : intf.getSubnets()) {
521                     programIcmpv6NaForwardFlows(networkID, subnet, Ipv6ServiceConstants.DEL_FLOW);
522                 }
523                 transmitRouterAdvertisement(intf, Ipv6RouterAdvertisementType.CEASE_ADVERTISEMENT);
524                 timer.cancelPeriodicTransmissionTimeout(intf.getPeriodicTimeout());
525                 intf.resetPeriodicTimeout();
526                 LOG.debug("Reset the periodic RA Timer for intf {}", intf.getIntfUUID());
527             } else {
528                 LOG.info("In removePort for host interface, portId {}", portId);
529                 jobCoordinator.enqueueJob("IPv6-" + String.valueOf(portId), () -> {
530                     // Remove the serviceBinding entry for the port.
531                     ipv6ServiceUtils.unbindIpv6Service(portId.getValue());
532                     // Remove the portId from the (network <--> List[dpnIds, List <ports>]) cache.
533                     VirtualNetwork vnet = getNetwork(networkID);
534                     if (null != vnet) {
535                         BigInteger dpId = intf.getDpId();
536                         vnet.updateDpnPortInfo(dpId, intf.getOfPort(), Ipv6ServiceConstants.DEL_ENTRY);
537                     }
538                     return Collections.emptyList();
539                 });
540             }
541         }
542     }
543
544     public void deleteInterface(Uuid interfaceUuid, String dpId) {
545         // Nothing to do for now
546     }
547
548     public void addUnprocessed(Map<Uuid, Set<VirtualPort>> unprocessed, Uuid id, VirtualPort intf) {
549         if (id != null) {
550             unprocessed.computeIfAbsent(id,
551                 key -> Collections.synchronizedSet(ConcurrentHashMap.newKeySet())).add(intf);
552         }
553     }
554
555     @Nullable
556     public Set<VirtualPort> removeUnprocessed(Map<Uuid, Set<VirtualPort>> unprocessed, Uuid id) {
557         if (id != null) {
558             return unprocessed.remove(id);
559         }
560         return null;
561     }
562
563     public void addUnprocessedRSFlows(Map<Uuid, Integer> unprocessed, Uuid id, Integer action) {
564         unprocessed.put(id, action);
565
566     }
567
568     public Integer removeUnprocessedRSFlows(Map<Uuid, Integer> unprocessed, Uuid id) {
569         return unprocessed.remove(id);
570     }
571
572     private void addUnprocessedNSFlows(Map<Uuid, Set<Ipv6Address>> unprocessed, Uuid id, Ipv6Address ipv6Address,
573             Integer action) {
574         if (action == Ipv6ServiceConstants.ADD_FLOW) {
575             unprocessed.computeIfAbsent(id, key -> Collections.synchronizedSet(ConcurrentHashMap.newKeySet()))
576                     .add(ipv6Address);
577         } else if (action == Ipv6ServiceConstants.DEL_FLOW) {
578             Set<Ipv6Address> ipv6AddressesList = unprocessed.get(id);
579             if ((ipv6AddressesList != null) && (ipv6AddressesList.contains(ipv6Address))) {
580                 ipv6AddressesList.remove(ipv6Address);
581             }
582         }
583     }
584
585     private Set<Ipv6Address> removeUnprocessedNSFlows(Map<Uuid, Set<Ipv6Address>> unprocessed, Uuid id) {
586         Set<Ipv6Address> removedIps = unprocessed.remove(id);
587         return removedIps != null ? removedIps : Collections.emptySet();
588     }
589
590     private void addUnprocessedNaFlows(Uuid networkId, Collection<VirtualSubnet> subnets, Integer action) {
591         if (action == Ipv6ServiceConstants.ADD_FLOW) {
592             unprocessedNetNaFlowIntfs.computeIfAbsent(networkId, key -> ConcurrentHashMap.newKeySet())
593                     .addAll(subnets);
594         } else if (action == Ipv6ServiceConstants.DEL_FLOW) {
595             Set<VirtualSubnet> subnetsInCache = unprocessedNetNaFlowIntfs.get(networkId);
596             if (subnetsInCache != null) {
597                 subnetsInCache.removeAll(subnets);
598             }
599         }
600     }
601
602     private Set<VirtualSubnet> removeUnprocessedNaFlows(Uuid networkId) {
603         Set<VirtualSubnet> removedSubnets = unprocessedNetNaFlowIntfs.remove(networkId);
604         return removedSubnets != null ? removedSubnets : Collections.emptySet();
605     }
606
607     @Nullable
608     public VirtualPort getRouterV6InterfaceForNetwork(Uuid networkId) {
609         LOG.debug("obtaining the virtual interface for {}", networkId);
610         return networkId != null ? vrouterv6IntfMap.get(networkId) : null;
611     }
612
613     @Nullable
614     public VirtualPort obtainV6Interface(Uuid id) {
615         VirtualPort intf = getPort(id);
616         if (intf == null) {
617             return null;
618         }
619         for (VirtualSubnet snet : intf.getSubnets()) {
620             if (snet.getIpVersion().equals(Ipv6ServiceConstants.IP_VERSION_V6)) {
621                 return intf;
622             }
623         }
624         return null;
625     }
626
627     private void programIcmpv6RSPuntFlows(Uuid networkId, int action) {
628         if (!ipv6ServiceEosHandler.isClusterOwner()) {
629             LOG.trace("Not a cluster Owner, skip flow programming.");
630             return;
631         }
632
633         Long elanTag = getNetworkElanTag(networkId);
634         int flowStatus;
635         VirtualNetwork vnet = getNetwork(networkId);
636         if (vnet != null) {
637             List<BigInteger> dpnList = vnet.getDpnsHostingNetwork();
638             for (BigInteger dpId : dpnList) {
639                 flowStatus = vnet.getRSPuntFlowStatusOnDpnId(dpId);
640                 if (action == Ipv6ServiceConstants.ADD_FLOW
641                         && flowStatus == Ipv6ServiceConstants.FLOWS_NOT_CONFIGURED) {
642                     ipv6ServiceUtils.installIcmpv6RsPuntFlow(NwConstants.IPV6_TABLE, dpId, elanTag,
643                             Ipv6ServiceConstants.ADD_FLOW);
644                     vnet.setRSPuntFlowStatusOnDpnId(dpId, Ipv6ServiceConstants.FLOWS_CONFIGURED);
645                 } else if (action == Ipv6ServiceConstants.DEL_FLOW
646                         && flowStatus == Ipv6ServiceConstants.FLOWS_CONFIGURED) {
647                     ipv6ServiceUtils.installIcmpv6RsPuntFlow(NwConstants.IPV6_TABLE, dpId, elanTag,
648                             Ipv6ServiceConstants.DEL_FLOW);
649                     vnet.setRSPuntFlowStatusOnDpnId(dpId, Ipv6ServiceConstants.FLOWS_NOT_CONFIGURED);
650                 }
651             }
652         } else {
653             addUnprocessedRSFlows(unprocessedNetRSFlowIntfs, networkId, action);
654         }
655     }
656
657     private void programIcmpv6NSPuntFlowForAddress(Uuid networkId, Ipv6Address ipv6Address, int action) {
658         if (!ipv6ServiceEosHandler.isClusterOwner()) {
659             LOG.trace("Not a cluster Owner, skip flow programming.");
660             return;
661         }
662
663         Long elanTag = getNetworkElanTag(networkId);
664         VirtualNetwork vnet = getNetwork(networkId);
665         if (vnet != null) {
666             Collection<VirtualNetwork.DpnInterfaceInfo> dpnIfaceList = vnet.getDpnIfaceList();
667             for (VirtualNetwork.DpnInterfaceInfo dpnIfaceInfo : dpnIfaceList) {
668                 if (action == Ipv6ServiceConstants.ADD_FLOW
669                         && !dpnIfaceInfo.isNdTargetFlowAlreadyConfigured(ipv6Address)
670                         && dpnIfaceInfo.getDpId() != null) {
671                     ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpnIfaceInfo.getDpId(), elanTag,
672                             ipv6Address, Ipv6ServiceConstants.ADD_FLOW);
673                     dpnIfaceInfo.updateNDTargetAddress(ipv6Address, action);
674                 } else if (action == Ipv6ServiceConstants.DEL_FLOW
675                         && dpnIfaceInfo.isNdTargetFlowAlreadyConfigured(ipv6Address)) {
676                     ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpnIfaceInfo.getDpId(), elanTag,
677                             ipv6Address, Ipv6ServiceConstants.DEL_FLOW);
678                     dpnIfaceInfo.updateNDTargetAddress(ipv6Address, action);
679                 }
680             }
681         } else {
682             addUnprocessedNSFlows(unprocessedNetNSFlowIntfs, networkId, ipv6Address, action);
683         }
684     }
685
686     private void programIcmpv6NaPuntFlow(Uuid networkID, Collection<VirtualSubnet> subnets, int action) {
687         if (!ipv6ServiceEosHandler.isClusterOwner()) {
688             LOG.trace("Not a cluster Owner, skip flow programming.");
689             return;
690         }
691         Long elanTag = getNetworkElanTag(networkID);
692         VirtualNetwork vnet = getNetwork(networkID);
693         if (vnet != null) {
694             Collection<VirtualNetwork.DpnInterfaceInfo> dpnIfaceList = vnet.getDpnIfaceList();
695             for (VirtualNetwork.DpnInterfaceInfo dpnIfaceInfo : dpnIfaceList) {
696                 if (dpnIfaceInfo.getDpId() == null) {
697                     continue;
698                 }
699                 for (VirtualSubnet subnet : subnets) {
700                     Ipv6Prefix ipv6SubnetPrefix = subnet.getSubnetCidr().getIpv6Prefix();
701                     if (ipv6SubnetPrefix != null) {
702                         if (action == Ipv6ServiceConstants.ADD_FLOW
703                                 && !dpnIfaceInfo.isSubnetCidrFlowAlreadyConfigured(subnet.getSubnetUUID())) {
704                             ipv6ServiceUtils.installIcmpv6NaPuntFlow(NwConstants.IPV6_TABLE, ipv6SubnetPrefix,
705                                     dpnIfaceInfo.getDpId(), elanTag, action);
706                             dpnIfaceInfo.updateSubnetCidrFlowStatus(subnet.getSubnetUUID(), action);
707                         } else if (action == Ipv6ServiceConstants.DEL_FLOW
708                                 && dpnIfaceInfo.isSubnetCidrFlowAlreadyConfigured(subnet.getSubnetUUID())) {
709                             ipv6ServiceUtils.installIcmpv6NaPuntFlow(NwConstants.IPV6_TABLE, ipv6SubnetPrefix,
710                                     dpnIfaceInfo.getDpId(), elanTag, action);
711                             dpnIfaceInfo.updateSubnetCidrFlowStatus(subnet.getSubnetUUID(), action);
712                         }
713                     }
714                 }
715             }
716         } else {
717             addUnprocessedNaFlows(networkID, subnets, action);
718         }
719     }
720
721     public void handleInterfaceStateEvent(VirtualPort port, BigInteger dpId, VirtualPort routerPort, int addOrRemove) {
722         Long elanTag = getNetworkElanTag(port.getNetworkID());
723         if (addOrRemove == Ipv6ServiceConstants.ADD_FLOW && routerPort != null) {
724             // Check and program icmpv6 punt flows on the dpnID if its the first VM on the host.
725             programIcmpv6PuntFlows(port, dpId, elanTag, routerPort);
726         }
727         if (elanTag != null) {
728             programIcmpv6NaForwardFlow(port, dpId, elanTag, addOrRemove);
729         } else {
730             addUnprocessedNaFlows(port.getNetworkID(), port.getSubnets(), addOrRemove);
731         }
732     }
733
734     private void programIcmpv6PuntFlows(IVirtualPort vmPort, BigInteger dpId, Long elanTag, VirtualPort routerPort) {
735         Uuid networkId = vmPort.getNetworkID();
736         VirtualNetwork vnet = getNetwork(networkId);
737         if (null != vnet) {
738             VirtualNetwork.DpnInterfaceInfo dpnInfo = vnet.getDpnIfaceInfo(dpId);
739             if (null != dpnInfo) {
740                 if (vnet.getRSPuntFlowStatusOnDpnId(dpId) == Ipv6ServiceConstants.FLOWS_NOT_CONFIGURED) {
741                     ipv6ServiceUtils.installIcmpv6RsPuntFlow(NwConstants.IPV6_TABLE, dpId, elanTag,
742                             Ipv6ServiceConstants.ADD_FLOW);
743                     vnet.setRSPuntFlowStatusOnDpnId(dpId, Ipv6ServiceConstants.FLOWS_CONFIGURED);
744                 }
745
746                 for (Ipv6Address ipv6Address : routerPort.getIpv6Addresses()) {
747                     if (!dpnInfo.isNdTargetFlowAlreadyConfigured(ipv6Address)) {
748                         ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpId,
749                                 elanTag, ipv6Address, Ipv6ServiceConstants.ADD_FLOW);
750                         dpnInfo.updateNDTargetAddress(ipv6Address, Ipv6ServiceConstants.ADD_FLOW);
751                     }
752                 }
753
754                 for (VirtualSubnet subnet : routerPort.getSubnets()) {
755                     Ipv6Prefix ipv6SubnetPrefix = subnet.getSubnetCidr().getIpv6Prefix();
756                     if (ipv6SubnetPrefix != null
757                             && !dpnInfo.isSubnetCidrFlowAlreadyConfigured(subnet.getSubnetUUID())) {
758                         ipv6ServiceUtils.installIcmpv6NaPuntFlow(NwConstants.IPV6_TABLE, ipv6SubnetPrefix, dpId,
759                                 elanTag, Ipv6ServiceConstants.ADD_FLOW);
760                         dpnInfo.updateSubnetCidrFlowStatus(subnet.getSubnetUUID(), Ipv6ServiceConstants.ADD_FLOW);
761                     }
762                 }
763             }
764         } else {
765             addUnprocessedRSFlows(unprocessedNetRSFlowIntfs, networkId, Ipv6ServiceConstants.ADD_FLOW);
766             for (Ipv6Address ipv6Address : routerPort.getIpv6Addresses()) {
767                 addUnprocessedNSFlows(unprocessedNetNSFlowIntfs, networkId, ipv6Address, Ipv6ServiceConstants.ADD_FLOW);
768             }
769             addUnprocessedNaFlows(networkId, routerPort.getSubnets(), Ipv6ServiceConstants.ADD_FLOW);
770         }
771     }
772
773     private void programIcmpv6NaForwardFlows(Uuid networkId, VirtualSubnet subnet, int action) {
774         if (!ipv6ServiceEosHandler.isClusterOwner()) {
775             LOG.trace("Not a cluster Owner, skip flow programming.");
776             return;
777         }
778         if (subnet == null) {
779             LOG.debug("Subnet is null, skipping programIcmpv6NaForwardFlows.");
780             return;
781         }
782
783         VirtualNetwork vnet = getNetwork(networkId);
784         if (vnet != null) {
785             if (!Ipv6ServiceUtils.isIpv6Subnet(subnet)) {
786                 return;
787             }
788             Long elanTag = getNetworkElanTag(networkId);
789             Collection<VirtualNetwork.DpnInterfaceInfo> dpnIfaceList = vnet.getDpnIfaceList();
790             for (VirtualNetwork.DpnInterfaceInfo dpnIfaceInfo : dpnIfaceList) {
791                 if (dpnIfaceInfo.getDpId() == null) {
792                     continue;
793                 }
794                 List<VirtualPort> vmPorts = getVmPortsInSubnetByDpId(subnet.getSubnetUUID(), dpnIfaceInfo.getDpId());
795                 for (VirtualPort vmPort : vmPorts) {
796                     programIcmpv6NaForwardFlow(vmPort, dpnIfaceInfo.getDpId(), elanTag, action);
797                 }
798             }
799         } else {
800             addUnprocessedNaFlows(networkId, Sets.newHashSet(subnet), action);
801         }
802     }
803
804     /**
805      * Programs ICMPv6 NA forwarding flow for fixed IPs of neutron port. NA's from non-fixed IPs are
806      * punted to controller for learning.
807      *
808      * @param vmPort the VM port
809      * @param dpId the DP ID
810      * @param elanTag the ELAN tag
811      * @param addOrRemove the add or remove flag
812      */
813     private void programIcmpv6NaForwardFlow(IVirtualPort vmPort, BigInteger dpId, Long elanTag, int addOrRemove) {
814         ipv6ServiceUtils.installIcmpv6NaForwardFlow(NwConstants.IPV6_TABLE, vmPort, dpId, elanTag, addOrRemove);
815     }
816
817     public List<VirtualPort> getVmPortsInSubnetByDpId(Uuid snetId, BigInteger dpId) {
818         List<VirtualPort> vmPorts = new ArrayList<>();
819         for (VirtualPort port : vintfs.values()) {
820             if (dpId.equals(port.getDpId()) && Ipv6ServiceUtils.isVmPort(port.getDeviceOwner())) {
821                 for (VirtualSubnet subnet : port.getSubnets()) {
822                     if (subnet.getSubnetUUID().equals(snetId)) {
823                         vmPorts.add(port);
824                     }
825                 }
826             }
827         }
828         return vmPorts;
829     }
830
831     public String getInterfaceNameFromTag(long portTag) {
832         String interfaceName = null;
833         GetInterfaceFromIfIndexInput input = new GetInterfaceFromIfIndexInputBuilder()
834                 .setIfIndex((int) portTag).build();
835         Future<RpcResult<GetInterfaceFromIfIndexOutput>> futureOutput =
836                 interfaceManagerRpc.getInterfaceFromIfIndex(input);
837         try {
838             GetInterfaceFromIfIndexOutput output = futureOutput.get().getResult();
839             interfaceName = output.getInterfaceName();
840         } catch (InterruptedException | ExecutionException e) {
841             LOG.error("Error while retrieving the interfaceName from tag using getInterfaceFromIfIndex RPC");
842         }
843         LOG.trace("Returning interfaceName {} for tag {} form getInterfaceNameFromTag", interfaceName, portTag);
844         return interfaceName;
845     }
846
847     @Nullable
848     public Long updateNetworkElanTag(Uuid networkId) {
849         Long elanTag = null;
850         if (null != this.elanProvider) {
851             ElanInstance elanInstance = this.elanProvider.getElanInstance(networkId.getValue());
852             if (null != elanInstance) {
853                 elanTag = elanInstance.getElanTag();
854                 VirtualNetwork net = getNetwork(networkId);
855                 if (null != net) {
856                     net.setElanTag(elanTag);
857                 }
858             }
859         }
860         return elanTag;
861     }
862
863     @Nullable
864     public void updateNetworkMtuInfo(Uuid networkId, int mtu) {
865         VirtualNetwork net = getNetwork(networkId);
866         if (null != net) {
867             net.setMtu(mtu);
868         }
869     }
870
871     @Nullable
872     private VirtualNetwork getNetwork(Uuid networkId) {
873         return networkId != null ? vnetworks.get(networkId) : null;
874     }
875
876     @Nullable
877     public Long getNetworkElanTag(Uuid networkId) {
878         Long elanTag = null;
879         IVirtualNetwork net = getNetwork(networkId);
880         if (null != net) {
881             elanTag = net.getElanTag();
882             if (null == elanTag) {
883                 elanTag = updateNetworkElanTag(networkId);
884             }
885         }
886         return elanTag;
887     }
888
889     @Nullable
890     public int getNetworkMtu(Uuid networkId) {
891         int mtu = 0;
892         IVirtualNetwork net = getNetwork(networkId);
893         if (null != net) {
894             mtu = net.getMtu();
895         }
896         return mtu;
897     }
898
899     public void addNetwork(Uuid networkId, int mtu) {
900         if (networkId == null) {
901             return;
902         }
903
904         if (vnetworks.putIfAbsent(networkId, new VirtualNetwork(networkId)) == null) {
905             updateNetworkMtuInfo(networkId, mtu);
906             updateNetworkElanTag(networkId);
907         }
908         Set<VirtualPort> intfList = removeUnprocessed(unprocessedNetIntfs, networkId);
909         if (intfList == null) {
910             LOG.info("No unprocessed interfaces for the net {}", networkId);
911             return;
912         }
913
914         for (VirtualPort intf : intfList) {
915             if (intf != null) {
916                 updateInterfaceDpidOfPortInfo(intf.getIntfUUID());
917             }
918         }
919
920         Set<Ipv6Address> ipv6Addresses =
921                 removeUnprocessedNSFlows(unprocessedNetNSFlowIntfs, networkId);
922
923         for (Ipv6Address ipv6Address : ipv6Addresses) {
924             programIcmpv6NSPuntFlowForAddress(networkId, ipv6Address, Ipv6ServiceConstants.ADD_FLOW);
925         }
926
927         Integer action = removeUnprocessedRSFlows(unprocessedNetRSFlowIntfs, networkId);
928         programIcmpv6RSPuntFlows(networkId, action);
929
930         Set<VirtualSubnet> subnets = removeUnprocessedNaFlows(networkId);
931         programIcmpv6NaPuntFlow(networkId, subnets, Ipv6ServiceConstants.ADD_FLOW);
932         for (VirtualSubnet subnet : subnets) {
933             programIcmpv6NaForwardFlows(networkId, subnet, action);
934         }
935     }
936
937     public void removeNetwork(Uuid networkId) {
938         // Delete the network and the corresponding dpnIds<-->List(ports) cache.
939         VirtualNetwork net = networkId != null ? vnetworks.remove(networkId) : null;
940         if (null != net && null != net.getNetworkUuid()) {
941             /* removing all RS flows when network gets removed, as the DPN-list is maintained only as part of
942             * network cache. After removal of network there is no way to remove them today. */
943             programIcmpv6RSPuntFlows(net.getNetworkUuid(), Ipv6ServiceConstants.DEL_FLOW);
944             removeAllIcmpv6NSPuntFlowForNetwork(net.getNetworkUuid());
945             net.removeSelf();
946         }
947         removeUnprocessed(unprocessedNetIntfs, networkId);
948         removeUnprocessedRSFlows(unprocessedNetRSFlowIntfs, networkId);
949         removeUnprocessedNSFlows(unprocessedNetNSFlowIntfs, networkId);
950     }
951
952     private void transmitRouterAdvertisement(VirtualPort intf, Ipv6RouterAdvertisementType advType) {
953         Ipv6RouterAdvt ipv6RouterAdvert = new Ipv6RouterAdvt(packetService, this);
954
955         VirtualNetwork vnet = getNetwork(intf.getNetworkID());
956         if (vnet != null) {
957             long elanTag = vnet.getElanTag();
958             Collection<VirtualNetwork.DpnInterfaceInfo> dpnIfaceList = vnet.getDpnIfaceList();
959             for (VirtualNetwork.DpnInterfaceInfo dpnIfaceInfo : dpnIfaceList) {
960                 LOG.debug("transmitRouterAdvertisement: Transmitting RA {} for ELAN Tag {}",
961                         advType, elanTag);
962                 if (dpnIfaceInfo.getDpId() != null) {
963                     ipv6RouterAdvert.transmitRtrAdvertisement(advType, intf, elanTag, null,
964                             dpnIfaceInfo.getDpId(), intf.getIntfUUID());
965                 }
966             }
967         }
968     }
969
970
971     private void removeAllIcmpv6NSPuntFlowForNetwork(Uuid networkId) {
972         Long elanTag = getNetworkElanTag(networkId);
973         VirtualNetwork vnet = vnetworks.get(networkId);
974         if (vnet == null) {
975             return;
976         }
977
978         Collection<VirtualNetwork.DpnInterfaceInfo> dpnIfaceList = vnet.getDpnIfaceList();
979
980         for (VirtualNetwork.DpnInterfaceInfo dpnIfaceInfo : dpnIfaceList) {
981             for (Ipv6Address ipv6Address : dpnIfaceInfo.ndTargetFlowsPunted) {
982                 if (ipv6ServiceEosHandler.isClusterOwner()) {
983                     ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpnIfaceInfo.getDpId(),
984                             elanTag, ipv6Address, Ipv6ServiceConstants.DEL_FLOW);
985                 }
986                 dpnIfaceInfo.updateNDTargetAddress(ipv6Address, Ipv6ServiceConstants.DEL_ENTRY);
987             }
988         }
989     }
990
991
992     public void transmitUnsolicitedRA(Uuid portId) {
993         VirtualPort port = getPort(portId);
994         LOG.debug("in transmitUnsolicitedRA for {}, port {}", portId, port);
995         if (port != null) {
996             transmitUnsolicitedRA(port);
997         }
998     }
999
1000     public void transmitUnsolicitedRA(VirtualPort port) {
1001         if (ipv6ServiceEosHandler.isClusterOwner()) {
1002             /* Only the Cluster Owner would be sending out the Periodic RAs.
1003                However, the timer is configured on all the nodes to handle cluster fail-over scenarios.
1004              */
1005             transmitRouterAdvertisement(port, Ipv6RouterAdvertisementType.UNSOLICITED_ADVERTISEMENT);
1006         }
1007         Timeout portTimeout = timer.setPeriodicTransmissionTimeout(port.getPeriodicTimer(),
1008                 Ipv6ServiceConstants.PERIODIC_RA_INTERVAL,
1009                 TimeUnit.SECONDS);
1010         port.setPeriodicTimeout(portTimeout);
1011         LOG.debug("re-started periodic RA Timer for routerIntf {}, int {}s", port.getIntfUUID(),
1012                 Ipv6ServiceConstants.PERIODIC_RA_INTERVAL);
1013     }
1014
1015     @Override
1016     public List<IVirtualPort> getInterfaceCache() {
1017         List<IVirtualPort> virtualPorts = new ArrayList<>();
1018         for (VirtualPort vport: vintfs.values()) {
1019             virtualPorts.add(vport);
1020         }
1021         return virtualPorts;
1022     }
1023
1024     @Override
1025     public List<IVirtualNetwork> getNetworkCache() {
1026         List<IVirtualNetwork> virtualNetworks = new ArrayList<>();
1027         for (VirtualNetwork vnet: vnetworks.values()) {
1028             virtualNetworks.add(vnet);
1029         }
1030         return virtualNetworks;
1031     }
1032
1033     @Override
1034     public List<IVirtualSubnet> getSubnetCache() {
1035         List<IVirtualSubnet> virtualSubnets = new ArrayList<>();
1036         for (VirtualSubnet vsubnet: vsubnets.values()) {
1037             virtualSubnets.add(vsubnet);
1038         }
1039         return virtualSubnets;
1040     }
1041
1042     @Override
1043     public List<IVirtualRouter> getRouterCache() {
1044         List<IVirtualRouter> virtualRouter = new ArrayList<>();
1045         for (VirtualRouter vrouter: vrouters.values()) {
1046             virtualRouter.add(vrouter);
1047         }
1048         return virtualRouter;
1049     }
1050
1051     public List<Action> getEgressAction(String interfaceName) {
1052         List<Action> actions = null;
1053         try {
1054             GetEgressActionsForInterfaceInputBuilder egressAction =
1055                     new GetEgressActionsForInterfaceInputBuilder().setIntfName(interfaceName);
1056             Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
1057                     interfaceManagerRpc.getEgressActionsForInterface(egressAction.build());
1058             RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
1059             if (!rpcResult.isSuccessful()) {
1060                 LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}",
1061                         interfaceName, rpcResult.getErrors());
1062             } else {
1063                 actions = rpcResult.getResult().getAction();
1064             }
1065         } catch (InterruptedException | ExecutionException e) {
1066             LOG.warn("Exception when egress actions for interface {}", interfaceName, e);
1067         }
1068         return actions;
1069     }
1070 }