2 * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.vpnmanager;
10 import com.google.common.base.*;
11 import com.google.common.collect.FluentIterable;
12 import com.google.common.collect.Iterators;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
15 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
16 import org.opendaylight.netvirt.bgpmanager.api.RouteOrigin;
17 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
18 import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
20 import com.google.common.util.concurrent.FutureCallback;
21 import com.google.common.util.concurrent.Futures;
22 import com.google.common.util.concurrent.JdkFutureAdapters;
24 import org.opendaylight.controller.md.sal.binding.api.*;
25 import org.opendaylight.genius.mdsalutil.*;
26 import org.opendaylight.genius.mdsalutil.AbstractDataChangeListener;
27 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.VpnTargets;
28 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
29 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentInputBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentOutput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.LabelRouteMap;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRoute;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRouteBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfo;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoKey;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.*;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.add.dpn.event.AddEventData;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.add.dpn.event.AddEventDataBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnListBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnListKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesListBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesListKey;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfacesBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfacesKey;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.remove.dpn.event.RemoveEventData;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.remove.dpn.event.RemoveEventDataBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
76 .VpnInstanceOpDataEntryBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesBuilder;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpResponseInput;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpResponseInputBuilder;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
95 import java.math.BigInteger;
96 import java.util.Collection;
97 import java.util.List;
98 import java.util.ArrayList;
99 import java.util.Arrays;
100 import java.util.Iterator;
101 import java.util.concurrent.*;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
106 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronvpnService;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
110 import org.opendaylight.yangtools.concepts.ListenerRegistration;
111 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
112 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
113 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
114 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
115 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
118 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
119 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
120 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
121 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
122 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
123 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
124 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
125 import org.opendaylight.yangtools.yang.common.RpcError;
126 import org.opendaylight.yangtools.yang.common.RpcResult;
127 import org.slf4j.Logger;
128 import org.slf4j.LoggerFactory;
130 public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface> implements AutoCloseable {
131 private static final Logger LOG = LoggerFactory.getLogger(VpnInterfaceManager.class);
132 private ListenerRegistration<DataChangeListener> listenerRegistration, opListenerRegistration, tunnelInterfaceStateListenerRegistration;
133 private final DataBroker broker;
134 private final IBgpManager bgpManager;
135 private IFibManager fibManager;
136 private IMdsalApiManager mdsalManager;
137 private OdlInterfaceRpcService ifaceMgrRpcService;
138 private ItmRpcService itmProvider;
139 private IdManagerService idManager;
140 private OdlArputilService arpManager;
141 private NeutronvpnService neuService;
142 private VpnSubnetRouteHandler vpnSubnetRouteHandler;
143 private ConcurrentHashMap<String, Runnable> vpnIntfMap = new ConcurrentHashMap<String, Runnable>();
144 private ExecutorService executorService = Executors.newSingleThreadExecutor();
145 private InterfaceStateChangeListener interfaceListener;
146 private SubnetRouteInterfaceStateChangeListener subnetRouteInterfaceListener;
147 private TunnelInterfaceStateListener tunnelInterfaceStateListener;
148 private VpnInterfaceOpListener vpnInterfaceOpListener;
149 private ArpNotificationHandler arpNotificationHandler;
150 private DpnInVpnChangeListener dpnInVpnChangeListener;
151 private NotificationPublishService notificationPublishService;
152 private FibRpcService fibService;
153 protected enum UpdateRouteAction {
154 ADVERTISE_ROUTE, WITHDRAW_ROUTE
158 * Responsible for listening to data change related to VPN Interface
159 * Bind VPN Service on the interface and informs the BGP service
161 * @param db - dataBroker service reference
162 * @param bgpManager Used to advertise routes to the BGP Router
163 * @param notificationService Used to subscribe to notification events
165 public VpnInterfaceManager(final DataBroker db, final IBgpManager bgpManager, NotificationService notificationService) {
166 super(VpnInterface.class);
168 this.bgpManager = bgpManager;
169 interfaceListener = new InterfaceStateChangeListener(db, this);
170 subnetRouteInterfaceListener = new SubnetRouteInterfaceStateChangeListener(db, this);
171 vpnInterfaceOpListener = new VpnInterfaceOpListener();
172 arpNotificationHandler = new ArpNotificationHandler(this, broker);
173 vpnSubnetRouteHandler = new VpnSubnetRouteHandler(broker, bgpManager, this);
174 dpnInVpnChangeListener = new DpnInVpnChangeListener(broker);
175 tunnelInterfaceStateListener = new TunnelInterfaceStateListener(broker, this);
176 notificationService.registerNotificationListener(vpnSubnetRouteHandler);
177 notificationService.registerNotificationListener(arpNotificationHandler);
178 notificationService.registerNotificationListener(dpnInVpnChangeListener);
179 registerListener(db);
182 public void setMdsalManager(IMdsalApiManager mdsalManager) {
183 this.mdsalManager = mdsalManager;
186 public void setIfaceMgrRpcService(OdlInterfaceRpcService ifMgrRpcService) {
187 this.ifaceMgrRpcService = ifMgrRpcService;
188 interfaceListener.setIfaceMgrRpcService(ifMgrRpcService);
191 public void setITMProvider(ItmRpcService itmProvider) {
192 this.itmProvider = itmProvider;
196 public void setFibManager(IFibManager fibManager) {
197 this.fibManager = fibManager;
200 public IFibManager getFibManager() {
201 return this.fibManager;
205 public void setIdManager(IdManagerService idManager) {
206 this.idManager = idManager;
207 vpnSubnetRouteHandler.setIdManager(idManager);
210 public void setArpManager(OdlArputilService arpManager) {
211 this.arpManager = arpManager;
214 void setNotificationPublishService(NotificationPublishService notificationPublishService) {
215 this.notificationPublishService = notificationPublishService;
218 public void setNeutronvpnManager(NeutronvpnService neuService) { this.neuService = neuService; }
220 public void setFibRpcService(FibRpcService fibService) {
221 this.fibService = fibService;
224 public FibRpcService getFibRpcService() {
228 public VpnSubnetRouteHandler getVpnSubnetRouteHandler() {
229 return this.vpnSubnetRouteHandler;
233 public void close() throws Exception {
234 if (listenerRegistration != null) {
236 listenerRegistration.close();
237 opListenerRegistration.close();
238 } catch (final Exception e) {
239 LOG.error("Error when cleaning up DataChangeListener.", e);
241 listenerRegistration = null;
242 opListenerRegistration = null;
244 LOG.info("VPN Interface Manager Closed");
247 private void registerListener(final DataBroker db) {
249 listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
250 getWildCardPath(), VpnInterfaceManager.this, DataChangeScope.SUBTREE);
251 opListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
252 getWildCardPath(), vpnInterfaceOpListener, DataChangeScope.SUBTREE);
253 tunnelInterfaceStateListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
254 getTunnelInterfaceStateListenerPath(), tunnelInterfaceStateListener, DataChangeScope.SUBTREE);
255 } catch (final Exception e) {
256 LOG.error("VPN Service DataChange listener registration fail!", e);
257 throw new IllegalStateException("VPN Service registration Listener failed.", e);
261 private InstanceIdentifier<StateTunnelList> getTunnelInterfaceStateListenerPath() {
262 return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
265 private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> getInterfaceListenerPath() {
266 return InstanceIdentifier.create(InterfacesState.class)
267 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class);
271 public void add(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface vpnInterface) {
272 LOG.trace("VPN Interface add event - key: {}, value: {}" ,identifier, vpnInterface );
273 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
274 String interfaceName = key.getName();
276 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState =
277 InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName);
278 if(interfaceState != null){
280 final BigInteger dpnId = InterfaceUtils.getDpIdFromInterface(interfaceState);
281 final int ifIndex = interfaceState.getIfIndex();
282 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
283 dataStoreCoordinator.enqueueJob("VPNINTERFACE-"+ interfaceName,
284 new Callable<List<ListenableFuture<Void>>>() {
286 public List<ListenableFuture<Void>> call() throws Exception {
287 WriteTransaction writeTxn = broker.newWriteOnlyTransaction();
288 processVpnInterfaceUp(dpnId, vpnInterface, ifIndex, false, writeTxn);
289 List<ListenableFuture<Void>> futures = new ArrayList<>();
290 futures.add(writeTxn.submit());
294 }catch (Exception e){
295 LOG.error("Unable to retrieve dpnId from interface operational data store for interface {}. ", interfaceName, e);
299 LOG.info("Handling addition of VPN interface {} skipped as interfaceState is not available", interfaceName);
303 protected void processVpnInterfaceUp(final BigInteger dpId, VpnInterface vpnInterface,
304 final int lPortTag, boolean isInterfaceUp, WriteTransaction writeTxn) {
306 final String interfaceName = vpnInterface.getName();
307 if (!isInterfaceUp) {
308 final String vpnName = vpnInterface.getVpnInstanceName();
309 LOG.info("Binding vpn service to interface {} ", interfaceName);
310 long vpnId = VpnUtil.getVpnId(broker, vpnName);
311 if (vpnId == VpnConstants.INVALID_ID) {
312 LOG.trace("VpnInstance to VPNId mapping is not yet available, bailing out now.");
315 boolean waitForVpnInterfaceOpRemoval = false;
317 VpnInterface opVpnInterface = null;
318 synchronized (interfaceName.intern()) {
319 opVpnInterface = VpnUtil.getOperationalVpnInterface(broker, vpnInterface.getName());
320 if (opVpnInterface != null ) {
321 String opVpnName = opVpnInterface.getVpnInstanceName();
322 String primaryInterfaceIp = null;
323 if(opVpnName.equals(vpnName)) {
324 // Please check if the primary VRF Entry does not exist for VPNInterface
325 // If so, we have to process ADD, as this might be a DPN Restart with Remove and Add triggered
327 // However, if the primary VRF Entry for this VPNInterface exists, please continue bailing out !
328 List<Adjacency> adjs = VpnUtil.getAdjacenciesForVpnInterfaceFromConfig(broker, interfaceName);
330 LOG.info("VPN Interface {} addition failed as adjacencies for this vpn interface could not be obtained", interfaceName);
333 numAdjs = adjs.size();
334 for (Adjacency adj : adjs) {
335 if (adj.getMacAddress() != null && !adj.getMacAddress().isEmpty()) {
336 primaryInterfaceIp = adj.getIpAddress();
340 if (primaryInterfaceIp == null) {
341 LOG.info("VPN Interface {} addition failed as primary adjacency for this vpn interface could not be obtained", interfaceName);
344 // Get the rd of the vpn instance
345 String rd = getRouteDistinguisher(opVpnName);
346 VrfEntry vrf = VpnUtil.getVrfEntry(broker, rd, primaryInterfaceIp);
348 LOG.info("VPN Interface {} already provisioned , bailing out from here.", interfaceName);
351 waitForVpnInterfaceOpRemoval = true;
353 LOG.info("vpn interface {} to go to configured vpn {}, but in operational vpn {}",
354 interfaceName, vpnName, opVpnName);
357 if (!waitForVpnInterfaceOpRemoval) {
358 // Add the VPNInterface and quit
359 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
360 dataStoreCoordinator.enqueueJob((interfaceName + dpId.toString()),
361 new UpdateDpnToVpnWorker(dpId, vpnName, interfaceName, lPortTag, true));
366 // FIB didn't get a chance yet to clean up this VPNInterface
367 // Let us give it a chance here !
368 LOG.info("VPN Interface {} waiting for FIB to clean up! ", interfaceName);
370 Runnable notifyTask = new VpnNotifyTask();
371 vpnIntfMap.put(interfaceName, notifyTask);
372 synchronized (notifyTask) {
374 notifyTask.wait(VpnConstants.MAX_WAIT_TIME_IN_MILLISECONDS);
375 } catch (InterruptedException e) {
379 vpnIntfMap.remove(interfaceName);
382 opVpnInterface = VpnUtil.getOperationalVpnInterface(broker, interfaceName);
383 if (opVpnInterface != null) {
384 LOG.error("VPN Interface {} removal by FIB did not complete on time, bailing addition ...", interfaceName);
387 // VPNInterface got removed, proceed with Add
388 synchronized (interfaceName.intern()) {
389 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
390 dataStoreCoordinator.enqueueJob((interfaceName + dpId.toString()),
391 new UpdateDpnToVpnWorker(dpId, vpnName, interfaceName, lPortTag, true));
394 synchronized (interfaceName.intern()) {
395 // Interface is retained in the DPN, but its Link Up.
396 // Advertise prefixes again for this interface to BGP
397 advertiseAdjacenciesForVpnToBgp(dpId, VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()),
398 vpnInterface, writeTxn);
404 private class UpdateDpnToVpnWorker implements Callable<List<ListenableFuture<Void>>> {
407 String interfaceName;
411 public UpdateDpnToVpnWorker(BigInteger dpnId, String vpnName, String interfaceName,
412 int lPortTag, boolean addToDpn) {
414 this.vpnName = vpnName;
415 this.interfaceName = interfaceName;
416 this.lPortTag = lPortTag;
417 this.addToDpn = addToDpn;
421 public List<ListenableFuture<Void>> call() throws Exception {
422 // If another renderer(for eg : CSS) needs to be supported, check can be performed here
423 // to call the respective helpers.
424 WriteTransaction writeTxn = broker.newWriteOnlyTransaction();
425 updateDpnDbs(dpnId, vpnName, interfaceName, addToDpn, writeTxn);
426 List<ListenableFuture<Void>> futures = new ArrayList<>();
427 futures.add(writeTxn.submit());
428 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
429 Futures.addCallback(listenableFuture,
430 new UpdateDpnToVpnCallback(dpnId, vpnName, interfaceName, lPortTag, addToDpn));
437 * JobCallback class is used as a future callback for
438 * main and rollback workers to handle success and failure.
440 private class UpdateDpnToVpnCallback implements FutureCallback<List<Void>> {
443 String interfaceName;
447 public UpdateDpnToVpnCallback(BigInteger dpnId, String vpnName, String interfaceName,
448 int lPortTag, boolean addToDpn) {
450 this.vpnName = vpnName;
451 this.interfaceName = interfaceName;
452 this.lPortTag = lPortTag;
453 this.addToDpn = addToDpn;
458 * This implies that all the future instances have returned success. -- TODO: Confirm this
461 public void onSuccess(List<Void> voids) {
462 WriteTransaction writeTxn = broker.newWriteOnlyTransaction();
463 bindService(dpnId, vpnName, interfaceName, lPortTag, writeTxn);
464 processVpnInterfaceAdjacencies(dpnId, vpnName, interfaceName, writeTxn);
471 * This method is used to handle failure callbacks.
472 * If more retry needed, the retrycount is decremented and mainworker is executed again.
473 * After retries completed, rollbackworker is executed.
474 * If rollbackworker fails, this is a double-fault. Double fault is logged and ignored.
478 public void onFailure(Throwable throwable) {
479 LOG.warn("Job: failed with exception: {}", throwable.getStackTrace());
484 private void advertiseAdjacenciesForVpnToBgp(BigInteger dpnId, final InstanceIdentifier<VpnInterface> identifier,
485 VpnInterface intf, WriteTransaction writeTxn) {
487 InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
488 Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
490 String rd = VpnUtil.getVpnRd(broker, intf.getVpnInstanceName());
492 LOG.error("advertiseAdjacenciesForVpnFromBgp: Unable to recover rd for interface {} in vpn {}",
493 intf.getName(), intf.getVpnInstanceName());
496 if (rd.equals(intf.getVpnInstanceName())) {
497 LOG.info("advertiseAdjacenciesForVpnFromBgp: Ignoring BGP advertisement for interface {} as it is in " +
498 "internal vpn{} with rd {}", intf.getName(), intf.getVpnInstanceName(), rd);
503 LOG.info("advertiseAdjacenciesForVpnToBgp: Advertising interface {} in vpn {} with rd {} ", intf.getName(),
504 intf.getVpnInstanceName(), rd);
506 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
507 if (nextHopIp == null){
508 LOG.trace("advertiseAdjacenciesForVpnToBgp: NextHop for interface {} is null, returning", intf.getName());
512 if (adjacencies.isPresent()) {
513 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
515 if (!nextHops.isEmpty()) {
516 LOG.trace("NextHops are " + nextHops);
517 for (Adjacency nextHop : nextHops) {
518 long label = nextHop.getLabel();
520 LOG.info("VPN ADVERTISE: Adding Fib Entry rd {} prefix {} nexthop {} label {}", rd, nextHop.getIpAddress(), nextHopIp, label);
521 bgpManager.advertisePrefix(rd, nextHop.getIpAddress(), nextHopIp, (int)label);
522 LOG.info("VPN ADVERTISE: Added Fib Entry rd {} prefix {} nexthop {} label {}", rd, nextHop.getIpAddress(), nextHopIp, label);
523 } catch(Exception e) {
524 LOG.error("Failed to advertise prefix {} in vpn {} with rd {} for interface {} ",
525 nextHop.getIpAddress(), intf.getVpnInstanceName(), rd, intf.getName(), e);
532 private void withdrawAdjacenciesForVpnFromBgp(final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
534 InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
535 Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
537 String rd = VpnUtil.getVpnRd(broker, intf.getVpnInstanceName());
539 LOG.error("withdrawAdjacenciesForVpnFromBgp: Unable to recover rd for interface {} in vpn {}",
540 intf.getName(), intf.getVpnInstanceName());
543 if (rd.equals(intf.getVpnInstanceName())) {
544 LOG.info("withdrawAdjacenciesForVpnFromBgp: Ignoring BGP withdrawal for interface {} as it is in " +
545 "internal vpn{} with rd {}", intf.getName(), intf.getVpnInstanceName(), rd);
549 LOG.info("withdrawAdjacenciesForVpnFromBgp: For interface {} in vpn {} with rd {}", intf.getName(),
550 intf.getVpnInstanceName(), rd);
551 if (adjacencies.isPresent()) {
552 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
554 if (!nextHops.isEmpty()) {
555 LOG.trace("NextHops are " + nextHops);
556 for (Adjacency nextHop : nextHops) {
558 LOG.info("VPN WITHDRAW: Removing Fib Entry rd {} prefix {}", rd, nextHop.getIpAddress());
559 bgpManager.withdrawPrefix(rd, nextHop.getIpAddress());
560 LOG.info("VPN WITHDRAW: Removed Fib Entry rd {} prefix {}", rd, nextHop.getIpAddress());
561 } catch(Exception e) {
562 LOG.error("Failed to withdraw prefix {} in vpn {} with rd {} for interface {} ",
563 nextHop.getIpAddress(), intf.getVpnInstanceName(), rd, intf.getName(), e);
570 private void updateDpnDbs(BigInteger dpId, String vpnName, String interfaceName, boolean add, WriteTransaction writeTxn) {
571 long vpnId = VpnUtil.getVpnId(broker, vpnName);
573 dpId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, interfaceName);
575 if(!dpId.equals(BigInteger.ZERO)) {
577 updateMappingDbs(vpnId, dpId, interfaceName, vpnName, writeTxn);
579 removeFromMappingDbs(vpnId, dpId, interfaceName, vpnName, writeTxn);
583 private void bindService(BigInteger dpId, String vpnInstanceName, String vpnInterfaceName, int lPortTag,
584 WriteTransaction writeTxn) {
585 int priority = VpnConstants.DEFAULT_FLOW_PRIORITY;
586 long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName);
588 int instructionKey = 0;
589 List<Instruction> instructions = new ArrayList<Instruction>();
591 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID, ++instructionKey));
592 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.L3_FIB_TABLE, ++instructionKey));
596 InterfaceUtils.getBoundServices(String.format("%s.%s.%s", "vpn",vpnInstanceName, vpnInterfaceName),
597 VpnConstants.L3VPN_SERVICE_IDENTIFIER, priority,
598 VpnConstants.COOKIE_VM_INGRESS_TABLE, instructions);
599 writeTxn.put(LogicalDatastoreType.CONFIGURATION,
600 InterfaceUtils.buildServiceId(vpnInterfaceName, VpnConstants.L3VPN_SERVICE_IDENTIFIER), serviceInfo, true);
601 makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
602 vpnId, ArpReplyOrRequest.REQUEST, NwConstants.ADD_FLOW, writeTxn);
603 makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
604 vpnId, ArpReplyOrRequest.REPLY, NwConstants.ADD_FLOW, writeTxn);
608 private void processVpnInterfaceAdjacencies(BigInteger dpnId, String vpnName, String interfaceName,
609 WriteTransaction writeTxn) {
610 InstanceIdentifier<VpnInterface> identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
612 synchronized (interfaceName) {
614 InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
615 Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
617 if (adjacencies.isPresent()) {
618 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
619 List<Adjacency> value = new ArrayList<>();
621 // Get the rd of the vpn instance
622 String rd = getRouteDistinguisher(vpnName);
624 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
625 if (nextHopIp == null){
626 LOG.error("NextHop for interface {} is null", interfaceName);
630 List<VpnInstance> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
632 LOG.trace("NextHops for interface {} are {}", interfaceName, nextHops);
633 for (Adjacency nextHop : nextHops) {
634 String prefix = VpnUtil.getIpPrefix(nextHop.getIpAddress());
635 long label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
636 VpnUtil.getNextHopLabelKey((rd == null) ? vpnName
638 List<String> adjNextHop = nextHop.getNextHopIpList();
639 value.add(new AdjacencyBuilder(nextHop).setLabel(label).setNextHopIpList(
640 (adjNextHop != null && !adjNextHop.isEmpty()) ? adjNextHop : Arrays.asList(nextHopIp))
641 .setIpAddress(prefix).setKey(new AdjacencyKey(prefix)).build());
643 if (nextHop.getMacAddress() != null && !nextHop.getMacAddress().isEmpty()) {
644 LOG.trace("Adding prefix {} to interface {} for vpn {}", prefix, interfaceName, vpnName);
646 LogicalDatastoreType.OPERATIONAL,
647 VpnUtil.getPrefixToInterfaceIdentifier(
648 VpnUtil.getVpnId(broker, vpnName), prefix),
649 VpnUtil.getPrefixToInterface(dpnId, interfaceName, prefix), true);
651 //Extra route adjacency
652 LOG.trace("Adding prefix {} and nexthopList {} as extra-route for vpn", nextHop.getIpAddress(), nextHop.getNextHopIpList(), vpnName);
654 LogicalDatastoreType.OPERATIONAL,
655 VpnUtil.getVpnToExtrarouteIdentifier(
656 (rd != null) ? rd : vpnName, nextHop.getIpAddress()),
657 VpnUtil.getVpnToExtraroute(nextHop.getIpAddress(), nextHop.getNextHopIpList()), true);
661 Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(value);
663 VpnInterface opInterface = VpnUtil.getVpnInterface(interfaceName, vpnName, aug, dpnId, Boolean.FALSE);
664 InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
665 writeTxn.put(LogicalDatastoreType.OPERATIONAL, interfaceId, opInterface, true);
666 long vpnId = VpnUtil.getVpnId(broker, vpnName);
668 for (Adjacency nextHop : aug.getAdjacency()) {
669 long label = nextHop.getLabel();
670 List<String> nextHopList = new ArrayList<>(nextHop.getNextHopIpList());
673 addToLabelMapper(label, dpnId, nextHop.getIpAddress(), nextHopList, vpnId,
674 interfaceName, null,false, rd);
675 addPrefixToBGP(rd, nextHop.getIpAddress(), nextHopIp, label, writeTxn);
676 //TODO: ERT - check for VPNs importing my route
677 for (VpnInstance vpn : vpnsToImportRoute) {
678 String vpnRd = vpn.getIpv4Family().getRouteDistinguisher();
680 LOG.debug("Exporting route with rd {} prefix {} nexthop {} label {} to VPN {}", vpnRd, nextHop.getIpAddress(), nextHopIp, label, vpn);
681 VpnUtil.addFibEntryToDS(broker, vpnRd, nextHop.getIpAddress(), nextHopIp, (int) label, RouteOrigin.SELF_IMPORTED, writeTxn);
685 // ### add FIB route directly
686 VpnUtil.addFibEntryToDS(broker, vpnName, nextHop.getIpAddress(), nextHopIp,
687 (int) label, RouteOrigin.STATIC, writeTxn);
694 private List<VpnInstance> getVpnsImportingMyRoute(final String vpnName) {
695 List<VpnInstance> vpnsToImportRoute = new ArrayList<>();
697 InstanceIdentifier<VpnInstance> id = InstanceIdentifier.builder(VpnInstances.class)
698 .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
699 Optional<VpnInstance> optVpnInstance = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
700 final VpnInstance vpnInstance;
701 if (optVpnInstance.isPresent()) {
702 vpnInstance = optVpnInstance.get();
704 LOG.debug("Could not retrieve vpn instance {} to check for vpns importing the routes", vpnName);
705 return vpnsToImportRoute;
708 Predicate<VpnInstance> excludeVpn = new Predicate<VpnInstance>() {
710 public boolean apply(VpnInstance input) {
711 return !input.getVpnInstanceName().equals(vpnName);
715 Predicate<VpnInstance> matchRTs = new Predicate<VpnInstance>() {
717 public boolean apply(VpnInstance input) {
718 Iterable<String> commonRTs = intersection(getRts(vpnInstance, VpnTarget.VrfRTType.ExportExtcommunity),
719 getRts(input, VpnTarget.VrfRTType.ImportExtcommunity));
720 return Iterators.size(commonRTs.iterator()) > 0;
724 Function<VpnInstance, String> toInstanceName = new Function<VpnInstance, String>() {
726 public String apply(VpnInstance vpnInstance) {
727 //return vpnInstance.getVpnInstanceName();
728 return vpnInstance.getIpv4Family().getRouteDistinguisher();
732 vpnsToImportRoute = FluentIterable.from(VpnUtil.getAllVpnInstance(broker)).
734 filter(matchRTs).toList();
735 return vpnsToImportRoute;
738 private List<VpnInstance> getVpnsExportingMyRoute(final String vpnName) {
739 List<VpnInstance> vpnsToExportRoute = new ArrayList<>();
741 InstanceIdentifier<VpnInstance> id = InstanceIdentifier.builder(VpnInstances.class)
742 .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
743 Optional<VpnInstance> optVpnInstance = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
744 final VpnInstance vpnInstance;
745 if (optVpnInstance.isPresent()) {
746 vpnInstance = optVpnInstance.get();
748 LOG.debug("Could not retrieve vpn instance {} to check for vpns exporting the routes", vpnName);
749 return vpnsToExportRoute;
752 Predicate<VpnInstance> excludeVpn = new Predicate<VpnInstance>() {
754 public boolean apply(VpnInstance input) {
755 return !input.getVpnInstanceName().equals(vpnName);
759 Predicate<VpnInstance> matchRTs = new Predicate<VpnInstance>() {
761 public boolean apply(VpnInstance input) {
762 Iterable<String> commonRTs = intersection(getRts(vpnInstance, VpnTarget.VrfRTType.ImportExtcommunity),
763 getRts(input, VpnTarget.VrfRTType.ExportExtcommunity));
764 return Iterators.size(commonRTs.iterator()) > 0;
768 Function<VpnInstance, String> toInstanceName = new Function<VpnInstance, String>() {
770 public String apply(VpnInstance vpnInstance) {
771 return vpnInstance.getVpnInstanceName();
775 vpnsToExportRoute = FluentIterable.from(VpnUtil.getAllVpnInstance(broker)).
777 filter(matchRTs).toList();
778 return vpnsToExportRoute;
781 private <T> Iterable<T> intersection(final Collection<T> collection1, final Collection<T> collection2) {
782 final Predicate<T> inPredicate = Predicates.<T>in(collection2);
783 return new Iterable<T>() {
785 public Iterator<T> iterator() {
786 return Iterators.filter(collection1.iterator(), inPredicate);
791 private List<String> getRts(VpnInstance vpnInstance, VpnTarget.VrfRTType rtType) {
792 String name = vpnInstance.getVpnInstanceName();
793 List<String> rts = new ArrayList<>();
794 VpnAfConfig vpnConfig = vpnInstance.getIpv4Family();
795 if (vpnConfig == null) {
796 LOG.trace("vpn config is not available for {}", name);
799 VpnTargets targets = vpnConfig.getVpnTargets();
800 if (targets == null) {
801 LOG.trace("vpn targets not available for {}", name);
804 List<VpnTarget> vpnTargets = targets.getVpnTarget();
805 if (vpnTargets == null) {
806 LOG.trace("vpnTarget values not available for {}", name);
809 for (VpnTarget target : vpnTargets) {
810 //TODO: Check for RT type is Both
811 if(target.getVrfRTType().equals(rtType) ||
812 target.getVrfRTType().equals(VpnTarget.VrfRTType.Both)) {
813 String rtValue = target.getVrfRTValue();
820 private List<String> getExportRts(VpnInstance vpnInstance) {
821 List<String> exportRts = new ArrayList<>();
822 VpnAfConfig vpnConfig = vpnInstance.getIpv4Family();
823 VpnTargets targets = vpnConfig.getVpnTargets();
824 List<VpnTarget> vpnTargets = targets.getVpnTarget();
825 for (VpnTarget target : vpnTargets) {
826 if (target.getVrfRTType().equals(VpnTarget.VrfRTType.ExportExtcommunity)) {
827 String rtValue = target.getVrfRTValue();
828 exportRts.add(rtValue);
834 private void makeArpFlow(BigInteger dpId,short sIndex, int lPortTag, String vpnInterfaceName,
835 long vpnId, ArpReplyOrRequest replyOrRequest, int addOrRemoveFlow, WriteTransaction writeTxn){
836 List<MatchInfo> matches = new ArrayList<MatchInfo>();
837 BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lPortTag, ++sIndex, BigInteger.valueOf(vpnId));
838 BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
839 MetaDataUtil.METADATA_MASK_LPORT_TAG, MetaDataUtil.METADATA_MASK_VRFID);
841 // Matching Arp reply flows
842 matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_ARP }));
843 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
844 metadata, metadataMask }));
846 matches.add(new MatchInfo(MatchFieldType.arp_op, new long[] { replyOrRequest.getArpOperation() }));
848 // Instruction to punt to controller
849 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
850 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
851 actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[] {}));
852 actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[]{
853 Short.toString(NwConstants.LPORT_DISPATCHER_TABLE)}));
855 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
857 // Install the flow entry in L3_INTERFACE_TABLE
858 String flowRef = VpnUtil.getFlowRef(dpId, NwConstants.L3_INTERFACE_TABLE,
859 NwConstants.ETHTYPE_ARP, lPortTag, replyOrRequest.getArpOperation());
860 FlowEntity flowEntity;
861 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_INTERFACE_TABLE, flowRef,
862 NwConstants.DEFAULT_ARP_FLOW_PRIORITY, replyOrRequest.getName(), 0, 0,
863 VpnUtil.getCookieArpFlow(lPortTag), matches, instructions);
864 Flow flow = flowEntity.getFlowBuilder().build();
865 String flowId = flowEntity.getFlowId();
866 FlowKey flowKey = new FlowKey( new FlowId(flowId));
867 Node nodeDpn = buildDpnNode(dpId);
869 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
870 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
871 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
873 if (writeTxn != null) {
874 if (addOrRemoveFlow == NwConstants.ADD_FLOW) {
875 LOG.debug("Creating ARP Flow for interface {}", vpnInterfaceName);
876 writeTxn.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
878 LOG.debug("Deleting ARP Flow for interface {}", vpnInterfaceName);
879 writeTxn.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
882 if (addOrRemoveFlow == NwConstants.ADD_FLOW) {
883 LOG.debug("Creating ARP Flow for interface {}",vpnInterfaceName);
884 mdsalManager.installFlow(flowEntity);
886 LOG.debug("Deleting ARP Flow for interface {}",vpnInterfaceName);
887 mdsalManager.removeFlow(flowEntity);
892 //TODO: How to handle the below code, its a copy paste from MDSALManager.java
893 private Node buildDpnNode(BigInteger dpnId) {
894 NodeId nodeId = new NodeId("openflow:" + dpnId);
895 Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
900 private String getRouteDistinguisher(String vpnName) {
901 InstanceIdentifier<VpnInstance> id = InstanceIdentifier.builder(VpnInstances.class)
902 .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
903 Optional<VpnInstance> vpnInstance = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
905 if(vpnInstance.isPresent()) {
906 VpnInstance instance = vpnInstance.get();
907 VpnAfConfig config = instance.getIpv4Family();
908 rd = config.getRouteDistinguisher();
913 private void updateMappingDbs(long vpnId, BigInteger dpnId, String intfName, String vpnName,
914 WriteTransaction writeTxn) {
915 String routeDistinguisher = getRouteDistinguisher(vpnName);
916 String rd = (routeDistinguisher == null) ? vpnName : routeDistinguisher;
917 synchronized (vpnName.intern()) {
918 InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
919 Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
920 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op
921 .data.entry.vpn.to.dpn.list.VpnInterfaces
922 vpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
924 if (dpnInVpn.isPresent()) {
925 if (writeTxn != null) {
926 writeTxn.put(LogicalDatastoreType.OPERATIONAL, id.child(
927 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance
928 .op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
929 new VpnInterfacesKey(intfName)), vpnInterface, true);
931 VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id.child(
932 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance
933 .op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
934 new VpnInterfacesKey(intfName)), vpnInterface);
939 * Increment the active dpn count in VpnInstanceOpData.
940 * ActiveDpnCount will be decremented when all the VpnInt in that Dpn are removed.
942 InstanceIdentifier<VpnInstanceOpDataEntry> vpnInsOpDataId = VpnUtil.getVpnInstanceOpDataIdentifier(rd);
943 Optional<VpnInstanceOpDataEntry> vpnInstOpData = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, vpnInsOpDataId);
945 java.lang.Long activeDpnCnt = vpnInstOpData.get().getActiveDpnCount();
947 VpnInstanceOpDataEntryBuilder builder =
948 new VpnInstanceOpDataEntryBuilder(vpnInstOpData.get()).setVrfId(rd).setVpnId(vpnId).setVpnInstanceName(vpnName).setActiveDpnCount(++activeDpnCnt);
950 if (writeTxn != null) {
951 writeTxn.merge(LogicalDatastoreType.OPERATIONAL,
953 builder.build(), true);
955 VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
960 VpnToDpnListBuilder vpnToDpnList = new VpnToDpnListBuilder().setDpnId(dpnId).setDpnState(VpnToDpnList.DpnState.Active);
961 List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
962 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = new ArrayList<>();
963 vpnInterfaces.add(vpnInterface);
964 if (writeTxn != null) {
965 writeTxn.merge(LogicalDatastoreType.OPERATIONAL, id,
966 vpnToDpnList.setVpnInterfaces(vpnInterfaces).build(), true);
968 VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, id,
969 vpnToDpnList.setVpnInterfaces(vpnInterfaces).build());
972 * FIXME: DC Gateway tunnel should be built dynamically
973 //this is the first VM in this VPN on the DPN, may be a new DPN has come up,
974 //if tunnel to DC GW does not exist, create it
975 //if(!tunnelExists(dpnID, bgpManager.getDCGWIP()))
976 String dcGW = bgpManager.getDCGwIP();
977 if(dcGW != null && !dcGW.isEmpty())
979 LOG.debug("Building tunnel from DPN {} to DC GW {}", dpnId, dcGW);
980 itmProvider.buildTunnelFromDPNToDCGW(dpnId, new IpAddress(dcGW.toCharArray()));
982 fibManager.populateFibOnNewDpn(dpnId, vpnId, (rd == null) ? vpnName : rd);
983 publishAddNotification(dpnId, vpnName, rd);
984 //TODO: IRT - import local routes to vpn. check for the VPNs exporting the routes
985 //FIXME: do we need to handle here. since already routes are imported to this vpn
991 void handleVpnsExportingRoutes(String vpnName, String vpnRd) {
992 List<VpnInstance> vpnsToExportRoute = getVpnsExportingMyRoute(vpnName);
993 long vpnId = VpnUtil.getVpnId(broker, vpnName);
994 for (VpnInstance vpn : vpnsToExportRoute) {
995 String rd = vpn.getIpv4Family().getRouteDistinguisher();
996 long exportingVpnId = VpnUtil.getVpnId(broker, vpn.getVpnInstanceName());
997 List<VrfEntry> vrfEntries = VpnUtil.getAllVrfEntries(broker, vpn.getIpv4Family().getRouteDistinguisher());
998 if (vrfEntries != null) {
999 for (VrfEntry vrfEntry : vrfEntries) {
1001 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.STATIC) {
1004 String prefix = vrfEntry.getDestPrefix();
1005 long label = vrfEntry.getLabel();
1006 List<String> nextHops = vrfEntry.getNextHopAddressList();
1007 SubnetRoute route = vrfEntry.getAugmentation(SubnetRoute.class);
1008 for (String nh : nextHops) {
1009 if (route != null) {
1010 LOG.info("Importing subnet route fib entry rd {} prefix {} nexthop {} label {} to vpn {}", vpnRd, prefix, nh, label, vpn.getVpnInstanceName());
1011 importSubnetRouteForNewVpn(rd, prefix, nh, (int)label, route);
1013 LOG.info("Importing fib entry rd {} prefix {} nexthop {} label {} to vpn {}", vpnRd, prefix, nh, label, vpn.getVpnInstanceName());
1014 VpnUtil.addFibEntryToDS(broker, vpnRd, prefix, nh, (int)label, RouteOrigin
1015 .SELF_IMPORTED, null);
1018 } catch (Exception e) {
1019 LOG.error("Exception occurred while importing route with prefix {} label {} nexthop {} from vpn {} to vpn {}", vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(), vpn.getVpnInstanceName(), vpnName);
1023 LOG.info("No vrf entries to import from vpn {} with rd {}", vpn.getVpnInstanceName(), vpn.getIpv4Family().getRouteDistinguisher());
1028 private void removeFromMappingDbs(long vpnId, BigInteger dpnId, String intfName, String vpnName,
1029 WriteTransaction writeTxn) {
1030 //TODO: Delay 'DPN' removal so that other services can cleanup the entries for this dpn
1031 synchronized (vpnName.intern()) {
1032 String rd = VpnUtil.getVpnRd(broker, vpnName);
1033 InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
1034 Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
1035 if (dpnInVpn.isPresent()) {
1036 List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
1037 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
1038 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn
1039 .instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
1040 currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
1042 if (vpnInterfaces.remove(currVpnInterface)) {
1043 if (vpnInterfaces.isEmpty()) {
1044 List<IpAddresses> ipAddresses = dpnInVpn.get().getIpAddresses();
1045 if (ipAddresses == null || ipAddresses.isEmpty()) {
1048 * Mark the DPN state as Inactive as the Vpnintf list is empty.
1049 * This DPN will be removed in DpnToVpnChangeListner only if its
1050 * inactive and ActiveDpnCount is zero.
1052 VpnToDpnListBuilder vpnToDpnList =
1053 new VpnToDpnListBuilder(dpnInVpn.get())
1055 .setDpnState(VpnToDpnList.DpnState.Inactive)
1056 .setVpnInterfaces(vpnInterfaces);
1058 if (writeTxn != null) {
1059 writeTxn.merge(LogicalDatastoreType.OPERATIONAL, id , vpnToDpnList.build(), true);
1061 VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, id, vpnToDpnList.build());
1064 InstanceIdentifier<VpnInstanceOpDataEntry> vpnInstOpDataId = VpnUtil.getVpnInstanceOpDataIdentifier(rd);
1065 Optional<VpnInstanceOpDataEntry> vpnInstOpData = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, vpnInstOpDataId);
1067 java.lang.Long activeDpnCnt = vpnInstOpData.get().getActiveDpnCount();
1069 VpnInstanceOpDataEntryBuilder builder =
1070 new VpnInstanceOpDataEntryBuilder(vpnInstOpData.get()).setVrfId(rd).setVpnId(vpnId).setVpnInstanceName(vpnName).setActiveDpnCount(--activeDpnCnt);
1072 if (writeTxn != null) {
1073 writeTxn.merge(LogicalDatastoreType.OPERATIONAL, vpnInstOpDataId , builder.build(), true);
1075 VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, vpnInstOpDataId, builder.build());
1078 LOG.debug("Sending cleanup event for dpn {} in VPN {}", dpnId, vpnName);
1079 fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd);
1080 publishRemoveNotification(dpnId, vpnName, rd);
1082 LOG.debug("vpn interfaces are empty but ip addresses are present for the vpn {} in dpn {}", vpnName, dpnId);
1085 if (writeTxn != null) {
1086 writeTxn.delete(LogicalDatastoreType.OPERATIONAL, id.child(
1087 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op
1089 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
1090 new VpnInterfacesKey(intfName)));
1092 VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
1093 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
1094 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
1095 new VpnInterfacesKey(intfName)), VpnUtil.DEFAULT_CALLBACK);
1103 private void addPrefixToBGP(String rd, String prefix, String nextHopIp, long label, WriteTransaction writeTxn) {
1106 LOG.info("ADD: Adding Fib entry rd {} prefix {} nextHop {} label {}", rd, prefix, nextHopIp, label);
1107 VpnUtil.addFibEntryToDS(broker, rd, prefix, nextHopIp, (int)label, RouteOrigin.STATIC, writeTxn);
1108 bgpManager.advertisePrefix(rd, prefix, Arrays.asList(nextHopIp), (int)label);
1109 LOG.info("ADD: Added Fib entry rd {} prefix {} nextHop {} label {}", rd, prefix, nextHopIp, label);
1110 } catch(Exception e) {
1111 LOG.error("Add prefix failed", e);
1116 private InstanceIdentifier<VpnInterface> getWildCardPath() {
1117 return InstanceIdentifier.create(VpnInterfaces.class).child(VpnInterface.class);
1121 public void remove( InstanceIdentifier<VpnInterface> identifier, VpnInterface vpnInterface) {
1122 LOG.trace("Remove event - key: {}, value: {}" ,identifier, vpnInterface );
1123 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
1124 final String interfaceName = key.getName();
1126 InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
1127 Optional<VpnInterface> existingVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, interfaceId);
1128 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState =
1129 InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName);
1130 if (existingVpnInterface.isPresent()){
1131 BigInteger dpnId = BigInteger.ZERO;
1132 Boolean dpnIdRetrieved = Boolean.FALSE;
1133 if(interfaceState != null){
1135 dpnId = InterfaceUtils.getDpIdFromInterface(interfaceState);
1136 dpnIdRetrieved = Boolean.TRUE;
1137 }catch (Exception e){
1138 LOG.error("Unable to retrieve dpnId from interface operational data store for interface {}. Fetching from vpn interface op data store. ", interfaceName, e);
1141 LOG.error("Unable to retrieve interfaceState for interface {} , quitting ", interfaceName);
1144 if(dpnIdRetrieved == Boolean.FALSE){
1145 LOG.info("dpnId for {} has not been retrieved yet. Fetching from vpn interface operational DS", interfaceName);
1146 dpnId = existingVpnInterface.get().getDpnId();
1148 final int ifIndex = interfaceState.getIfIndex();
1149 final BigInteger dpId = dpnId;
1150 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1151 dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + interfaceName,
1152 new Callable<List<ListenableFuture<Void>>>() {
1154 public List<ListenableFuture<Void>> call() throws Exception {
1155 WriteTransaction writeTxn = broker.newWriteOnlyTransaction();
1156 processVpnInterfaceDown(dpId, interfaceName, ifIndex, false, true, writeTxn);
1157 List<ListenableFuture<Void>> futures = new ArrayList<>();
1158 futures.add(writeTxn.submit());
1159 waitForFibToRemoveVpnPrefix(interfaceName);
1163 //processVpnInterfaceDown(dpnId, interfaceName, interfaceState.getIfIndex(), false, true);
1165 LOG.warn("VPN interface {} was unavailable in operational data store to handle remove event", interfaceName);
1169 protected void processVpnInterfaceDown(BigInteger dpId, String interfaceName, int lPortTag, boolean isInterfaceStateDown,
1170 boolean isConfigRemoval, WriteTransaction writeTxn) {
1171 InstanceIdentifier<VpnInterface> identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
1172 if (!isInterfaceStateDown) {
1173 synchronized (interfaceName.intern()) {
1174 VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(broker, interfaceName);
1175 if(vpnInterface == null){
1176 LOG.info("Unable to process delete/down for interface {} as it is not available in operational data store", interfaceName);
1179 final String vpnName = vpnInterface.getVpnInstanceName();
1180 if(!vpnInterface.isScheduledForRemove()){
1181 VpnUtil.updateVpnInterface(broker, interfaceName, dpId, vpnName, Boolean.TRUE, writeTxn);
1182 removeAdjacenciesFromVpn(dpId, interfaceName, vpnInterface.getVpnInstanceName(), writeTxn);
1183 LOG.info("Unbinding vpn service from interface {} ", interfaceName);
1184 unbindService(dpId, vpnName, interfaceName, lPortTag, isInterfaceStateDown, isConfigRemoval, writeTxn);
1186 LOG.info("Unbinding vpn service for interface {} has already been scheduled by a different event ", interfaceName);
1192 synchronized (interfaceName.intern()) {
1193 // Interface is retained in the DPN, but its Link Down.
1194 // Only withdraw the prefixes for this interface from BGP
1195 VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(broker, interfaceName);
1196 if(vpnInterface == null){
1197 LOG.info("Unable to withdraw adjacencies for vpn interface {} from BGP as it is not available in operational data store", interfaceName);
1200 withdrawAdjacenciesForVpnFromBgp(identifier, vpnInterface);
1207 private void waitForFibToRemoveVpnPrefix(String interfaceName) {
1208 // FIB didn't get a chance yet to clean up this VPNInterface
1209 // Let us give it a chance here !
1210 LOG.info("VPN Interface {} removal waiting for FIB to clean up ! ", interfaceName);
1212 Runnable notifyTask = new VpnNotifyTask();
1213 vpnIntfMap.put(interfaceName, notifyTask);
1214 synchronized (notifyTask) {
1216 notifyTask.wait(VpnConstants.PER_INTERFACE_MAX_WAIT_TIME_IN_MILLISECONDS);
1217 } catch (InterruptedException e) {
1221 vpnIntfMap.remove(interfaceName);
1225 private void removeAdjacenciesFromVpn(final BigInteger dpnId, final String interfaceName, final String vpnName,
1226 WriteTransaction writeTxn) {
1228 InstanceIdentifier<VpnInterface> identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
1229 InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
1230 Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
1232 String rd = VpnUtil.getVpnRd(broker, vpnName);
1233 LOG.trace("removeAdjacenciesFromVpn: For interface {} RD recovered for vpn {} as rd {}", interfaceName,
1235 if (adjacencies.isPresent()) {
1236 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
1238 if (!nextHops.isEmpty()) {
1239 LOG.trace("NextHops are " + nextHops);
1240 for (Adjacency nextHop : nextHops) {
1241 List<String> nhList = new ArrayList<String>();
1242 if (nextHop.getMacAddress() == null || nextHop.getMacAddress().isEmpty()) {
1243 // This is either an extra-route (or) a learned IP via subnet-route
1244 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
1245 if (nextHopIp == null || nextHopIp.isEmpty()) {
1246 LOG.error("Unable to obtain nextHopIp for extra-route/learned-route in rd {} prefix {}",
1247 rd, nextHop.getIpAddress());
1250 nhList = Arrays.asList(nextHopIp);
1252 // This is a primary adjacency
1253 nhList = nextHop.getNextHopIpList();
1255 if (rd.equals(vpnName)) {
1256 //this is an internal vpn - the rd is assigned to the vpn instance name;
1257 //remove from FIB directly
1258 for(String nh : nhList) {
1259 VpnUtil.removeFibEntryFromDS(broker, vpnName, nextHop.getIpAddress(), nh, writeTxn);
1262 List<VpnInstance> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
1263 for (String nh : nextHop.getNextHopIpList()) {
1264 //IRT: remove routes from other vpns importing it
1265 removePrefixFromBGP(rd, nextHop.getIpAddress(), nh, writeTxn);
1266 for (VpnInstance vpn : vpnsToImportRoute) {
1267 String vpnRd = vpn.getIpv4Family().getRouteDistinguisher();
1268 if (vpnRd != null) {
1269 LOG.info("Removing Exported route with rd {} prefix {} from VPN {}", vpnRd, nextHop.getIpAddress(), vpn.getVpnInstanceName());
1270 VpnUtil.removeFibEntryFromDS(broker, vpnRd, nextHop.getIpAddress(), nh, writeTxn);
1275 String ip = nextHop.getIpAddress().split("/")[0];
1276 VpnPortipToPort vpnPortipToPort = VpnUtil.getNeutronPortFromVpnPortFixedIp(broker,
1278 if (vpnPortipToPort != null && !vpnPortipToPort.isConfig()) {
1279 LOG.trace("VpnInterfaceManager removing adjacency for Interface {} ip {} from VpnPortData Entry",
1280 vpnPortipToPort.getPortName(),ip);
1281 VpnUtil.removeVpnPortFixedIpToPort(broker, vpnName, ip);
1289 private void unbindService(BigInteger dpId, String vpnInstanceName, String vpnInterfaceName,
1290 int lPortTag, boolean isInterfaceStateDown, boolean isConfigRemoval,
1291 WriteTransaction writeTxn) {
1292 if (!isInterfaceStateDown && isConfigRemoval) {
1293 writeTxn.delete(LogicalDatastoreType.CONFIGURATION,
1294 InterfaceUtils.buildServiceId(vpnInterfaceName,
1295 VpnConstants.L3VPN_SERVICE_IDENTIFIER));
1297 long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName);
1298 makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
1299 vpnId, ArpReplyOrRequest.REQUEST, NwConstants.DEL_FLOW, writeTxn);
1300 makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
1301 vpnId, ArpReplyOrRequest.REPLY, NwConstants.DEL_FLOW, writeTxn);
1305 private void removePrefixFromBGP(String rd, String prefix, String nextHop, WriteTransaction writeTxn) {
1306 VpnUtil.removeFibEntryFromDS(broker, rd, prefix, nextHop, writeTxn);
1308 LOG.info("VPN WITHDRAW: Removing Fib Entry rd {} prefix {}", rd, prefix);
1309 VpnUtil.removeFibEntryFromDS(broker, rd, prefix, nextHop, writeTxn);
1310 bgpManager.withdrawPrefix(rd, prefix); // TODO: Might be needed to include nextHop here
1311 LOG.info("VPN WITHDRAW: Removed Fib Entry rd {} prefix {}", rd, prefix);
1312 } catch(Exception e) {
1313 LOG.error("Delete prefix failed", e);
1318 protected void update(InstanceIdentifier<VpnInterface> identifier, VpnInterface original, VpnInterface update) {
1319 LOG.trace("Updating VPN Interface : key {}, original value={}, update value={}", identifier, original, update);
1320 String oldVpnName = original.getVpnInstanceName();
1321 String newVpnName = update.getVpnInstanceName();
1322 BigInteger dpnId = update.getDpnId();
1323 List<Adjacency> oldAdjs = original.getAugmentation(Adjacencies.class).getAdjacency();
1324 List<Adjacency> newAdjs = update.getAugmentation(Adjacencies.class).getAdjacency();
1325 if (oldAdjs == null) {
1326 oldAdjs = new ArrayList<>();
1328 if (newAdjs == null) {
1329 newAdjs = new ArrayList<>();
1331 //handles switching between <internal VPN - external VPN>
1332 if (!oldVpnName.equals(newVpnName)) {
1333 remove(identifier, original);
1334 add(identifier, update);
1336 //handle both addition and removal of adjacencies
1337 //currently, new adjacency may be an extra route
1338 if (!oldAdjs.equals(newAdjs)) {
1339 for (Adjacency adj : newAdjs) {
1340 if (oldAdjs.contains(adj)) {
1341 oldAdjs.remove(adj);
1343 // add new adjacency - right now only extra route will hit this path
1344 addNewAdjToVpnInterface(identifier, adj, dpnId);
1347 for (Adjacency adj : oldAdjs) {
1348 delAdjFromVpnInterface(identifier, adj, dpnId);
1353 public void processArpRequest(IpAddress srcIP, PhysAddress srcMac, IpAddress targetIP, PhysAddress targetMac,String srcInterface){
1354 //Build ARP response with ARP requests TargetIp TargetMac as the Arp Response SrcIp and SrcMac
1355 SendArpResponseInput input = new SendArpResponseInputBuilder().setInterface(srcInterface)
1356 .setDstIpaddress(srcIP).setDstMacaddress(srcMac).setSrcIpaddress(targetIP).setSrcMacaddress(targetMac).build();
1357 final String msgFormat = String.format("Send ARP Response on interface %s to destination %s", srcInterface, srcIP);
1358 Future<RpcResult<Void>> future = arpManager.sendArpResponse(input);
1359 Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future), new FutureCallback<RpcResult<Void>>() {
1361 public void onFailure(Throwable error) {
1362 LOG.error("Error - {}", msgFormat, error);
1366 public void onSuccess(RpcResult<Void> result) {
1367 if(!result.isSuccessful()) {
1368 LOG.warn("Rpc call to {} failed", msgFormat, getErrorText(result.getErrors()));
1370 LOG.debug("Successful RPC Result - {}", msgFormat);
1376 private String getErrorText(Collection<RpcError> errors) {
1377 StringBuilder errorText = new StringBuilder();
1378 for(RpcError error : errors) {
1379 errorText.append(",").append(error.getErrorType()).append("-")
1380 .append(error.getMessage());
1382 return errorText.toString();
1385 private void addToLabelMapper(Long label, BigInteger dpnId, String prefix, List<String> nextHopIpList, Long vpnId,
1386 String vpnInterfaceName, Long elanTag, boolean isSubnetRoute, String rd) {
1387 Preconditions.checkNotNull(label, "label cannot be null or empty!");
1388 Preconditions.checkNotNull(prefix, "prefix cannot be null or empty!");
1389 Preconditions.checkNotNull(vpnId, "vpnId cannot be null or empty!");
1390 Preconditions.checkNotNull(rd, "rd cannot be null or empty!");
1391 if (!isSubnetRoute) {
1392 // NextHop must be present for non-subnetroute entries
1393 Preconditions.checkNotNull(nextHopIpList, "nextHopIp cannot be null or empty!");
1395 LOG.info("Adding to label mapper : label {} dpn {} prefix {} nexthoplist {} vpnid {} vpnIntfcName {} rd {}", label, dpnId, prefix, nextHopIpList, vpnId, vpnInterfaceName, rd);
1396 if (dpnId != null) {
1397 InstanceIdentifier<LabelRouteInfo> lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
1398 .child(LabelRouteInfo.class, new LabelRouteInfoKey((long)label)).build();
1399 LabelRouteInfoBuilder lriBuilder = new LabelRouteInfoBuilder();
1400 lriBuilder.setLabel(label).setDpnId(dpnId).setPrefix(prefix).setNextHopIpList(nextHopIpList).setParentVpnid(vpnId)
1401 .setIsSubnetRoute(isSubnetRoute);
1402 if (elanTag != null) {
1403 lriBuilder.setElanTag(elanTag);
1405 if (vpnInterfaceName != null) {
1406 lriBuilder.setVpnInterfaceName(vpnInterfaceName);
1408 lriBuilder.setParentVpnRd(rd);
1409 VpnInstanceOpDataEntry vpnInstanceOpDataEntry = VpnUtil.getVpnInstanceOpData(broker, rd);
1410 if (vpnInstanceOpDataEntry != null) {
1411 List<String> vpnInstanceNames = Arrays.asList(vpnInstanceOpDataEntry.getVpnInstanceName());
1412 lriBuilder.setVpnInstanceList(vpnInstanceNames);
1414 LabelRouteInfo lri = lriBuilder.build();
1415 LOG.trace("Adding route info to label map: {}", lri);
1416 VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, lriIid, lri);
1418 LOG.trace("Can't add entry to label map for lable {},dpnId is null", label);
1422 public synchronized void addSubnetRouteFibEntryToDS(String rd, String vpnName, String prefix, String nextHop, int label,
1423 long elantag, BigInteger dpnId, WriteTransaction writeTxn) {
1425 SubnetRoute route = new SubnetRouteBuilder().setElantag(elantag).build();
1426 RouteOrigin origin = RouteOrigin.STATIC; // Only case when a route is considered as directly connected
1427 VrfEntry vrfEntry = new VrfEntryBuilder().setDestPrefix(prefix).setNextHopAddressList(Arrays.asList(nextHop))
1428 .setLabel((long)label).setOrigin(origin.getValue())
1429 .addAugmentation(SubnetRoute.class, route).build();
1431 LOG.debug("Created vrfEntry for {} nexthop {} label {} and elantag {}", prefix, nextHop, label, elantag);
1433 //TODO: What should be parentVpnId? Get it from RD?
1434 long vpnId = VpnUtil.getVpnId(broker, vpnName);
1435 addToLabelMapper((long)label, dpnId, prefix, Arrays.asList(nextHop), vpnId, null, elantag, true, rd);
1436 List<VrfEntry> vrfEntryList = Arrays.asList(vrfEntry);
1438 InstanceIdentifierBuilder<VrfTables> idBuilder =
1439 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
1440 InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
1442 VrfTables vrfTableNew = new VrfTablesBuilder().setRouteDistinguisher(rd).
1443 setVrfEntry(vrfEntryList).build();
1445 if (writeTxn != null) {
1446 writeTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew, true);
1448 VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
1451 List<VpnInstance> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
1452 if (vpnsToImportRoute.size() > 0) {
1453 VrfEntry importingVrfEntry = new VrfEntryBuilder().setDestPrefix(prefix).setNextHopAddressList(Arrays.asList(nextHop))
1454 .setLabel((long) label).setOrigin(RouteOrigin.SELF_IMPORTED.getValue())
1455 .addAugmentation(SubnetRoute.class, route).build();
1456 List<VrfEntry> importingVrfEntryList = Arrays.asList(importingVrfEntry);
1457 for (VpnInstance vpnInstance : vpnsToImportRoute) {
1458 LOG.info("Exporting subnet route rd {} prefix {} nexthop {} label {} to vpn {}", rd, prefix, nextHop, label, vpnInstance.getVpnInstanceName());
1459 String importingRd = vpnInstance.getIpv4Family().getRouteDistinguisher();
1460 InstanceIdentifier<VrfTables> importingVrfTableId = InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(importingRd)).build();
1461 VrfTables importingVrfTable = new VrfTablesBuilder().setRouteDistinguisher(importingRd).setVrfEntry(importingVrfEntryList).build();
1462 if (writeTxn != null) {
1463 writeTxn.merge(LogicalDatastoreType.CONFIGURATION, importingVrfTableId, importingVrfTable, true);
1465 VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, importingVrfTableId, importingVrfTable);
1471 public synchronized void importSubnetRouteForNewVpn(String rd, String prefix, String nextHop, int label,
1472 SubnetRoute route) {
1474 RouteOrigin origin = RouteOrigin.SELF_IMPORTED;
1475 VrfEntry vrfEntry = new VrfEntryBuilder().setDestPrefix(prefix).setNextHopAddressList(Arrays.asList(nextHop))
1476 .setLabel((long)label).setOrigin(origin.getValue())
1477 .addAugmentation(SubnetRoute.class, route).build();
1478 LOG.debug("Created vrfEntry for {} nexthop {} label {} and elantag {}", prefix, nextHop, label, route.getElantag());
1479 List<VrfEntry> vrfEntryList = Arrays.asList(vrfEntry);
1480 InstanceIdentifierBuilder<VrfTables> idBuilder =
1481 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
1482 InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
1483 VrfTables vrfTableNew = new VrfTablesBuilder().setRouteDistinguisher(rd).
1484 setVrfEntry(vrfEntryList).build();
1485 VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
1488 public synchronized void deleteSubnetRouteFibEntryFromDS(String rd, String prefix, String vpnName){
1489 VpnUtil.removeFibEntryFromDS(broker, rd, prefix, null /* nextHopToRemove */, null);
1490 List<VpnInstance> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
1491 for (VpnInstance vpnInstance : vpnsToImportRoute) {
1492 String importingRd = vpnInstance.getIpv4Family().getRouteDistinguisher();
1493 LOG.info("Deleting imported subnet route rd {} prefix {} from vpn {}", rd, prefix, vpnInstance.getVpnInstanceName());
1494 VpnUtil.removeFibEntryFromDS(broker, importingRd, prefix, null, null);
1498 public synchronized void removeVrfFromDS(String rd) {
1499 LOG.debug("Removing vrf table for rd {}", rd);
1501 InstanceIdentifierBuilder<VrfTables> idBuilder =
1502 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
1503 InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
1505 VpnUtil.delete(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, VpnUtil.DEFAULT_CALLBACK);
1509 protected void addNewAdjToVpnInterface(InstanceIdentifier<VpnInterface> identifier, Adjacency adj, BigInteger dpnId) {
1511 Optional<VpnInterface> optVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
1513 if (optVpnInterface.isPresent()) {
1514 VpnInterface currVpnIntf = optVpnInterface.get();
1515 String prefix = VpnUtil.getIpPrefix(adj.getIpAddress());
1516 String rd = getRouteDistinguisher(currVpnIntf.getVpnInstanceName());
1517 InstanceIdentifier<Adjacencies> adjPath = identifier.augmentation(Adjacencies.class);
1518 Optional<Adjacencies> optAdjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, adjPath);
1520 VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
1521 VpnUtil.getNextHopLabelKey((rd != null) ? rd : currVpnIntf.getVpnInstanceName(), prefix));
1523 List<Adjacency> adjacencies;
1524 if (optAdjacencies.isPresent()) {
1525 adjacencies = optAdjacencies.get().getAdjacency();
1527 //This code will not be hit since VM adjacency will always be there
1528 adjacencies = new ArrayList<>();
1532 adjacencies.add(new AdjacencyBuilder(adj).setLabel(label).setNextHopIpList(adj.getNextHopIpList())
1533 .setIpAddress(prefix).setKey(new AdjacencyKey(prefix)).build());
1534 Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencies);
1535 VpnInterface newVpnIntf = VpnUtil.getVpnInterface(currVpnIntf.getName(), currVpnIntf.getVpnInstanceName(), aug, dpnId, currVpnIntf.isScheduledForRemove());
1536 VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, newVpnIntf);
1537 for (String nh : adj.getNextHopIpList()) {
1538 addExtraRoute(adj.getIpAddress(), nh, rd, currVpnIntf.getVpnInstanceName(), (int) label,
1539 currVpnIntf.getName());
1546 protected void delAdjFromVpnInterface(InstanceIdentifier<VpnInterface> identifier, Adjacency adj, BigInteger dpnId) {
1547 Optional<VpnInterface> optVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
1549 if (optVpnInterface.isPresent()) {
1550 VpnInterface currVpnIntf = optVpnInterface.get();
1552 InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
1553 Optional<Adjacencies> optAdjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
1554 if (optAdjacencies.isPresent()) {
1555 List<Adjacency> adjacencies = optAdjacencies.get().getAdjacency();
1557 if (!adjacencies.isEmpty()) {
1558 String rd = getRouteDistinguisher(currVpnIntf.getVpnInstanceName());
1559 LOG.trace("Adjacencies are " + adjacencies);
1560 Iterator<Adjacency> adjIt = adjacencies.iterator();
1561 while (adjIt.hasNext()) {
1562 Adjacency adjElem = adjIt.next();
1563 if (adjElem.getIpAddress().equals(adj.getIpAddress())) {
1566 Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencies);
1567 VpnInterface newVpnIntf = VpnUtil.getVpnInterface(currVpnIntf.getName(),
1568 currVpnIntf.getVpnInstanceName(),
1569 aug, dpnId, currVpnIntf.isScheduledForRemove());
1571 VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, newVpnIntf);
1573 for (String nh : adj.getNextHopIpList()) {
1574 delExtraRoute(adj.getIpAddress(), nh, rd, currVpnIntf.getVpnInstanceName(),
1575 currVpnIntf.getName());
1587 protected void addExtraRoute(String destination, String nextHop, String rd, String routerID, int label,
1590 //add extra route to vpn mapping; advertise with nexthop as tunnel ip
1593 LogicalDatastoreType.OPERATIONAL,
1594 VpnUtil.getVpnToExtrarouteIdentifier( (rd != null) ? rd : routerID, destination),
1595 VpnUtil.getVpnToExtraroute(destination, Arrays.asList(nextHop)));
1597 BigInteger dpnId = null;
1598 if (intfName != null && !intfName.isEmpty()) {
1599 dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, intfName);
1600 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
1601 if (nextHopIp == null || nextHopIp.isEmpty()) {
1602 LOG.error("NextHop for interface {} is null / empty. Failed advertising extra route for prefix {}",
1603 intfName, destination);
1606 nextHop = nextHopIp;
1608 List<String> nextHopIpList = Arrays.asList(nextHop);
1609 addToLabelMapper((long)label, dpnId, destination, nextHopIpList, VpnUtil.getVpnId(broker, routerID),
1610 intfName, null, false, rd);
1612 // TODO (eperefr): This is a limitation to be stated in docs. When configuring static route to go to
1613 // another VPN, there can only be one nexthop or, at least, the nexthop to the interVpnLink should be in
1615 InterVpnLink interVpnLink = VpnUtil.getInterVpnLinkByEndpointIp(broker, nextHop);
1616 if ( interVpnLink != null ) {
1617 // If the nexthop is the endpoint of Vpn2, then prefix must be advertised to Vpn1 in DC-GW, with nexthops
1618 // pointing to the DPNs where Vpn1 is instantiated. LFIB in these DPNS must have a flow entry, with lower
1619 // priority, where if Label matches then sets the lportTag of the Vpn2 endpoint and goes to LportDispatcher
1620 // This is like leaking one of the Vpn2 routes towards Vpn1
1621 boolean nexthopIsVpn2 = ( interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(nextHop) );
1622 String srcVpnUuid = (nexthopIsVpn2) ? interVpnLink.getSecondEndpoint().getVpnUuid().getValue()
1623 : interVpnLink.getFirstEndpoint().getVpnUuid().getValue();
1624 String dstVpnUuid = (nexthopIsVpn2) ? interVpnLink.getFirstEndpoint().getVpnUuid().getValue()
1625 : interVpnLink.getSecondEndpoint().getVpnUuid().getValue();
1626 String dstVpnRd = VpnUtil.getVpnRd(broker, dstVpnUuid);
1627 long newLabel = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
1628 VpnUtil.getNextHopLabelKey(dstVpnRd, destination));
1629 VpnUtil.leakRoute(broker, bgpManager, interVpnLink, srcVpnUuid, dstVpnUuid, destination, newLabel);
1632 addPrefixToBGP(rd, destination, nextHop, label, null);
1634 // ### add FIB route directly
1635 VpnUtil.addFibEntryToDS(broker, routerID, destination, nextHop, label, RouteOrigin.STATIC, null);
1640 protected void delExtraRoute(String destination, String nextHop, String rd, String routerID, String intfName) {
1641 if (intfName != null && !intfName.isEmpty()) {
1642 BigInteger dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, intfName);
1643 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
1644 if (nextHopIp == null || nextHopIp.isEmpty()) {
1645 LOG.warn("NextHop for interface {} is null / empty. Failed advertising extra route for prefix {}",
1646 intfName, destination);
1648 nextHop = nextHopIp;
1652 removePrefixFromBGP(rd, destination, nextHop, null);
1654 // ### add FIB route directly
1655 VpnUtil.removeFibEntryFromDS(broker, routerID, destination, nextHop, null);
1659 class VpnInterfaceOpListener extends AbstractDataChangeListener<VpnInterface> {
1661 public VpnInterfaceOpListener() {
1662 super(VpnInterface.class);
1666 protected void remove(InstanceIdentifier<VpnInterface> identifier, VpnInterface del) {
1667 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
1668 String interfaceName = key.getName();
1669 String vpnName = del.getVpnInstanceName();
1671 LOG.trace("VpnInterfaceOpListener removed: interface name {} vpnName {}", interfaceName, vpnName);
1672 //decrement the vpn interface count in Vpn Instance Op Data
1673 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
1674 id = VpnUtil.getVpnInstanceToVpnIdIdentifier(vpnName);
1675 Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> vpnInstance
1676 = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
1678 if (vpnInstance.isPresent()) {
1680 rd = vpnInstance.get().getVrfId();
1681 //String rd = getRouteDistinguisher(del.getVpnInstanceName());
1683 VpnInstanceOpDataEntry vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
1684 LOG.trace("VpnInterfaceOpListener removed: interface name {} rd {} vpnName {} in Vpn Op Instance {}",
1685 interfaceName, rd, vpnName, vpnInstOp);
1687 if (vpnInstOp != null) {
1688 // Vpn Interface removed => No more adjacencies from it.
1689 // Hence clean up interface from vpn-dpn-interface list.
1690 Adjacency adjacency = del.getAugmentation(Adjacencies.class).getAdjacency().get(0);
1691 List<Prefixes> prefixToInterface = new ArrayList<>();
1692 Optional<Prefixes> prefix = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
1693 VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
1694 VpnUtil.getIpPrefix(adjacency.getIpAddress())));
1695 if (prefix.isPresent()) {
1696 prefixToInterface.add(prefix.get());
1698 if (prefixToInterface.isEmpty()) {
1699 for (String nh : adjacency.getNextHopIpList()) {
1700 prefix = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
1701 VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
1702 VpnUtil.getIpPrefix(nh)));
1703 if (prefix.isPresent())
1704 prefixToInterface.add(prefix.get());
1707 for (Prefixes pref : prefixToInterface) {
1708 VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
1709 VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(), pref.getIpAddress()),
1710 VpnUtil.DEFAULT_CALLBACK);
1711 synchronized (interfaceName.intern()) {
1712 updateDpnDbs(pref.getDpnId(), del.getVpnInstanceName(), interfaceName, false, null);
1717 LOG.error("rd not retrievable as vpninstancetovpnid for vpn {} is absent, trying rd as ", vpnName, vpnName);
1719 notifyTaskIfRequired(interfaceName);
1722 private void notifyTaskIfRequired(String intfName) {
1723 Runnable notifyTask = vpnIntfMap.remove(intfName);
1724 if (notifyTask == null) {
1725 LOG.trace("VpnInterfaceOpListener update: No Notify Task queued for vpnInterface {}", intfName);
1728 executorService.execute(notifyTask);
1732 protected void update(InstanceIdentifier<VpnInterface> identifier, VpnInterface original, VpnInterface update) {
1733 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
1734 String interfaceName = key.getName();
1736 if (original.getVpnInstanceName().equals(update.getVpnInstanceName())) {
1740 //increment the vpn interface count in Vpn Instance Op Data
1741 VpnInstanceOpDataEntry vpnInstOp = null;
1742 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
1743 origId = VpnUtil.getVpnInstanceToVpnIdIdentifier(original.getVpnInstanceName());
1744 Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> origVpnInstance
1745 = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, origId);
1747 if (origVpnInstance.isPresent()) {
1749 rd = origVpnInstance.get().getVrfId();
1751 vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
1752 LOG.trace("VpnInterfaceOpListener updated: interface name {} original rd {} original vpnName {}",
1753 interfaceName, rd, original.getVpnInstanceName());
1755 if (vpnInstOp != null) {
1756 Adjacency adjacency = original.getAugmentation(Adjacencies.class).getAdjacency().get(0);
1757 List<Prefixes> prefixToInterfaceList = new ArrayList<>();
1758 Optional<Prefixes> prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
1759 VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
1760 VpnUtil.getIpPrefix(adjacency.getIpAddress())));
1761 if (prefixToInterface.isPresent()) {
1762 prefixToInterfaceList.add(prefixToInterface.get());
1764 for (String adj : adjacency.getNextHopIpList()) {
1765 prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
1766 VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
1767 VpnUtil.getIpPrefix(adj)));
1768 if (prefixToInterface.isPresent()) {
1769 prefixToInterfaceList.add(prefixToInterface.get());
1773 synchronized (interfaceName.intern()) {
1774 for (Prefixes prefix : prefixToInterfaceList) {
1775 updateDpnDbs(prefix.getDpnId(), original.getVpnInstanceName(), interfaceName, false, null);
1780 notifyTaskIfRequired(interfaceName);
1784 protected void add(InstanceIdentifier<VpnInterface> identifier, VpnInterface add) {
1789 protected void handlePrefixesForDPNs(StateTunnelList stateTunnelList, UpdateRouteAction action) {
1790 BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
1791 BigInteger destDpnId;
1792 String srcTepIp = String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue());
1793 String destTepIp = String.valueOf(stateTunnelList.getDstInfo().getTepIp().getValue());
1795 InstanceIdentifierBuilder<VpnInstances> idBuilder = InstanceIdentifier.builder(VpnInstances.class);
1796 InstanceIdentifier<VpnInstances> vpnInstancesId = idBuilder.build();
1797 Optional<VpnInstances> vpnInstances = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vpnInstancesId);
1798 long tunTypeVal = 0, vpnId;
1800 if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
1801 tunTypeVal = VpnConstants.ITMTunnelLocType.Internal.getValue();
1802 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
1803 tunTypeVal = VpnConstants.ITMTunnelLocType.External.getValue();
1804 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class){
1805 tunTypeVal = VpnConstants.ITMTunnelLocType.Hwvtep.getValue();
1807 tunTypeVal = VpnConstants.ITMTunnelLocType.Invalid.getValue();
1809 LOG.trace("tunTypeVal is {}", tunTypeVal);
1810 long dcgwPresentStatus = VpnConstants.DCGWPresentStatus.Invalid.getValue();
1811 if (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) {
1812 Future<RpcResult<IsDcgwPresentOutput>> result;
1814 result = itmProvider.isDcgwPresent(new IsDcgwPresentInputBuilder()
1815 .setDcgwIp(destTepIp)
1817 RpcResult<IsDcgwPresentOutput> rpcResult = result.get();
1818 if (!rpcResult.isSuccessful()) {
1819 LOG.warn("RPC Call to isDcgwPresent {} returned with Errors {}", destTepIp, rpcResult.getErrors());
1821 dcgwPresentStatus = rpcResult.getResult().getRetVal();
1823 } catch (Exception e) {
1824 LOG.warn("Exception {} when querying for isDcgwPresent {}, trace {}", e, destTepIp, e.getStackTrace());
1828 if (vpnInstances.isPresent()) {
1829 List<VpnInstance> vpnInstanceList = vpnInstances.get().getVpnInstance();
1830 Iterator<VpnInstance> vpnInstIter = vpnInstanceList.iterator();
1831 LOG.trace("vpnInstIter {}", vpnInstIter);
1832 while (vpnInstIter.hasNext()) {
1833 VpnInstance vpnInstance = vpnInstIter.next();
1834 LOG.trace("vpnInstance {}", vpnInstance);
1835 vpnId = VpnUtil.getVpnId(broker, vpnInstance.getVpnInstanceName());
1837 VpnAfConfig vpnConfig = vpnInstance.getIpv4Family();
1838 LOG.trace("vpnConfig {}", vpnConfig);
1839 String rd = vpnConfig.getRouteDistinguisher();
1840 if (rd == null || rd.isEmpty()) {
1841 rd = vpnInstance.getVpnInstanceName();
1842 LOG.trace("rd is null or empty. Assigning VpnInstanceName to rd {}", rd);
1844 InstanceIdentifier<VpnToDpnList> srcId =
1845 VpnUtil.getVpnToDpnListIdentifier(rd, srcDpnId);
1846 Optional<VpnToDpnList> srcDpnInVpn =
1847 VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, srcId);
1848 if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
1849 destDpnId = new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId());
1850 InstanceIdentifier<VpnToDpnList> destId =
1851 VpnUtil.getVpnToDpnListIdentifier(rd, destDpnId);
1852 Optional<VpnToDpnList> destDpnInVpn =
1853 VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, destId);
1854 if (!(srcDpnInVpn.isPresent() &&
1855 destDpnInVpn.isPresent())) {
1856 LOG.trace(" srcDpn {} - destDPN {}, do not share the VPN {} with rd {}.",
1857 srcDpnId, destDpnId, vpnInstance.getVpnInstanceName(), rd);
1861 if (srcDpnInVpn.isPresent()) {
1862 List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
1863 .instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces>
1864 vpnInterfaces = srcDpnInVpn.get().getVpnInterfaces();
1865 for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
1866 .instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces vpnInterface : vpnInterfaces) {
1867 InstanceIdentifier<VpnInterface> vpnIntfId =
1868 VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getInterfaceName());
1869 LOG.trace("vpnInterface {}", vpnInterface);
1870 InstanceIdentifier<Adjacencies> path =
1871 vpnIntfId.augmentation(Adjacencies.class);
1872 Optional<Adjacencies> adjacencies =
1873 VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
1874 LOG.trace("adjacencies {}", adjacencies);
1875 if (adjacencies.isPresent()) {
1876 List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
1877 Iterator<Adjacency> adjacencyIterator = adjacencyList.iterator();
1879 while (adjacencyIterator.hasNext()) {
1880 Adjacency adjacency = adjacencyIterator.next();
1882 if (action == UpdateRouteAction.ADVERTISE_ROUTE) {
1883 LOG.info("VPNInterfaceManager : Added Fib Entry rd {} prefix {} nextHop {} label {}",
1884 rd, adjacency.getIpAddress(), adjacency.getNextHopIpList(),
1885 adjacency.getLabel());
1886 // vrf = new VrfEntryBuilder().set
1887 if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
1888 fibManager.handleRemoteRoute(true,
1889 new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId()),
1890 new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId()),
1891 VpnUtil.getVpnId(broker, vpnInstance.getVpnInstanceName()),
1892 rd, adjacency.getIpAddress(), srcTepIp, destTepIp);
1894 if (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) {
1895 fibManager.populateFibOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
1898 else if (action == UpdateRouteAction.WITHDRAW_ROUTE) {
1899 LOG.info("VPNInterfaceManager : Removed Fib entry rd {} prefix {}",
1900 rd, adjacency.getIpAddress());
1901 if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
1902 fibManager.handleRemoteRoute(false, srcDpnId,
1903 new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId()),
1904 vpnId, rd, adjacency.getIpAddress(), srcTepIp, destTepIp);
1906 if ((tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) &&
1907 (dcgwPresentStatus == VpnConstants.DCGWPresentStatus.Absent.getValue())) {
1908 bgpManager.withdrawPrefix(rd, adjacency.getIpAddress());
1909 fibManager.cleanUpDpnForVpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
1912 } catch (Exception e) {
1913 LOG.error("Exception when updating prefix {} in vrf {} to BGP",
1914 adjacency.getIpAddress(), rd);
1918 LOG.trace("no adjacencies present for path {}.", path);
1922 // if (action == UpdateRouteAction.WITHDRAW_ROUTE) {
1923 // fibManager.cleanUpDpnForVpn(dpnId, VpnUtil.getVpnId(broker, vpnInstance.getVpnInstanceName()), rd);
1925 // Go through all the VrfEntries and withdraw and readvertise the prefixes to BGP for which the nextHop is the SrcTepIp
1926 if ((action == UpdateRouteAction.ADVERTISE_ROUTE) &&
1927 (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue())) {
1928 List<VrfEntry> vrfEntries = VpnUtil.getAllVrfEntries(broker, rd);
1929 if (vrfEntries != null) {
1930 for (VrfEntry vrfEntry : vrfEntries) {
1931 String destPrefix = vrfEntry.getDestPrefix().trim();
1932 int vpnLabel = vrfEntry.getLabel().intValue();
1933 List<String> nextHops = vrfEntry.getNextHopAddressList();
1934 if (nextHops.contains(srcTepIp.trim())) {
1935 bgpManager.withdrawPrefix(rd, destPrefix);
1936 bgpManager.advertisePrefix(rd, destPrefix, nextHops, vpnLabel);
1942 LOG.trace("dpnInVpn check failed for srcDpnId {}.", srcDpnId);
1944 } catch (Exception e) {
1945 LOG.error("updatePrefixesForDPN {} in vpn {} failed", 0, vpnInstance.getVpnInstanceName(), e);
1949 LOG.trace("No vpn instances present.");
1953 void publishAddNotification(final BigInteger dpnId, final String vpnName, final String rd) {
1954 LOG.debug("Sending notification for add dpn {} in vpn {} event ", dpnId, vpnName);
1955 AddEventData data = new AddEventDataBuilder().setVpnName(vpnName).setRd(rd).setDpnId(dpnId).build();
1956 AddDpnEvent event = new AddDpnEventBuilder().setAddEventData(data).build();
1957 final ListenableFuture<? extends Object> eventFuture = notificationPublishService.offerNotification(event);
1958 Futures.addCallback(eventFuture, new FutureCallback<Object>() {
1960 public void onFailure(Throwable error) {
1961 LOG.warn("Error in notifying listeners for add dpn {} in vpn {} event ", dpnId, vpnName, error);
1965 public void onSuccess(Object arg) {
1966 LOG.trace("Successful in notifying listeners for add dpn {} in vpn {} event ", dpnId, vpnName);
1971 void publishRemoveNotification(final BigInteger dpnId, final String vpnName, final String rd) {
1972 LOG.debug("Sending notification for remove dpn {} in vpn {} event ", dpnId, vpnName);
1973 RemoveEventData data = new RemoveEventDataBuilder().setVpnName(vpnName).setRd(rd).setDpnId(dpnId).build();
1974 RemoveDpnEvent event = new RemoveDpnEventBuilder().setRemoveEventData(data).build();
1975 final ListenableFuture<? extends Object> eventFuture = notificationPublishService.offerNotification(event);
1976 Futures.addCallback(eventFuture, new FutureCallback<Object>() {
1978 public void onFailure(Throwable error) {
1979 LOG.warn("Error in notifying listeners for remove dpn {} in vpn {} event ", dpnId, vpnName, error);
1983 public void onSuccess(Object arg) {
1984 LOG.trace("Successful in notifying listeners for remove dpn {} in vpn {} event ", dpnId, vpnName);
1989 InstanceIdentifier<DpnVpninterfacesList> getRouterDpnId(String routerName, BigInteger dpnId) {
1990 return InstanceIdentifier.builder(NeutronRouterDpns.class)
1991 .child(RouterDpnList.class, new RouterDpnListKey(routerName))
1992 .child(DpnVpninterfacesList.class, new DpnVpninterfacesListKey(dpnId)).build();
1995 InstanceIdentifier<RouterDpnList> getRouterId(String routerName) {
1996 return InstanceIdentifier.builder(NeutronRouterDpns.class)
1997 .child(RouterDpnList.class, new RouterDpnListKey(routerName)).build();
2000 protected void addToNeutronRouterDpnsMap(String routerName, String vpnInterfaceName, WriteTransaction writeTxn) {
2001 BigInteger dpId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
2002 if(dpId.equals(BigInteger.ZERO)) {
2003 LOG.warn("Could not retrieve dp id for interface {} to handle router {} association model", vpnInterfaceName, routerName);
2006 InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
2008 Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
2009 .OPERATIONAL, routerDpnListIdentifier);
2010 RouterInterfaces routerInterface = new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName)).setInterface(vpnInterfaceName).build();
2011 if (optionalRouterDpnList.isPresent()) {
2012 writeTxn.merge(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
2013 RouterInterfaces.class, new RouterInterfacesKey(vpnInterfaceName)), routerInterface, true);
2015 RouterDpnListBuilder builder = new RouterDpnListBuilder();
2016 builder.setRouterId(routerName);
2017 DpnVpninterfacesListBuilder dpnVpnList = new DpnVpninterfacesListBuilder().setDpnId(dpId);
2018 List<RouterInterfaces> routerInterfaces = new ArrayList<>();
2019 routerInterfaces.add(routerInterface);
2020 builder.setDpnVpninterfacesList(Arrays.asList(dpnVpnList.build()));
2021 writeTxn.merge(LogicalDatastoreType.OPERATIONAL,
2022 getRouterId(routerName),
2023 new RouterDpnListBuilder().setRouterId(routerName).build(), true);
2027 protected void removeFromNeutronRouterDpnsMap(String routerName, String vpnInterfaceName, WriteTransaction writeTxn) {
2028 BigInteger dpId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
2029 if(dpId.equals(BigInteger.ZERO)) {
2030 LOG.warn("Could not retrieve dp id for interface {} to handle router {} dissociation model", vpnInterfaceName, routerName);
2033 InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
2034 Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
2035 .OPERATIONAL, routerDpnListIdentifier);
2036 if (optionalRouterDpnList.isPresent()) {
2037 List<RouterInterfaces> routerInterfaces = optionalRouterDpnList.get().getRouterInterfaces();
2038 RouterInterfaces routerInterface = new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName)).setInterface(vpnInterfaceName).build();
2040 if (routerInterfaces != null && routerInterfaces.remove(routerInterface)) {
2041 if (routerInterfaces.isEmpty()) {
2042 if (writeTxn != null) {
2043 writeTxn.delete(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
2045 MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
2048 if (writeTxn != null) {
2049 writeTxn.delete(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
2050 RouterInterfaces.class,
2051 new RouterInterfacesKey(vpnInterfaceName)));
2053 MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
2054 RouterInterfaces.class,
2055 new RouterInterfacesKey(vpnInterfaceName)));
2062 protected void removeFromNeutronRouterDpnsMap(String routerName, String vpnInterfaceName, BigInteger dpId, WriteTransaction writeTxn) {
2063 if(dpId.equals(BigInteger.ZERO)) {
2064 LOG.warn("Could not retrieve dp id for interface {} to handle router {} dissociation model", vpnInterfaceName, routerName);
2067 InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
2068 Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
2069 .OPERATIONAL, routerDpnListIdentifier);
2070 if (optionalRouterDpnList.isPresent()) {
2071 List<RouterInterfaces> routerInterfaces = optionalRouterDpnList.get().getRouterInterfaces();
2072 RouterInterfaces routerInterface = new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName)).setInterface(vpnInterfaceName).build();
2073 if (routerInterfaces != null && routerInterfaces.remove(routerInterface)) {
2074 if (routerInterfaces.isEmpty()) {
2075 writeTxn.delete(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
2077 writeTxn.delete(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
2078 RouterInterfaces.class,
2079 new RouterInterfacesKey(vpnInterfaceName)));
2085 public void addMIPAdjacency(String vpnName,String vpnInterface, IpAddress prefix){
2087 LOG.trace("Adding {} adjacency to VPN Interface {} ",prefix,vpnInterface);
2088 InstanceIdentifier<VpnInterface> vpnIfId = VpnUtil.getVpnInterfaceIdentifier(vpnInterface);
2089 InstanceIdentifier<Adjacencies> path = vpnIfId.augmentation(Adjacencies.class);
2090 Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
2091 String nextHopIpAddr = null;
2092 String nextHopMacAddress = null;
2093 String ip = prefix.getIpv4Address().getValue();
2094 if (adjacencies.isPresent()) {
2095 List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
2096 ip = VpnUtil.getIpPrefix(ip);
2097 for (Adjacency adjacs : adjacencyList) {
2098 if (adjacs.getMacAddress() != null && !adjacs.getMacAddress().isEmpty()) {
2099 nextHopIpAddr = adjacs.getIpAddress();
2100 nextHopMacAddress = adjacs.getMacAddress();
2104 if (nextHopMacAddress != null && ip != null) {
2105 synchronized (vpnInterface.intern()) {
2106 String rd = VpnUtil.getVpnRd(broker, vpnName);
2108 VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
2109 VpnUtil.getNextHopLabelKey((rd != null) ? rd : vpnName, ip));
2110 String nextHopIp = nextHopIpAddr.split("/")[0];
2111 Adjacency newAdj = new AdjacencyBuilder().setIpAddress(ip).setKey
2112 (new AdjacencyKey(ip)).setNextHopIpList(Arrays.asList(nextHopIp)).build();
2113 adjacencyList.add(newAdj);
2114 Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencyList);
2115 VpnInterface newVpnIntf = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(vpnInterface)).
2116 setName(vpnInterface).setVpnInstanceName(vpnName).addAugmentation(Adjacencies.class, aug).build();
2117 VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vpnIfId, newVpnIntf);
2119 LOG.debug(" Successfully stored subnetroute Adjacency into VpnInterface {}", vpnInterface);
2125 public void removeMIPAdjacency(String vpnName, String vpnInterface, IpAddress prefix) {
2126 String ip = VpnUtil.getIpPrefix(prefix.getIpv4Address().getValue());
2127 LOG.trace("Removing {} adjacency from Old VPN Interface {} ",ip,vpnInterface);
2128 InstanceIdentifier<VpnInterface> vpnIfId = VpnUtil.getVpnInterfaceIdentifier(vpnInterface);
2129 InstanceIdentifier<Adjacencies> path = vpnIfId.augmentation(Adjacencies.class);
2130 Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
2131 if (adjacencies.isPresent()) {
2132 synchronized (vpnInterface.intern()) {
2133 InstanceIdentifier<Adjacency> adjacencyIdentifier = InstanceIdentifier.builder(VpnInterfaces.class).
2134 child(VpnInterface.class, new VpnInterfaceKey(vpnInterface)).augmentation(Adjacencies.class)
2135 .child(Adjacency.class, new AdjacencyKey(ip)).build();
2136 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, adjacencyIdentifier);
2138 LOG.trace("Successfully Deleted Adjacency into VpnInterface {}", vpnInterface);
2142 class TunnelInterfaceStateListener extends AbstractDataChangeListener<StateTunnelList> {
2143 public TunnelInterfaceStateListener(final DataBroker db, VpnInterfaceManager vpnIfMgr) {
2144 super(StateTunnelList.class);
2149 protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
2150 LOG.trace("Tunnel deletion---- {}", del);
2151 handlePrefixesForDPNs(del, UpdateRouteAction.WITHDRAW_ROUTE);
2155 protected void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original, StateTunnelList update) {
2156 LOG.trace("Tunnel updation---- {}", update);
2157 LOG.trace("ITM Tunnel {} of type {} state event changed from :{} to :{}",
2158 update.getTunnelInterfaceName(),
2159 fibManager.getTransportTypeStr(update.getTransportType().toString()),
2160 original.isTunnelState(), update.isTunnelState());
2161 //withdraw all prefixes in all vpns for this dpn
2162 boolean isTunnelUp = update.isTunnelState();
2163 handlePrefixesForDPNs(update,isTunnelUp ? UpdateRouteAction.ADVERTISE_ROUTE :
2164 UpdateRouteAction.WITHDRAW_ROUTE);
2168 protected void add(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList add) {
2169 LOG.trace("Tunnel addition---- {}", add);
2171 if(!add.isTunnelState()) {
2172 LOG.trace( "Tunnel {} is not yet UP.",
2173 add.getTunnelInterfaceName());
2176 LOG.trace("ITM Tunnel ,type {} ,State is UP b/w src: {} and dest: {}",
2177 fibManager.getTransportTypeStr(add.getTransportType().toString()),
2178 add.getSrcInfo().getTepDeviceId(), add.getDstInfo().getTepDeviceId());
2179 handlePrefixesForDPNs(add, UpdateRouteAction.ADVERTISE_ROUTE);