c761dcd902f0b2bed10d0d399f34c4b1ccb2228c
[netvirt.git] / vpnservice / 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.net.InetAddresses;
12 import io.netty.util.Timeout;
13 import java.math.BigInteger;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.Future;
21 import java.util.concurrent.TimeUnit;
22 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
23 import org.opendaylight.genius.mdsalutil.MDSALUtil;
24 import org.opendaylight.genius.mdsalutil.NwConstants;
25 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
26 import org.opendaylight.netvirt.elanmanager.api.IElanService;
27 import org.opendaylight.netvirt.ipv6service.utils.Ipv6Constants;
28 import org.opendaylight.netvirt.ipv6service.utils.Ipv6Constants.Ipv6RtrAdvertType;
29 import org.opendaylight.netvirt.ipv6service.utils.Ipv6ServiceUtils;
30 import org.opendaylight.netvirt.ipv6service.utils.Ipv6TimerWheel;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInput;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInputBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexOutput;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
51 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
52 import org.opendaylight.yangtools.yang.common.RpcResult;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 public class IfMgr {
57     static final Logger LOG = LoggerFactory.getLogger(IfMgr.class);
58
59     private final Map<Uuid, VirtualRouter> vrouters = new HashMap<>();
60     private final Map<Uuid, VirtualNetwork> vnetworks = new HashMap<>();
61     private final Map<Uuid, VirtualSubnet> vsubnets = new HashMap<>();
62     private final Map<Uuid, VirtualPort> vintfs = new HashMap<>();
63     private final Map<Uuid, VirtualPort> vrouterv6IntfMap = new HashMap<>();
64     private final Map<Uuid, List<VirtualPort>> unprocessedRouterIntfs = new HashMap<>();
65     private final Map<Uuid, List<VirtualPort>> unprocessedSubnetIntfs = new HashMap<>();
66     private OdlInterfaceRpcService interfaceManagerRpc;
67     private IElanService elanProvider;
68     private IMdsalApiManager mdsalUtil;
69     private final Ipv6ServiceUtils ipv6ServiceUtils = new Ipv6ServiceUtils();
70     private DataBroker dataBroker;
71
72     private static IfMgr ifMgr;
73     private Ipv6ServiceUtils ipv6Utils = Ipv6ServiceUtils.getInstance();
74
75     private IfMgr() {
76         LOG.info("IfMgr is enabled");
77     }
78
79     public static IfMgr getIfMgrInstance() {
80         if (ifMgr == null) {
81             ifMgr = new IfMgr();
82         }
83         return ifMgr;
84     }
85
86     public static void setIfMgrInstance(IfMgr ifMgr) {
87         IfMgr.ifMgr = ifMgr;
88     }
89
90     public void setElanProvider(IElanService elanProvider) {
91         this.elanProvider = elanProvider;
92     }
93
94     public void setDataBroker(DataBroker dataBroker) {
95         this.dataBroker = dataBroker;
96     }
97
98     public void setMdsalUtilManager(IMdsalApiManager mdsalUtil) {
99         this.mdsalUtil = mdsalUtil;
100     }
101
102     public void setInterfaceManagerRpc(OdlInterfaceRpcService interfaceManagerRpc) {
103         LOG.trace("Registered interfaceManager successfully");
104         this.interfaceManagerRpc = interfaceManagerRpc;
105     }
106
107     /**
108      * Add router.
109      *
110      * @param rtrUuid router uuid
111      * @param rtrName router name
112      * @param tenantId tenant id
113      */
114     public void addRouter(Uuid rtrUuid, String rtrName, Uuid tenantId) {
115
116         VirtualRouter rtr = new VirtualRouter();
117
118         rtr.setTenantID(tenantId)
119                 .setRouterUUID(rtrUuid)
120                 .setName(rtrName);
121         vrouters.put(rtrUuid, rtr);
122
123         List<VirtualPort> intfList = unprocessedRouterIntfs.get(rtrUuid);
124
125         if (intfList == null) {
126             LOG.info("No unprocessed interfaces for the router {}", rtrUuid);
127             return;
128         }
129
130         for (VirtualPort intf : intfList) {
131             if (intf != null) {
132                 intf.setRouter(rtr);
133                 rtr.addInterface(intf);
134
135                 for (VirtualSubnet snet : intf.getSubnets()) {
136                     rtr.addSubnet(snet);
137                 }
138             }
139         }
140
141         removeUnprocessed(unprocessedRouterIntfs, rtrUuid);
142     }
143
144     /**
145      * Remove Router.
146      *
147      * @param rtrUuid router uuid
148      */
149     public void removeRouter(Uuid rtrUuid) {
150
151         VirtualRouter rtr = vrouters.get(rtrUuid);
152         if (rtr != null) {
153             rtr.removeSelf();
154             vrouters.remove(rtrUuid);
155             removeUnprocessed(unprocessedRouterIntfs, rtrUuid);
156         } else {
157             LOG.error("Delete router failed for :{}", rtrUuid);
158         }
159     }
160
161     /**
162      * Add Subnet.
163      *
164      * @param snetId subnet id
165      * @param name subnet name
166      * @param tenantId tenant id
167      * @param gatewayIp gateway ip address
168      * @param ipVersion IP Version "IPv4 or IPv6"
169      * @param subnetCidr subnet CIDR
170      * @param ipV6AddressMode Address Mode of IPv6 Subnet
171      * @param ipV6RaMode RA Mode of IPv6 Subnet.
172      */
173     public void addSubnet(Uuid snetId, String name, Uuid tenantId,
174                           IpAddress gatewayIp, String ipVersion, IpPrefix subnetCidr,
175                           String ipV6AddressMode, String ipV6RaMode) {
176
177         // Save the gateway ipv6 address in its fully expanded format. We always store the v6Addresses
178         // in expanded form and are used during Neighbor Discovery Support.
179         if (gatewayIp != null) {
180             Ipv6Address addr = new Ipv6Address(InetAddresses
181                     .forString(gatewayIp.getIpv6Address().getValue()).getHostAddress());
182             gatewayIp = new IpAddress(addr);
183         }
184
185         VirtualSubnet snet = new VirtualSubnet();
186         snet.setTenantID(tenantId)
187                 .setSubnetUUID(snetId)
188                 .setName(name)
189                 .setGatewayIp(gatewayIp)
190                 .setIPVersion(ipVersion)
191                 .setSubnetCidr(subnetCidr)
192                 .setIpv6AddressMode(ipV6AddressMode)
193                 .setIpv6RAMode(ipV6RaMode);
194
195         vsubnets.put(snetId, snet);
196
197         List<VirtualPort> intfList = unprocessedSubnetIntfs.get(snetId);
198         if (intfList == null) {
199             LOG.info("No unprocessed interfaces for the subnet {}", snetId);
200             return;
201         }
202         for (VirtualPort intf : intfList) {
203             if (intf != null) {
204                 intf.setSubnet(snetId, snet);
205                 snet.addInterface(intf);
206
207                 VirtualRouter rtr = intf.getRouter();
208                 if (rtr != null) {
209                     rtr.addSubnet(snet);
210                 }
211             }
212         }
213
214         removeUnprocessed(unprocessedSubnetIntfs, snetId);
215     }
216
217     /**
218      * Remove Subnet.
219      *
220      * @param snetId subnet id
221      */
222     public void removeSubnet(Uuid snetId) {
223         VirtualSubnet snet = vsubnets.get(snetId);
224         if (snet != null) {
225             LOG.info("removeSubnet is invoked for {}", snetId);
226             snet.removeSelf();
227             vsubnets.remove(snetId);
228             removeUnprocessed(unprocessedSubnetIntfs, snetId);
229         }
230     }
231
232     public void addRouterIntf(Uuid portId, Uuid rtrId, Uuid snetId,
233                               Uuid networkId, IpAddress fixedIp, String macAddress,
234                               String deviceOwner) {
235         LOG.debug("addRouterIntf portId {}, rtrId {}, snetId {}, networkId {}, ip {}, mac {}",
236             portId, rtrId, snetId, networkId, fixedIp, macAddress);
237         //Save the interface ipv6 address in its fully expanded format
238         Ipv6Address addr = new Ipv6Address(InetAddresses
239                 .forString(fixedIp.getIpv6Address().getValue()).getHostAddress());
240         fixedIp = new IpAddress(addr);
241
242         VirtualPort intf = vintfs.get(portId);
243         boolean newIntf = false;
244         if (intf == null) {
245             intf = new VirtualPort();
246             vintfs.put(portId, intf);
247             intf.setIntfUUID(portId)
248                     .setSubnetInfo(snetId, fixedIp)
249                     .setNetworkID(networkId)
250                     .setMacAddress(macAddress)
251                     .setRouterIntfFlag(true)
252                     .setDeviceOwner(deviceOwner);
253             intf.setPeriodicTimer();
254             newIntf = true;
255             MacAddress ifaceMac = MacAddress.getDefaultInstance(macAddress);
256             Ipv6Address llAddr = ipv6Utils.getIpv6LinkLocalAddressFromMac(ifaceMac);
257             /* A new router interface is created. This is basically triggered when an
258             IPv6 subnet is associated to the router. Check if network is already hosting
259             any VMs. If so, on all the hosts that have VMs on the network, program the
260             icmpv6 punt flows in IPV6_TABLE(45).
261              */
262             programIcmpv6RSPuntFlows(intf, Ipv6Constants.ADD_FLOW);
263             programIcmpv6NSPuntFlowForAddress(intf, llAddr, Ipv6Constants.ADD_FLOW);
264         } else {
265             intf.setSubnetInfo(snetId, fixedIp);
266         }
267
268         VirtualRouter rtr = vrouters.get(rtrId);
269         VirtualSubnet snet = vsubnets.get(snetId);
270
271         if (rtr != null && snet != null) {
272             snet.setRouter(rtr);
273             intf.setSubnet(snetId, snet);
274             rtr.addSubnet(snet);
275         } else if (snet != null) {
276             intf.setSubnet(snetId, snet);
277             addUnprocessed(unprocessedRouterIntfs, rtrId, intf);
278         } else {
279             addUnprocessed(unprocessedRouterIntfs, rtrId, intf);
280             addUnprocessed(unprocessedSubnetIntfs, snetId, intf);
281         }
282
283         vrouterv6IntfMap.put(networkId, intf);
284         programIcmpv6NSPuntFlowForAddress(intf, fixedIp.getIpv6Address(), Ipv6Constants.ADD_FLOW);
285
286         if (newIntf) {
287             LOG.debug("start the periodic RA Timer for routerIntf {}", portId);
288             transmitUnsolicitedRA(intf);
289         }
290     }
291
292     public void updateRouterIntf(Uuid portId, Uuid rtrId, List<FixedIps> fixedIpsList) {
293         LOG.info("updateRouterIntf portId {}, fixedIpsList {} ", portId, fixedIpsList);
294         VirtualPort intf = vintfs.get(portId);
295         if (intf == null) {
296             LOG.info("Skip Router interface update for non-ipv6 port {}", portId);
297             return;
298         }
299
300         List<Ipv6Address> existingIPv6AddressList = intf.getIpv6AddressesWithoutLLA();
301         List<Ipv6Address> newlyAddedIpv6AddressList = new ArrayList<>();
302         intf.clearSubnetInfo();
303         for (FixedIps fip : fixedIpsList) {
304             IpAddress fixedIp = fip.getIpAddress();
305
306             if (fixedIp.getIpv4Address() != null) {
307                 continue;
308             }
309
310             //Save the interface ipv6 address in its fully expanded format
311             Ipv6Address addr = new Ipv6Address(InetAddresses
312                     .forString(fixedIp.getIpv6Address().getValue()).getHostAddress());
313             fixedIp = new IpAddress(addr);
314             intf.setSubnetInfo(fip.getSubnetId(), fixedIp);
315
316             VirtualRouter rtr = vrouters.get(rtrId);
317             VirtualSubnet snet = vsubnets.get(fip.getSubnetId());
318
319             if (rtr != null && snet != null) {
320                 snet.setRouter(rtr);
321                 intf.setSubnet(fip.getSubnetId(), snet);
322                 rtr.addSubnet(snet);
323             } else if (snet != null) {
324                 intf.setSubnet(fip.getSubnetId(), snet);
325                 addUnprocessed(unprocessedRouterIntfs, rtrId, intf);
326             } else {
327                 addUnprocessed(unprocessedRouterIntfs, rtrId, intf);
328                 addUnprocessed(unprocessedSubnetIntfs, fip.getSubnetId(), intf);
329             }
330             vrouterv6IntfMap.put(intf.getNetworkID(), intf);
331
332             if (existingIPv6AddressList.contains(fixedIp.getIpv6Address())) {
333                 existingIPv6AddressList.remove(fixedIp.getIpv6Address());
334             } else {
335                 newlyAddedIpv6AddressList.add(fixedIp.getIpv6Address());
336             }
337         }
338
339         /* This is a port update event for routerPort. Check if any IPv6 subnet is added
340          or removed from the router port. Depending on subnet added/removed, we add/remove
341          the corresponding flows from IPV6_TABLE(45).
342          */
343         for (Ipv6Address ipv6Address: newlyAddedIpv6AddressList) {
344             // Some v6 subnets are associated to the routerPort add the corresponding NS Flows.
345             programIcmpv6NSPuntFlowForAddress(intf, ipv6Address, Ipv6Constants.ADD_FLOW);
346         }
347
348         for (Ipv6Address ipv6Address: existingIPv6AddressList) {
349             // Some v6 subnets are disassociated from the routerPort, remove the corresponding NS Flows.
350             programIcmpv6NSPuntFlowForAddress(intf, ipv6Address, Ipv6Constants.DEL_FLOW);
351         }
352     }
353
354     public void addHostIntf(Uuid portId, Uuid snetId, Uuid networkId,
355                             IpAddress fixedIp, String macAddress, String deviceOwner) {
356         LOG.debug("addHostIntf portId {}, snetId {}, networkId {}, ip {}, mac {}",
357             portId, snetId, networkId, fixedIp, macAddress);
358
359         //Save the interface ipv6 address in its fully expanded format
360         Ipv6Address addr = new Ipv6Address(InetAddresses
361                 .forString(fixedIp.getIpv6Address().getValue()).getHostAddress());
362         fixedIp = new IpAddress(addr);
363         VirtualPort intf = vintfs.get(portId);
364         if (intf == null) {
365             intf = new VirtualPort();
366             vintfs.put(portId, intf);
367             intf.setIntfUUID(portId)
368                     .setSubnetInfo(snetId, fixedIp)
369                     .setNetworkID(networkId)
370                     .setMacAddress(macAddress)
371                     .setRouterIntfFlag(false)
372                     .setDeviceOwner(deviceOwner);
373             Long elanTag = getNetworkElanTag(networkId);
374             // Do service binding for the port and set the serviceBindingStatus to true.
375             ipv6ServiceUtils.bindIpv6Service(dataBroker, portId.getValue(), elanTag, NwConstants.IPV6_TABLE);
376             intf.setServiceBindingStatus(Boolean.TRUE);
377
378             /* Update the intf dpnId/ofPort from the Operational Store */
379             updateInterfaceDpidOfPortInfo(portId);
380
381         } else {
382             intf.setSubnetInfo(snetId, fixedIp);
383         }
384
385         VirtualSubnet snet = vsubnets.get(snetId);
386
387         if (snet != null) {
388             intf.setSubnet(snetId, snet);
389         } else {
390             addUnprocessed(unprocessedSubnetIntfs, snetId, intf);
391         }
392     }
393
394     public void clearAnyExistingSubnetInfo(Uuid portId) {
395         VirtualPort intf = vintfs.get(portId);
396         if (intf != null) {
397             intf.clearSubnetInfo();
398         }
399     }
400
401     public void updateHostIntf(Uuid portId, Boolean portIncludesV6Address) {
402         VirtualPort intf = vintfs.get(portId);
403         if (intf == null) {
404             LOG.debug("Update Host interface failed. Could not get Host interface details {}", portId);
405             return;
406         }
407
408         /* If the VMPort initially included an IPv6 address (along with IPv4 address) and IPv6 address
409          was removed, we will have to unbind the service on the VM port. Similarly we do a ServiceBind
410          if required.
411           */
412         if (portIncludesV6Address) {
413             if (intf.getServiceBindingStatus() == Boolean.FALSE) {
414                 Long elanTag = getNetworkElanTag(intf.getNetworkID());
415                 LOG.info("In updateHostIntf, service binding for portId {}", portId);
416                 ipv6ServiceUtils.bindIpv6Service(dataBroker, portId.getValue(), elanTag, NwConstants.IPV6_TABLE);
417                 intf.setServiceBindingStatus(Boolean.TRUE);
418             }
419         } else {
420             LOG.info("In updateHostIntf, removing service binding for portId {}", portId);
421             ipv6ServiceUtils.unbindIpv6Service(dataBroker, portId.getValue());
422             intf.setServiceBindingStatus(Boolean.FALSE);
423         }
424     }
425
426     public void updateDpnInfo(Uuid portId, BigInteger dpId, Long ofPort) {
427         LOG.info("In updateDpnInfo portId {}, dpId {}, ofPort {}",
428             portId, dpId, ofPort);
429         VirtualPort intf = vintfs.get(portId);
430         if (intf != null) {
431             intf.setDpId(dpId.toString())
432                     .setOfPort(ofPort);
433
434             // Update the network <--> List[dpnIds, List<ports>] cache.
435             VirtualNetwork vnet = vnetworks.get(intf.getNetworkID());
436             if (null != vnet) {
437                 vnet.updateDpnPortInfo(dpId, ofPort, Ipv6Constants.ADD_ENTRY);
438             }
439         }
440     }
441
442     public void updateInterfaceDpidOfPortInfo(Uuid portId) {
443         LOG.debug("In updateInterfaceDpidOfPortInfo portId {}", portId);
444         Interface interfaceState = Ipv6ServiceUtils.getInterfaceStateFromOperDS(dataBroker, portId.getValue());
445         if (interfaceState == null) {
446             LOG.warn("In updateInterfaceDpidOfPortInfo, port info not found in Operational Store {}.", portId);
447             return;
448         }
449
450         List<String> ofportIds = interfaceState.getLowerLayerIf();
451         NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
452         BigInteger dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
453         if (!dpId.equals(Ipv6Constants.INVALID_DPID)) {
454             Long ofPort = MDSALUtil.getOfPortNumberFromPortName(nodeConnectorId);
455             updateDpnInfo(portId, dpId, ofPort);
456         }
457     }
458
459
460     public void removePort(Uuid portId) {
461         VirtualPort intf = vintfs.get(portId);
462         if (intf != null) {
463             intf.removeSelf();
464             if (intf.getDeviceOwner().equalsIgnoreCase(Ipv6Constants.NETWORK_ROUTER_INTERFACE)) {
465                 LOG.info("In removePort for router interface, portId {}", portId);
466                 MacAddress ifaceMac = MacAddress.getDefaultInstance(intf.getMacAddress());
467                 vrouterv6IntfMap.remove(intf.getNetworkID(), intf);
468                 /* Router port is deleted. Remove the corresponding icmpv6 punt flows on all
469                 the dpnIds which were hosting the VMs on the network.
470                  */
471                 programIcmpv6RSPuntFlows(intf, Ipv6Constants.DEL_FLOW);
472                 for (Ipv6Address ipv6Address: intf.getIpv6Addresses()) {
473                     programIcmpv6NSPuntFlowForAddress(intf, ipv6Address, Ipv6Constants.DEL_FLOW);
474                 }
475                 transmitRouterAdvertisement(intf, Ipv6RtrAdvertType.CEASE_ADVERTISEMENT);
476                 Ipv6TimerWheel timer = Ipv6TimerWheel.getInstance();
477                 timer.cancelPeriodicTransmissionTimeout(intf.getPeriodicTimeout());
478                 intf.resetPeriodicTimeout();
479                 LOG.debug("Reset the periodic RA Timer for intf {}", intf.getIntfUUID());
480             } else {
481                 LOG.info("In removePort for host interface, portId {}", portId);
482                 // Remove the serviceBinding entry for the port.
483                 ipv6ServiceUtils.unbindIpv6Service(dataBroker, portId.getValue());
484                 // Remove the portId from the (network <--> List[dpnIds, List <ports>]) cache.
485                 VirtualNetwork vnet = vnetworks.get(intf.getNetworkID());
486                 if (null != vnet) {
487                     BigInteger dpId = Ipv6ServiceUtils.getDataPathId(intf.getDpId());
488                     vnet.updateDpnPortInfo(dpId, intf.getOfPort(), Ipv6Constants.DEL_ENTRY);
489                 }
490             }
491             vintfs.remove(portId);
492         }
493     }
494
495     public void deleteInterface(Uuid interfaceUuid, String dpId) {
496         // Nothing to do for now
497     }
498
499     public void addUnprocessed(Map<Uuid, List<VirtualPort>> unprocessed, Uuid id, VirtualPort intf) {
500         unprocessed.computeIfAbsent(id, key -> new ArrayList<>()).add(intf);
501     }
502
503     public void removeUnprocessed(Map<Uuid, List<VirtualPort>> unprocessed, Uuid id) {
504         unprocessed.remove(id);
505     }
506
507     public VirtualPort getRouterV6InterfaceForNetwork(Uuid networkId) {
508         LOG.debug("obtaining the virtual interface for {}", networkId);
509         return (vrouterv6IntfMap.get(networkId));
510     }
511
512     public VirtualPort obtainV6Interface(Uuid id) {
513         VirtualPort intf = vintfs.get(id);
514         if (intf == null) {
515             return null;
516         }
517         for (VirtualSubnet snet : intf.getSubnets()) {
518             if (snet.getIpVersion().equals(Ipv6Constants.IP_VERSION_V6)) {
519                 return intf;
520             }
521         }
522         return null;
523     }
524
525     private void programIcmpv6RSPuntFlows(VirtualPort routerPort, int action) {
526         Long elanTag = getNetworkElanTag(routerPort.getNetworkID());
527         int flowStatus;
528         VirtualNetwork vnet = vnetworks.get(routerPort.getNetworkID());
529         if (vnet != null) {
530             List<BigInteger> dpnList = vnet.getDpnsHostingNetwork();
531             for (BigInteger dpId : dpnList) {
532                 flowStatus = vnet.getRSPuntFlowStatusOnDpnId(dpId);
533                 if (action == Ipv6Constants.ADD_FLOW && flowStatus == Ipv6Constants.FLOWS_NOT_CONFIGURED) {
534                     ipv6ServiceUtils.installIcmpv6RsPuntFlow(NwConstants.IPV6_TABLE, dpId, elanTag,
535                             mdsalUtil, Ipv6Constants.ADD_FLOW);
536                     vnet.setRSPuntFlowStatusOnDpnId(dpId, Ipv6Constants.FLOWS_CONFIGURED);
537                 } else if (action == Ipv6Constants.DEL_FLOW && flowStatus == Ipv6Constants.FLOWS_CONFIGURED) {
538                     ipv6ServiceUtils.installIcmpv6RsPuntFlow(NwConstants.IPV6_TABLE, dpId, elanTag,
539                             mdsalUtil, Ipv6Constants.DEL_FLOW);
540                     vnet.setRSPuntFlowStatusOnDpnId(dpId, Ipv6Constants.FLOWS_NOT_CONFIGURED);
541                 }
542             }
543         }
544     }
545
546     private void programIcmpv6NSPuntFlowForAddress(VirtualPort routerPort, Ipv6Address ipv6Address, int action) {
547         Long elanTag = getNetworkElanTag(routerPort.getNetworkID());
548         VirtualNetwork vnet = vnetworks.get(routerPort.getNetworkID());
549         if (vnet != null) {
550             Collection<VirtualNetwork.DpnInterfaceInfo> dpnIfaceList = vnet.getDpnIfaceList();
551             for (VirtualNetwork.DpnInterfaceInfo dpnIfaceInfo : dpnIfaceList) {
552                 if (action == Ipv6Constants.ADD_FLOW && !dpnIfaceInfo.ndTargetFlowsPunted.contains(ipv6Address)) {
553                     ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpnIfaceInfo.getDpId(),
554                             elanTag, ipv6Address.getValue(), mdsalUtil, Ipv6Constants.ADD_FLOW);
555                     dpnIfaceInfo.updateNDTargetAddress(ipv6Address, action);
556                 } else if (action == Ipv6Constants.DEL_FLOW && dpnIfaceInfo.ndTargetFlowsPunted.contains(ipv6Address)) {
557                     ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpnIfaceInfo.getDpId(),
558                             elanTag, ipv6Address.getValue(), mdsalUtil, Ipv6Constants.DEL_FLOW);
559                     dpnIfaceInfo.updateNDTargetAddress(ipv6Address, action);
560                 }
561             }
562         }
563     }
564
565     public void programIcmpv6PuntFlowsIfNecessary(Uuid vmPortId, BigInteger dpId, VirtualPort routerPort) {
566         VirtualPort vmPort = vintfs.get(vmPortId);
567         if (null != vmPort) {
568             VirtualNetwork vnet = vnetworks.get(vmPort.getNetworkID());
569             if (null != vnet) {
570                 VirtualNetwork.DpnInterfaceInfo dpnInfo = vnet.getDpnIfaceInfo(dpId);
571                 if (null != dpnInfo) {
572                     Long elanTag = getNetworkElanTag(routerPort.getNetworkID());
573                     if (vnet.getRSPuntFlowStatusOnDpnId(dpId) == Ipv6Constants.FLOWS_NOT_CONFIGURED) {
574                         ipv6ServiceUtils.installIcmpv6RsPuntFlow(NwConstants.IPV6_TABLE, dpId, elanTag,
575                                 mdsalUtil, Ipv6Constants.ADD_FLOW);
576                         vnet.setRSPuntFlowStatusOnDpnId(dpId, Ipv6Constants.FLOWS_CONFIGURED);
577                     }
578
579                     for (Ipv6Address ipv6Address: routerPort.getIpv6Addresses()) {
580                         if (!dpnInfo.ndTargetFlowsPunted.contains(ipv6Address)) {
581                             ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpId,
582                                     elanTag, ipv6Address.getValue(), mdsalUtil, Ipv6Constants.ADD_FLOW);
583                             dpnInfo.updateNDTargetAddress(ipv6Address, Ipv6Constants.ADD_FLOW);
584                         }
585                     }
586                 }
587             }
588         }
589     }
590
591     public String getInterfaceNameFromTag(long portTag) {
592         String interfaceName = null;
593         GetInterfaceFromIfIndexInput input = new GetInterfaceFromIfIndexInputBuilder()
594                 .setIfIndex((int) portTag).build();
595         Future<RpcResult<GetInterfaceFromIfIndexOutput>> futureOutput =
596                 interfaceManagerRpc.getInterfaceFromIfIndex(input);
597         try {
598             GetInterfaceFromIfIndexOutput output = futureOutput.get().getResult();
599             interfaceName = output.getInterfaceName();
600         } catch (InterruptedException | ExecutionException e) {
601             LOG.error("Error while retrieving the interfaceName from tag using getInterfaceFromIfIndex RPC");
602         }
603         LOG.trace("Returning interfaceName {} for tag {} form getInterfaceNameFromTag", interfaceName, portTag);
604         return interfaceName;
605     }
606
607     public Long updateNetworkElanTag(Uuid networkId) {
608         Long elanTag = null;
609         if (null != this.elanProvider) {
610             ElanInstance elanInstance = this.elanProvider.getElanInstance(networkId.getValue());
611             if (null != elanInstance) {
612                 elanTag = elanInstance.getElanTag();
613                 VirtualNetwork net = vnetworks.get(networkId);
614                 if (null != net) {
615                     net.setElanTag(elanTag);
616                 }
617             }
618         }
619         return elanTag;
620     }
621
622     public Long getNetworkElanTag(Uuid networkId) {
623         Long elanTag = null;
624         VirtualNetwork net = vnetworks.get(networkId);
625         if (null != net) {
626             elanTag = net.getElanTag();
627             if (null == elanTag) {
628                 elanTag = updateNetworkElanTag(networkId);
629             }
630         }
631         return elanTag;
632     }
633
634     public void addNetwork(Uuid networkId) {
635         VirtualNetwork net = vnetworks.get(networkId);
636         if (null == net) {
637             net = new VirtualNetwork();
638             net.setNetworkUuid(networkId);
639             vnetworks.put(networkId, net);
640             updateNetworkElanTag(networkId);
641         }
642     }
643
644     public void removeNetwork(Uuid networkId) {
645         // Delete the network and the corresponding dpnIds<-->List(ports) cache.
646         VirtualNetwork net = vnetworks.get(networkId);
647         if (null != net) {
648             net.removeSelf();
649             vnetworks.remove(networkId);
650         }
651     }
652
653     private void transmitRouterAdvertisement(VirtualPort intf, Ipv6RtrAdvertType advType) {
654         Ipv6RouterAdvt ipv6RouterAdvert = new Ipv6RouterAdvt();
655
656         LOG.debug("in transmitRouterAdvertisement for {}", advType);
657         VirtualNetwork vnet = vnetworks.get(intf.getNetworkID());
658         if (vnet != null) {
659             String nodeName;
660             String outPort;
661             Collection<VirtualNetwork.DpnInterfaceInfo> dpnIfaceList = vnet.getDpnIfaceList();
662             for (VirtualNetwork.DpnInterfaceInfo dpnIfaceInfo : dpnIfaceList) {
663                 nodeName = Ipv6Constants.OPENFLOW_NODE_PREFIX + dpnIfaceInfo.getDpId();
664                 List<NodeConnectorRef> ncRefList = new ArrayList<>();
665                 for (Long ofPort: dpnIfaceInfo.ofPortList) {
666                     outPort = nodeName + ":" + ofPort;
667                     LOG.debug("Transmitting RA {} for node {}, port {}", advType, nodeName, outPort);
668                     InstanceIdentifier<NodeConnector> outPortId = InstanceIdentifier.builder(Nodes.class)
669                             .child(Node.class, new NodeKey(new NodeId(nodeName)))
670                             .child(NodeConnector.class, new NodeConnectorKey(new NodeConnectorId(outPort)))
671                             .build();
672                     ncRefList.add(new NodeConnectorRef(outPortId));
673                 }
674                 if (!ncRefList.isEmpty()) {
675                     ipv6RouterAdvert.transmitRtrAdvertisement(advType, intf, ncRefList, null);
676                 }
677             }
678         }
679     }
680
681     public void transmitUnsolicitedRA(Uuid portId) {
682         VirtualPort port = vintfs.get(portId);
683         LOG.debug("in transmitUnsolicitedRA for {}, port", portId, port);
684         if (port != null) {
685             transmitUnsolicitedRA(port);
686         }
687     }
688
689     public void transmitUnsolicitedRA(VirtualPort port) {
690         transmitRouterAdvertisement(port, Ipv6RtrAdvertType.UNSOLICITED_ADVERTISEMENT);
691         Ipv6TimerWheel timer = Ipv6TimerWheel.getInstance();
692         Timeout portTimeout = timer.setPeriodicTransmissionTimeout(port.getPeriodicTimer(),
693                                                                    Ipv6Constants.PERIODIC_RA_INTERVAL,
694                                                                    TimeUnit.SECONDS);
695         port.setPeriodicTimeout(portTimeout);
696         LOG.debug("re-started periodic RA Timer for routerIntf {}, int {}s", port.getIntfUUID(),
697                    Ipv6Constants.PERIODIC_RA_INTERVAL);
698     }
699 }