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.*;
14 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
15 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
16 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
17 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
18 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
19 import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
21 import org.opendaylight.controller.md.sal.binding.api.*;
22 import org.opendaylight.genius.mdsalutil.*;
23 import org.opendaylight.genius.mdsalutil.AbstractDataChangeListener;
24 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.VpnTargets;
25 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
26 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentInputBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentOutput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.LabelRouteMap;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRoute;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRouteBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfo;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoKey;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.*;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.add.dpn.event.AddEventData;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.add.dpn.event.AddEventDataBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.Vpn;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnListBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnListKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesListBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesListKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfacesBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfacesKey;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.remove.dpn.event.RemoveEventData;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.remove.dpn.event.RemoveEventDataBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
74 .VpnInstanceOpDataEntryBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListBuilder;
77 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;
78 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;
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.VpnInterfacesKey;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesBuilder;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpResponseInput;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpResponseInputBuilder;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
92 import java.math.BigInteger;
93 import java.util.Collection;
94 import java.util.List;
95 import java.util.ArrayList;
96 import java.util.Arrays;
97 import java.util.Iterator;
98 import java.util.concurrent.*;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
103 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronvpnService;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
107 import org.opendaylight.yangtools.concepts.ListenerRegistration;
108 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
109 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
110 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
111 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
112 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
115 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
116 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
117 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
118 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
119 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
120 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
121 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
122 import org.opendaylight.yangtools.yang.common.RpcError;
123 import org.opendaylight.yangtools.yang.common.RpcResult;
124 import org.slf4j.Logger;
125 import org.slf4j.LoggerFactory;
127 public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface> implements AutoCloseable {
128 private static final Logger LOG = LoggerFactory.getLogger(VpnInterfaceManager.class);
129 private ListenerRegistration<DataChangeListener> listenerRegistration, opListenerRegistration;
130 private final DataBroker broker;
131 private final IBgpManager bgpManager;
132 private IFibManager fibManager;
133 private IMdsalApiManager mdsalManager;
134 private OdlInterfaceRpcService ifaceMgrRpcService;
135 private IdManagerService idManager;
136 private OdlArputilService arpManager;
137 private NeutronvpnService neuService;
138 private VpnSubnetRouteHandler vpnSubnetRouteHandler;
139 private ConcurrentHashMap<String, Runnable> vpnIntfMap = new ConcurrentHashMap<String, Runnable>();
140 private ExecutorService executorService = Executors.newSingleThreadExecutor();
141 private InterfaceStateChangeListener interfaceListener;
142 private SubnetRouteInterfaceStateChangeListener subnetRouteInterfaceListener;
143 private TunnelInterfaceStateListener tunnelInterfaceStateListener;
144 private VpnInterfaceOpListener vpnInterfaceOpListener;
145 private ArpNotificationHandler arpNotificationHandler;
146 private DpnInVpnChangeListener dpnInVpnChangeListener;
147 private NotificationPublishService notificationPublishService;
148 private FibRpcService fibService;
151 * Responsible for listening to data change related to VPN Interface
152 * Bind VPN Service on the interface and informs the BGP service
154 * @param db - dataBroker service reference
155 * @param bgpManager Used to advertise routes to the BGP Router
156 * @param notificationService Used to subscribe to notification events
158 public VpnInterfaceManager(final DataBroker db, final IBgpManager bgpManager, NotificationService notificationService) {
159 super(VpnInterface.class);
161 this.bgpManager = bgpManager;
162 interfaceListener = new InterfaceStateChangeListener(db, this);
163 subnetRouteInterfaceListener = new SubnetRouteInterfaceStateChangeListener(db, this);
164 vpnInterfaceOpListener = new VpnInterfaceOpListener();
165 arpNotificationHandler = new ArpNotificationHandler(this, broker);
166 vpnSubnetRouteHandler = new VpnSubnetRouteHandler(broker, bgpManager, this);
167 dpnInVpnChangeListener = new DpnInVpnChangeListener(broker);
168 notificationService.registerNotificationListener(vpnSubnetRouteHandler);
169 notificationService.registerNotificationListener(arpNotificationHandler);
170 notificationService.registerNotificationListener(dpnInVpnChangeListener);
171 registerListener(db);
174 public void setMdsalManager(IMdsalApiManager mdsalManager) {
175 this.mdsalManager = mdsalManager;
178 public void setIfaceMgrRpcService(OdlInterfaceRpcService ifMgrRpcService) {
179 this.ifaceMgrRpcService = ifMgrRpcService;
180 interfaceListener.setIfaceMgrRpcService(ifMgrRpcService);
183 public void setFibManager(IFibManager fibManager) {
184 this.fibManager = fibManager;
187 public IFibManager getFibManager() {
188 return this.fibManager;
192 public void setIdManager(IdManagerService idManager) {
193 this.idManager = idManager;
194 vpnSubnetRouteHandler.setIdManager(idManager);
197 public void setArpManager(OdlArputilService arpManager) {
198 this.arpManager = arpManager;
201 void setNotificationPublishService(NotificationPublishService notificationPublishService) {
202 this.notificationPublishService = notificationPublishService;
205 public void setNeutronvpnManager(NeutronvpnService neuService) { this.neuService = neuService; }
207 public void setFibRpcService(FibRpcService fibService) {
208 this.fibService = fibService;
211 public FibRpcService getFibRpcService() {
215 public VpnSubnetRouteHandler getVpnSubnetRouteHandler() {
216 return this.vpnSubnetRouteHandler;
220 public void close() throws Exception {
221 if (listenerRegistration != null) {
223 listenerRegistration.close();
224 opListenerRegistration.close();
225 } catch (final Exception e) {
226 LOG.error("Error when cleaning up DataChangeListener.", e);
228 listenerRegistration = null;
229 opListenerRegistration = null;
231 LOG.info("VPN Interface Manager Closed");
234 private void registerListener(final DataBroker db) {
236 listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
237 getWildCardPath(), VpnInterfaceManager.this, DataChangeScope.SUBTREE);
238 opListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
239 getWildCardPath(), vpnInterfaceOpListener, DataChangeScope.SUBTREE);
240 } catch (final Exception e) {
241 LOG.error("VPN Service DataChange listener registration fail!", e);
242 throw new IllegalStateException("VPN Service registration Listener failed.", e);
246 private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> getInterfaceListenerPath() {
247 return InstanceIdentifier.create(InterfacesState.class)
248 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class);
252 public void add(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface vpnInterface) {
253 LOG.trace("VPN Interface add event - key: {}, value: {}" ,identifier, vpnInterface );
254 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
255 final String interfaceName = key.getName();
257 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState =
258 InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName);
259 if(interfaceState != null){
261 final BigInteger dpnId = InterfaceUtils.getDpIdFromInterface(interfaceState);
262 final int ifIndex = interfaceState.getIfIndex();
263 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
264 dataStoreCoordinator.enqueueJob("VPNINTERFACE-"+ interfaceName,
265 new Callable<List<ListenableFuture<Void>>>() {
267 public List<ListenableFuture<Void>> call() throws Exception {
268 WriteTransaction writeConfigTxn = broker.newWriteOnlyTransaction();
269 WriteTransaction writeOperTxn = broker.newWriteOnlyTransaction();
270 WriteTransaction writeInvTxn = broker.newWriteOnlyTransaction();
271 processVpnInterfaceUp(dpnId, vpnInterface, ifIndex, false, writeConfigTxn, writeOperTxn, writeInvTxn);
272 CheckedFuture<Void, TransactionCommitFailedException> futures = writeOperTxn.submit();
275 } catch (InterruptedException | ExecutionException e) {
276 LOG.error("Error adding oper data for interface {} to vpn {} on dpn {}", interfaceName,
277 vpnInterface.getVpnInstanceName(), dpnId);
278 throw new RuntimeException(e.getMessage());
280 futures = writeConfigTxn.submit();
283 } catch (InterruptedException | ExecutionException e) {
284 LOG.error("Error adding config data for interface {} to vpn {} on dpn {}", interfaceName,
285 vpnInterface.getVpnInstanceName(), dpnId);
286 throw new RuntimeException(e.getMessage());
288 futures = writeInvTxn.submit();
291 } catch (InterruptedException | ExecutionException e) {
292 LOG.error("Error adding inventory/flow data for interface {} to vpn {} on dpn {}", interfaceName,
293 vpnInterface.getVpnInstanceName(), dpnId);
294 throw new RuntimeException(e.getMessage());
299 }catch (Exception e){
300 LOG.error("Unable to retrieve dpnId from interface operational data store for interface {}. ", interfaceName, e);
304 LOG.info("Handling addition of VPN interface {} skipped as interfaceState is not available", interfaceName);
308 protected void processVpnInterfaceUp(final BigInteger dpId, VpnInterface vpnInterface,
309 final int lPortTag, boolean isInterfaceUp,
310 WriteTransaction writeConfigTxn,
311 WriteTransaction writeOperTxn,
312 WriteTransaction writeInvTxn) {
314 final String interfaceName = vpnInterface.getName();
315 if (!isInterfaceUp) {
316 final String vpnName = vpnInterface.getVpnInstanceName();
317 LOG.info("Binding vpn service to interface {} ", interfaceName);
318 long vpnId = VpnUtil.getVpnId(broker, vpnName);
319 if (vpnId == VpnConstants.INVALID_ID) {
320 LOG.trace("VpnInstance to VPNId mapping is not yet available, bailing out now.");
323 boolean waitForVpnInterfaceOpRemoval = false;
324 VpnInterface opVpnInterface = VpnUtil.getOperationalVpnInterface(broker, vpnInterface.getName());
325 if (opVpnInterface != null ) {
326 String opVpnName = opVpnInterface.getVpnInstanceName();
327 String primaryInterfaceIp = null;
328 if(opVpnName.equals(vpnName)) {
329 // Please check if the primary VRF Entry does not exist for VPNInterface
330 // If so, we have to process ADD, as this might be a DPN Restart with Remove and Add triggered
332 // However, if the primary VRF Entry for this VPNInterface exists, please continue bailing out !
333 List<Adjacency> adjs = VpnUtil.getAdjacenciesForVpnInterfaceFromConfig(broker, interfaceName);
335 LOG.info("VPN Interface {} addition failed as adjacencies for this vpn interface could not be obtained", interfaceName);
338 for (Adjacency adj : adjs) {
339 if (adj.getMacAddress() != null && !adj.getMacAddress().isEmpty()) {
340 primaryInterfaceIp = adj.getIpAddress();
344 if (primaryInterfaceIp == null) {
345 LOG.info("VPN Interface {} addition failed as primary adjacency "
346 + "for this vpn interface could not be obtained", interfaceName);
349 // Get the rd of the vpn instance
350 String rd = getRouteDistinguisher(opVpnName);
351 rd = (rd == null) ? opVpnName : rd;
352 VrfEntry vrf = VpnUtil.getVrfEntry(broker, rd, primaryInterfaceIp);
354 LOG.info("VPN Interface {} already provisioned , bailing out from here.", interfaceName);
357 waitForVpnInterfaceOpRemoval = true;
359 LOG.info("vpn interface {} to go to configured vpn {}, but in operational vpn {}",
360 interfaceName, vpnName, opVpnName);
363 if (!waitForVpnInterfaceOpRemoval) {
364 // Add the VPNInterface and quit
365 updateVpnToDpnMapping(dpId, vpnName, interfaceName, true /* add */);
366 bindService(dpId, vpnName, interfaceName, lPortTag, writeConfigTxn, writeInvTxn);
367 processVpnInterfaceAdjacencies(dpId, vpnName, interfaceName, writeConfigTxn, writeOperTxn);
371 // FIB didn't get a chance yet to clean up this VPNInterface
372 // Let us give it a chance here !
373 LOG.info("VPN Interface {} waiting for FIB to clean up! ", interfaceName);
375 Runnable notifyTask = new VpnNotifyTask();
376 vpnIntfMap.put(interfaceName, notifyTask);
377 synchronized (notifyTask) {
379 notifyTask.wait(VpnConstants.MAX_WAIT_TIME_IN_MILLISECONDS);
380 } catch (InterruptedException e) {
384 vpnIntfMap.remove(interfaceName);
387 opVpnInterface = VpnUtil.getOperationalVpnInterface(broker, interfaceName);
388 if (opVpnInterface != null) {
389 LOG.error("VPN Interface {} removal by FIB did not complete on time, bailing addition ...", interfaceName);
392 // VPNInterface got removed, proceed with Add
393 updateVpnToDpnMapping(dpId, vpnName, interfaceName, true /* add */);
394 bindService(dpId, vpnName, interfaceName, lPortTag, writeConfigTxn, writeInvTxn);
395 processVpnInterfaceAdjacencies(dpId, vpnName, interfaceName, writeConfigTxn, writeOperTxn);
397 // Interface is retained in the DPN, but its Link Up.
398 // Advertise prefixes again for this interface to BGP
399 advertiseAdjacenciesForVpnToBgp(dpId, VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()),
405 // private class UpdateDpnToVpnWorker implements Callable<List<ListenableFuture<Void>>> {
408 // String interfaceName;
412 // public UpdateDpnToVpnWorker(BigInteger dpnId, String vpnName, String interfaceName,
413 // int lPortTag, boolean addToDpn) {
414 // this.dpnId= dpnId;
415 // this.vpnName = vpnName;
416 // this.interfaceName = interfaceName;
417 // this.lPortTag = lPortTag;
418 // this.addToDpn = addToDpn;
422 // public List<ListenableFuture<Void>> call() throws Exception {
423 // // If another renderer(for eg : CSS) needs to be supported, check can be performed here
424 // // to call the respective helpers.
425 // WriteTransaction writeTxn = broker.newWriteOnlyTransaction();
426 // updateDpnDbs(dpnId, vpnName, interfaceName, addToDpn, writeTxn);
427 // List<ListenableFuture<Void>> futures = new ArrayList<>();
428 // futures.add(writeTxn.submit());
429 // ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
430 // Futures.addCallback(listenableFuture,
431 // new UpdateDpnToVpnCallback(dpnId, vpnName, interfaceName, lPortTag, addToDpn));
438 // * JobCallback class is used as a future callback for
439 // * main and rollback workers to handle success and failure.
441 // private class UpdateDpnToVpnCallback implements FutureCallback<List<Void>> {
444 // String interfaceName;
448 // public UpdateDpnToVpnCallback(BigInteger dpnId, String vpnName, String interfaceName,
449 // int lPortTag, boolean addToDpn) {
450 // this.dpnId= dpnId;
451 // this.vpnName = vpnName;
452 // this.interfaceName = interfaceName;
453 // this.lPortTag = lPortTag;
454 // this.addToDpn = addToDpn;
459 // * This implies that all the future instances have returned success. -- TODO: Confirm this
462 // public void onSuccess(List<Void> voids) {
463 // WriteTransaction writeTxn = broker.newWriteOnlyTransaction();
464 // bindService(dpnId, vpnName, interfaceName, lPortTag, writeTxn);
465 // processVpnInterfaceAdjacencies(dpnId, vpnName, interfaceName, writeTxn);
466 // writeTxn.submit();
471 // * @param throwable
472 // * This method is used to handle failure callbacks.
473 // * If more retry needed, the retrycount is decremented and mainworker is executed again.
474 // * After retries completed, rollbackworker is executed.
475 // * If rollbackworker fails, this is a double-fault. Double fault is logged and ignored.
479 // public void onFailure(Throwable throwable) {
480 // LOG.warn("Job: failed with exception: {}", throwable.getStackTrace());
485 private void advertiseAdjacenciesForVpnToBgp(BigInteger dpnId, final InstanceIdentifier<VpnInterface> identifier,
488 InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
489 Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
491 String rd = VpnUtil.getVpnRd(broker, intf.getVpnInstanceName());
493 LOG.error("advertiseAdjacenciesForVpnFromBgp: Unable to recover rd for interface {} in vpn {}",
494 intf.getName(), intf.getVpnInstanceName());
497 if (rd.equals(intf.getVpnInstanceName())) {
498 LOG.info("advertiseAdjacenciesForVpnFromBgp: Ignoring BGP advertisement for interface {} as it is in " +
499 "internal vpn{} with rd {}", intf.getName(), intf.getVpnInstanceName(), rd);
504 LOG.info("advertiseAdjacenciesForVpnToBgp: Advertising interface {} in vpn {} with rd {} ", intf.getName(),
505 intf.getVpnInstanceName(), rd);
507 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
508 if (nextHopIp == null){
509 LOG.trace("advertiseAdjacenciesForVpnToBgp: NextHop for interface {} is null, returning", intf.getName());
513 if (adjacencies.isPresent()) {
514 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
516 if (!nextHops.isEmpty()) {
517 LOG.trace("NextHops are " + nextHops);
518 for (Adjacency nextHop : nextHops) {
519 long label = nextHop.getLabel();
521 LOG.info("VPN ADVERTISE: Adding Fib Entry rd {} prefix {} nexthop {} label {}", rd, nextHop.getIpAddress(), nextHopIp, label);
522 bgpManager.advertisePrefix(rd, nextHop.getIpAddress(), nextHopIp, (int)label);
523 LOG.info("VPN ADVERTISE: Added Fib Entry rd {} prefix {} nexthop {} label {}", rd, nextHop.getIpAddress(), nextHopIp, label);
524 } catch(Exception e) {
525 LOG.error("Failed to advertise prefix {} in vpn {} with rd {} for interface {} ",
526 nextHop.getIpAddress(), intf.getVpnInstanceName(), rd, intf.getName(), e);
533 private void withdrawAdjacenciesForVpnFromBgp(final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
535 InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
536 Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
538 String rd = VpnUtil.getVpnRd(broker, intf.getVpnInstanceName());
540 LOG.error("withdrawAdjacenciesForVpnFromBgp: Unable to recover rd for interface {} in vpn {}",
541 intf.getName(), intf.getVpnInstanceName());
544 if (rd.equals(intf.getVpnInstanceName())) {
545 LOG.info("withdrawAdjacenciesForVpnFromBgp: Ignoring BGP withdrawal for interface {} as it is in " +
546 "internal vpn{} with rd {}", intf.getName(), intf.getVpnInstanceName(), rd);
550 LOG.info("withdrawAdjacenciesForVpnFromBgp: For interface {} in vpn {} with rd {}", intf.getName(),
551 intf.getVpnInstanceName(), rd);
552 if (adjacencies.isPresent()) {
553 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
555 if (!nextHops.isEmpty()) {
556 LOG.trace("NextHops are " + nextHops);
557 for (Adjacency nextHop : nextHops) {
559 LOG.info("VPN WITHDRAW: Removing Fib Entry rd {} prefix {}", rd, nextHop.getIpAddress());
560 bgpManager.withdrawPrefix(rd, nextHop.getIpAddress());
561 LOG.info("VPN WITHDRAW: Removed Fib Entry rd {} prefix {}", rd, nextHop.getIpAddress());
562 } catch(Exception e) {
563 LOG.error("Failed to withdraw prefix {} in vpn {} with rd {} for interface {} ",
564 nextHop.getIpAddress(), intf.getVpnInstanceName(), rd, intf.getName(), e);
571 private void updateVpnToDpnMapping(BigInteger dpId, String vpnName, String interfaceName, boolean add) {
572 long vpnId = VpnUtil.getVpnId(broker, vpnName);
574 dpId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, interfaceName);
576 if(!dpId.equals(BigInteger.ZERO)) {
578 createOrUpdateVpnToDpnList(vpnId, dpId, interfaceName, vpnName);
580 removeOrUpdateVpnToDpnList(vpnId, dpId, interfaceName, vpnName);
584 private void bindService(BigInteger dpId, String vpnInstanceName, String vpnInterfaceName, int lPortTag,
585 WriteTransaction writeConfigTxn, WriteTransaction writeInvTxn) {
586 int priority = VpnConstants.DEFAULT_FLOW_PRIORITY;
587 long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName);
589 int instructionKey = 0;
590 List<Instruction> instructions = new ArrayList<Instruction>();
592 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(MetaDataUtil.getVpnIdMetadata(vpnId),
593 MetaDataUtil.METADATA_MASK_VRFID, ++instructionKey));
594 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.L3_FIB_TABLE, ++instructionKey));
598 InterfaceUtils.getBoundServices(String.format("%s.%s.%s", "vpn",vpnInstanceName, vpnInterfaceName),
599 NwConstants.L3VPN_SERVICE_INDEX, priority,
600 NwConstants.COOKIE_VM_INGRESS_TABLE, instructions);
601 writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION,
602 InterfaceUtils.buildServiceId(vpnInterfaceName, NwConstants.L3VPN_SERVICE_INDEX), serviceInfo, true);
603 makeArpFlow(dpId, NwConstants.L3VPN_SERVICE_INDEX, lPortTag, vpnInterfaceName,
604 vpnId, ArpReplyOrRequest.REQUEST, NwConstants.ADD_FLOW, writeInvTxn);
605 makeArpFlow(dpId, NwConstants.L3VPN_SERVICE_INDEX, lPortTag, vpnInterfaceName,
606 vpnId, ArpReplyOrRequest.REPLY, NwConstants.ADD_FLOW, writeInvTxn);
610 private void processVpnInterfaceAdjacencies(BigInteger dpnId, String vpnName, String interfaceName,
611 WriteTransaction writeConfigTxn,
612 WriteTransaction writeOperTxn) {
613 InstanceIdentifier<VpnInterface> identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
615 InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
616 Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
618 if (adjacencies.isPresent()) {
619 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
620 List<Adjacency> value = new ArrayList<>();
622 // Get the rd of the vpn instance
623 String rd = getRouteDistinguisher(vpnName);
625 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
626 if (nextHopIp == null){
627 LOG.error("NextHop for interface {} is null", interfaceName);
631 List<VpnInstance> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
633 LOG.trace("NextHops for interface {} are {}", interfaceName, nextHops);
634 for (Adjacency nextHop : nextHops) {
635 String prefix = VpnUtil.getIpPrefix(nextHop.getIpAddress());
636 long label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
637 VpnUtil.getNextHopLabelKey((rd == null) ? vpnName
639 List<String> adjNextHop = nextHop.getNextHopIpList();
640 value.add(new AdjacencyBuilder(nextHop).setLabel(label).setNextHopIpList(
641 (adjNextHop != null && !adjNextHop.isEmpty()) ? adjNextHop : Arrays.asList(nextHopIp))
642 .setIpAddress(prefix).setKey(new AdjacencyKey(prefix)).build());
644 if (nextHop.getMacAddress() != null && !nextHop.getMacAddress().isEmpty()) {
645 LOG.trace("Adding prefix {} to interface {} for vpn {}", prefix, interfaceName, vpnName);
647 LogicalDatastoreType.OPERATIONAL,
648 VpnUtil.getPrefixToInterfaceIdentifier(
649 VpnUtil.getVpnId(broker, vpnName), prefix),
650 VpnUtil.getPrefixToInterface(dpnId, interfaceName, prefix), true);
652 //Extra route adjacency
653 LOG.trace("Adding prefix {} and nexthopList {} as extra-route for vpn", nextHop.getIpAddress(), nextHop.getNextHopIpList(), vpnName);
655 LogicalDatastoreType.OPERATIONAL,
656 VpnUtil.getVpnToExtrarouteIdentifier(
657 (rd != null) ? rd : vpnName, nextHop.getIpAddress()),
658 VpnUtil.getVpnToExtraroute(nextHop.getIpAddress(), nextHop.getNextHopIpList()), true);
662 Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(value);
664 VpnInterface opInterface = VpnUtil.getVpnInterface(interfaceName, vpnName, aug, dpnId, Boolean.FALSE);
665 InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
666 writeOperTxn.put(LogicalDatastoreType.OPERATIONAL, interfaceId, opInterface, true);
667 long vpnId = VpnUtil.getVpnId(broker, vpnName);
669 for (Adjacency nextHop : aug.getAdjacency()) {
670 long label = nextHop.getLabel();
671 List<String> nextHopList = new ArrayList<>(nextHop.getNextHopIpList());
673 addToLabelMapper(label, dpnId, nextHop.getIpAddress(), nextHopList, vpnId,
674 interfaceName, null,false, rd, writeOperTxn);
675 addPrefixToBGP(rd, nextHop.getIpAddress(), nextHopIp, label, writeConfigTxn);
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 fibManager.addOrUpdateFibEntry(broker, vpnRd, nextHop.getIpAddress(), Arrays.asList(nextHopIp), (int) label,
682 RouteOrigin.SELF_IMPORTED, writeConfigTxn);
686 // ### add FIB route directly
687 fibManager.addOrUpdateFibEntry(broker, vpnName, nextHop.getIpAddress(), Arrays.asList(nextHopIp),
688 (int) label, RouteOrigin.STATIC, writeConfigTxn);
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,
836 WriteTransaction writeConfigTxn){
837 List<MatchInfo> matches = new ArrayList<MatchInfo>();
838 BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lPortTag, ++sIndex, MetaDataUtil.getVpnIdMetadata(vpnId));
839 BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
840 MetaDataUtil.METADATA_MASK_LPORT_TAG, MetaDataUtil.METADATA_MASK_VRFID);
842 // Matching Arp reply flows
843 matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_ARP }));
844 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
845 metadata, metadataMask }));
847 matches.add(new MatchInfo(MatchFieldType.arp_op, new long[] { replyOrRequest.getArpOperation() }));
849 // Instruction to punt to controller
850 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
851 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
852 actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[] {}));
853 actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[]{
854 Short.toString(NwConstants.LPORT_DISPATCHER_TABLE)}));
856 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
858 // Install the flow entry in L3_INTERFACE_TABLE
859 String flowRef = VpnUtil.getFlowRef(dpId, NwConstants.L3_INTERFACE_TABLE,
860 NwConstants.ETHTYPE_ARP, lPortTag, replyOrRequest.getArpOperation());
861 FlowEntity flowEntity;
862 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_INTERFACE_TABLE, flowRef,
863 NwConstants.DEFAULT_ARP_FLOW_PRIORITY, replyOrRequest.getName(), 0, 0,
864 VpnUtil.getCookieArpFlow(lPortTag), matches, instructions);
866 Flow flow = flowEntity.getFlowBuilder().build();
867 String flowId = flowEntity.getFlowId();
868 FlowKey flowKey = new FlowKey( new FlowId(flowId));
869 Node nodeDpn = buildDpnNode(dpId);
871 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
872 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
873 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
875 if (writeConfigTxn != null) {
876 if (addOrRemoveFlow == NwConstants.ADD_FLOW) {
877 LOG.debug("Creating ARP Flow for interface {}", vpnInterfaceName);
878 writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
880 LOG.debug("Deleting ARP Flow for interface {}", vpnInterfaceName);
881 writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
884 if (addOrRemoveFlow == NwConstants.ADD_FLOW) {
885 LOG.debug("Creating ARP Flow for interface {}",vpnInterfaceName);
886 mdsalManager.installFlow(flowEntity);
888 LOG.debug("Deleting ARP Flow for interface {}",vpnInterfaceName);
889 mdsalManager.removeFlow(flowEntity);
894 //TODO: How to handle the below code, its a copy paste from MDSALManager.java
895 private Node buildDpnNode(BigInteger dpnId) {
896 NodeId nodeId = new NodeId("openflow:" + dpnId);
897 Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
902 private String getRouteDistinguisher(String vpnName) {
903 InstanceIdentifier<VpnInstance> id = InstanceIdentifier.builder(VpnInstances.class)
904 .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
905 Optional<VpnInstance> vpnInstance = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
907 if(vpnInstance.isPresent()) {
908 VpnInstance instance = vpnInstance.get();
909 VpnAfConfig config = instance.getIpv4Family();
910 rd = config.getRouteDistinguisher();
915 private void createOrUpdateVpnToDpnList(long vpnId, BigInteger dpnId, String intfName, String vpnName) {
916 String routeDistinguisher = getRouteDistinguisher(vpnName);
917 String rd = (routeDistinguisher == null) ? vpnName : routeDistinguisher;
918 Boolean newDpnOnVpn = Boolean.FALSE;
920 synchronized (vpnName.intern()) {
921 WriteTransaction writeTxn = broker.newWriteOnlyTransaction();
922 InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
923 Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
924 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data
925 .entry.vpn.to.dpn.list.VpnInterfaces
926 vpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
928 if (dpnInVpn.isPresent()) {
929 if (writeTxn != null) {
930 writeTxn.put(LogicalDatastoreType.OPERATIONAL, id.child(
931 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance
932 .op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
933 new VpnInterfacesKey(intfName)), vpnInterface, true);
935 VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id.child(
936 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance
937 .op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
938 new VpnInterfacesKey(intfName)), vpnInterface);
941 List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
942 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = new ArrayList<>();
943 vpnInterfaces.add(vpnInterface);
944 VpnToDpnListBuilder vpnToDpnListBuilder = new VpnToDpnListBuilder().setDpnId(dpnId);
945 vpnToDpnListBuilder.setDpnState(VpnToDpnList.DpnState.Active).setVpnInterfaces(vpnInterfaces);
947 if (writeTxn != null) {
948 writeTxn.put(LogicalDatastoreType.OPERATIONAL, id, vpnToDpnListBuilder.build(), true);
950 VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id, vpnToDpnListBuilder.build());
952 newDpnOnVpn = Boolean.TRUE;
954 CheckedFuture<Void, TransactionCommitFailedException> futures = writeTxn.submit();
957 } catch (InterruptedException | ExecutionException e) {
958 LOG.error("Error adding to dpnToVpnList for vpn {} interface {} dpn {}", vpnName, intfName, dpnId);
959 throw new RuntimeException(e.getMessage());
962 * Informing the Fib only after writeTxn is submitted successfuly.
965 LOG.debug("Sending populateFib event for new dpn {} in VPN {}", dpnId, vpnName);
966 fibManager.populateFibOnNewDpn(dpnId, vpnId, rd);
967 publishAddNotification(dpnId, vpnName, rd);
972 private void removeOrUpdateVpnToDpnList(long vpnId, BigInteger dpnId, String intfName, String vpnName) {
973 Boolean lastDpnOnVpn = Boolean.FALSE;
975 synchronized (vpnName.intern()) {
976 String rd = VpnUtil.getVpnRd(broker, vpnName);
977 InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
978 Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
979 WriteTransaction writeTxn = broker.newWriteOnlyTransaction();
980 if (dpnInVpn.isPresent()) {
981 List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
982 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
983 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
984 currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
986 if (vpnInterfaces.remove(currVpnInterface)) {
987 if (vpnInterfaces.isEmpty()) {
988 List<IpAddresses> ipAddresses = dpnInVpn.get().getIpAddresses();
989 if (ipAddresses == null || ipAddresses.isEmpty()) {
990 VpnToDpnListBuilder dpnInVpnBuilder =
991 new VpnToDpnListBuilder(dpnInVpn.get())
992 .setDpnState(VpnToDpnList.DpnState.Inactive)
993 .setVpnInterfaces(null);
994 if (writeTxn != null) {
995 writeTxn.put(LogicalDatastoreType.OPERATIONAL, id, dpnInVpnBuilder.build(), true);
997 VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id, dpnInVpnBuilder.build());
999 lastDpnOnVpn = Boolean.TRUE;
1001 LOG.warn("vpn interfaces are empty but ip addresses are present for the vpn {} in dpn {}", vpnName, dpnId);
1004 if (writeTxn != null) {
1005 writeTxn.delete(LogicalDatastoreType.OPERATIONAL, id.child(
1006 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
1007 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
1008 new VpnInterfacesKey(intfName)));
1010 VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
1011 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
1012 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
1013 new VpnInterfacesKey(intfName)), VpnUtil.DEFAULT_CALLBACK);
1018 CheckedFuture<Void, TransactionCommitFailedException> futures = writeTxn.submit();
1021 } catch (InterruptedException | ExecutionException e) {
1022 LOG.error("Error removing from dpnToVpnList for vpn {} interface {} dpn {}", vpnName, intfName, dpnId);
1023 throw new RuntimeException(e.getMessage());
1026 LOG.debug("Sending cleanup event for dpn {} in VPN {}", dpnId, vpnName);
1027 fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd);
1028 publishRemoveNotification(dpnId, vpnName, rd);
1033 void handleVpnsExportingRoutes(String vpnName, String vpnRd) {
1034 List<VpnInstance> vpnsToExportRoute = getVpnsExportingMyRoute(vpnName);
1035 for (VpnInstance vpn : vpnsToExportRoute) {
1036 String rd = vpn.getIpv4Family().getRouteDistinguisher();
1037 List<VrfEntry> vrfEntries = VpnUtil.getAllVrfEntries(broker, vpn.getIpv4Family().getRouteDistinguisher());
1038 WriteTransaction writeConfigTxn = broker.newWriteOnlyTransaction();
1039 if (vrfEntries != null) {
1040 for (VrfEntry vrfEntry : vrfEntries) {
1042 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.STATIC) {
1045 String prefix = vrfEntry.getDestPrefix();
1046 long label = vrfEntry.getLabel();
1047 List<String> nextHops = vrfEntry.getNextHopAddressList();
1048 SubnetRoute route = vrfEntry.getAugmentation(SubnetRoute.class);
1049 for (String nh : nextHops) {
1050 if (route != null) {
1051 LOG.info("Importing subnet route fib entry rd {} prefix {} nexthop {} label {} to vpn {}", vpnRd, prefix, nh, label, vpn.getVpnInstanceName());
1052 importSubnetRouteForNewVpn(rd, prefix, nh, (int)label, route, writeConfigTxn);
1054 LOG.info("Importing fib entry rd {} prefix {} nexthop {} label {} to vpn {}", vpnRd, prefix, nh, label, vpn.getVpnInstanceName());
1055 fibManager.addOrUpdateFibEntry(broker, vpnRd, prefix, Arrays.asList(nh), (int)label,
1056 RouteOrigin.SELF_IMPORTED, writeConfigTxn);
1059 } catch (Exception e) {
1060 LOG.error("Exception occurred while importing route with prefix {} label {} nexthop {} from vpn {} to vpn {}", vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(), vpn.getVpnInstanceName(), vpnName);
1063 writeConfigTxn.submit();
1065 LOG.info("No vrf entries to import from vpn {} with rd {}", vpn.getVpnInstanceName(), vpn.getIpv4Family().getRouteDistinguisher());
1070 private void addPrefixToBGP(String rd, String prefix, String nextHopIp, long label, WriteTransaction writeConfigTxn) {
1072 LOG.info("ADD: Adding Fib entry rd {} prefix {} nextHop {} label {}", rd, prefix, nextHopIp, label);
1073 fibManager.addOrUpdateFibEntry(broker, rd, prefix, Arrays.asList(nextHopIp), (int)label, RouteOrigin.STATIC, writeConfigTxn);
1074 bgpManager.advertisePrefix(rd, prefix, Arrays.asList(nextHopIp), (int)label);
1075 LOG.info("ADD: Added Fib entry rd {} prefix {} nextHop {} label {}", rd, prefix, nextHopIp, label);
1076 } catch(Exception e) {
1077 LOG.error("Add prefix failed", e);
1082 private InstanceIdentifier<VpnInterface> getWildCardPath() {
1083 return InstanceIdentifier.create(VpnInterfaces.class).child(VpnInterface.class);
1087 public void remove( InstanceIdentifier<VpnInterface> identifier, VpnInterface vpnInterface) {
1088 LOG.trace("Remove event - key: {}, value: {}" ,identifier, vpnInterface );
1089 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
1090 final String interfaceName = key.getName();
1092 InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
1093 final Optional<VpnInterface> optVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, interfaceId);
1094 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState =
1095 InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName);
1096 if (optVpnInterface.isPresent()){
1097 BigInteger dpnId = BigInteger.ZERO;
1098 Boolean dpnIdRetrieved = Boolean.FALSE;
1099 if(interfaceState != null){
1101 dpnId = InterfaceUtils.getDpIdFromInterface(interfaceState);
1102 dpnIdRetrieved = Boolean.TRUE;
1103 }catch (Exception e){
1104 LOG.error("Unable to retrieve dpnId from interface operational data store for interface {}. Fetching from vpn interface op data store. ", interfaceName, e);
1107 LOG.error("Unable to retrieve interfaceState for interface {} , quitting ", interfaceName);
1110 final VpnInterface vpnOpInterface = optVpnInterface.get();
1111 if(dpnIdRetrieved == Boolean.FALSE){
1112 LOG.info("dpnId for {} has not been retrieved yet. Fetching from vpn interface operational DS", interfaceName);
1113 dpnId = vpnOpInterface.getDpnId();
1115 final int ifIndex = interfaceState.getIfIndex();
1116 final BigInteger dpId = dpnId;
1117 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1118 dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + interfaceName,
1119 new Callable<List<ListenableFuture<Void>>>() {
1121 public List<ListenableFuture<Void>> call() throws Exception {
1122 WriteTransaction writeConfigTxn = broker.newWriteOnlyTransaction();
1123 WriteTransaction writeOperTxn = broker.newWriteOnlyTransaction();
1124 WriteTransaction writeInvTxn = broker.newWriteOnlyTransaction();
1125 processVpnInterfaceDown(dpId, interfaceName, ifIndex, false, true, writeConfigTxn, writeOperTxn, writeInvTxn);
1126 CheckedFuture<Void, TransactionCommitFailedException> futures = writeOperTxn.submit();
1129 } catch (InterruptedException | ExecutionException e) {
1130 LOG.error("Error removing Oper data for interface {} from vpn {} on dpn {}", interfaceName,
1131 vpnOpInterface.getVpnInstanceName(), dpId);
1132 throw new RuntimeException(e.getMessage());
1134 futures = writeConfigTxn.submit();
1137 } catch (InterruptedException | ExecutionException e) {
1138 LOG.error("Error removing Config data for interface {} from vpn {} on dpn {}", interfaceName,
1139 vpnOpInterface.getVpnInstanceName(), dpId);
1140 throw new RuntimeException(e.getMessage());
1142 futures = writeInvTxn.submit();
1145 } catch (InterruptedException | ExecutionException e) {
1146 LOG.error("Error removing Inventory/Flow data for interface {} from vpn {} on dpn {}", interfaceName,
1147 vpnOpInterface.getVpnInstanceName(), dpId);
1148 throw new RuntimeException(e.getMessage());
1155 LOG.warn("VPN interface {} was unavailable in operational data store to handle remove event", interfaceName);
1159 protected void processVpnInterfaceDown(BigInteger dpId,
1160 String interfaceName,
1162 boolean isInterfaceStateDown,
1163 boolean isConfigRemoval,
1164 WriteTransaction writeConfigTxn,
1165 WriteTransaction writeOperTxn,
1166 WriteTransaction writeInvTxn) {
1167 InstanceIdentifier<VpnInterface> identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
1168 if (!isInterfaceStateDown) {
1169 VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(broker, interfaceName);
1170 if(vpnInterface == null){
1171 LOG.info("Unable to process delete/down for interface {} as it is not available in operational data store", interfaceName);
1174 final String vpnName = vpnInterface.getVpnInstanceName();
1175 if(!vpnInterface.isScheduledForRemove()){
1176 VpnUtil.scheduleVpnInterfaceForRemoval(broker, interfaceName, dpId, vpnName, Boolean.TRUE, writeOperTxn);
1177 removeAdjacenciesFromVpn(dpId, interfaceName, vpnInterface.getVpnInstanceName(), writeConfigTxn);
1178 LOG.info("Unbinding vpn service from interface {} ", interfaceName);
1179 unbindService(dpId, vpnName, interfaceName, lPortTag, isInterfaceStateDown, isConfigRemoval, writeConfigTxn, writeInvTxn);
1181 LOG.info("Unbinding vpn service for interface {} has already been scheduled by a different event ", interfaceName);
1186 // Interface is retained in the DPN, but its Link Down.
1187 // Only withdraw the prefixes for this interface from BGP
1188 VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(broker, interfaceName);
1189 if(vpnInterface == null){
1190 LOG.info("Unable to withdraw adjacencies for vpn interface {} from BGP as it is not available in operational data store", interfaceName);
1193 withdrawAdjacenciesForVpnFromBgp(identifier, vpnInterface);
1198 private void waitForFibToRemoveVpnPrefix(String interfaceName) {
1199 // FIB didn't get a chance yet to clean up this VPNInterface
1200 // Let us give it a chance here !
1201 LOG.info("VPN Interface {} removal waiting for FIB to clean up ! ", interfaceName);
1203 Runnable notifyTask = new VpnNotifyTask();
1204 vpnIntfMap.put(interfaceName, notifyTask);
1205 synchronized (notifyTask) {
1207 notifyTask.wait(VpnConstants.PER_INTERFACE_MAX_WAIT_TIME_IN_MILLISECONDS);
1208 } catch (InterruptedException e) {
1212 vpnIntfMap.remove(interfaceName);
1216 private void removeAdjacenciesFromVpn(final BigInteger dpnId, final String interfaceName, final String vpnName,
1217 WriteTransaction writeConfigTxn) {
1219 InstanceIdentifier<VpnInterface> identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
1220 InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
1221 Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
1223 String rd = VpnUtil.getVpnRd(broker, vpnName);
1224 LOG.trace("removeAdjacenciesFromVpn: For interface {} RD recovered for vpn {} as rd {}", interfaceName,
1226 if (adjacencies.isPresent()) {
1227 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
1229 if (!nextHops.isEmpty()) {
1230 LOG.trace("NextHops are " + nextHops);
1231 for (Adjacency nextHop : nextHops) {
1232 List<String> nhList = new ArrayList<String>();
1233 if (nextHop.getMacAddress() == null || nextHop.getMacAddress().isEmpty()) {
1234 // This is either an extra-route (or) a learned IP via subnet-route
1235 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
1236 if (nextHopIp == null || nextHopIp.isEmpty()) {
1237 LOG.error("Unable to obtain nextHopIp for extra-route/learned-route in rd {} prefix {}",
1238 rd, nextHop.getIpAddress());
1241 nhList = Arrays.asList(nextHopIp);
1243 // This is a primary adjacency
1244 nhList = nextHop.getNextHopIpList();
1246 if (rd.equals(vpnName)) {
1247 //this is an internal vpn - the rd is assigned to the vpn instance name;
1248 //remove from FIB directly
1249 for(String nh : nhList) {
1250 fibManager.removeOrUpdateFibEntry(broker, vpnName, nextHop.getIpAddress(), nh, writeConfigTxn);
1253 List<VpnInstance> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
1254 for (String nh : nhList) {
1255 //IRT: remove routes from other vpns importing it
1256 removePrefixFromBGP(rd, nextHop.getIpAddress(), nh, writeConfigTxn);
1257 for (VpnInstance vpn : vpnsToImportRoute) {
1258 String vpnRd = vpn.getIpv4Family().getRouteDistinguisher();
1259 if (vpnRd != null) {
1260 LOG.info("Removing Exported route with rd {} prefix {} from VPN {}", vpnRd, nextHop.getIpAddress(), vpn.getVpnInstanceName());
1261 fibManager.removeOrUpdateFibEntry(broker, vpnRd, nextHop.getIpAddress(), nh, writeConfigTxn);
1266 String ip = nextHop.getIpAddress().split("/")[0];
1267 VpnPortipToPort vpnPortipToPort = VpnUtil.getNeutronPortFromVpnPortFixedIp(broker,
1269 if (vpnPortipToPort != null && !vpnPortipToPort.isConfig()) {
1270 LOG.trace("VpnInterfaceManager removing adjacency for Interface {} ip {} from VpnPortData Entry",
1271 vpnPortipToPort.getPortName(),ip);
1272 VpnUtil.removeVpnPortFixedIpToPort(broker, vpnName, ip);
1280 private void unbindService(BigInteger dpId, String vpnInstanceName, String vpnInterfaceName,
1281 int lPortTag, boolean isInterfaceStateDown, boolean isConfigRemoval,
1282 WriteTransaction writeConfigTxn, WriteTransaction writeInvTxn) {
1283 if (!isInterfaceStateDown && isConfigRemoval) {
1284 writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION,
1285 InterfaceUtils.buildServiceId(vpnInterfaceName,
1286 NwConstants.L3VPN_SERVICE_INDEX));
1288 long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName);
1289 makeArpFlow(dpId, NwConstants.L3VPN_SERVICE_INDEX, lPortTag, vpnInterfaceName,
1290 vpnId, ArpReplyOrRequest.REQUEST, NwConstants.DEL_FLOW, writeInvTxn);
1291 makeArpFlow(dpId, NwConstants.L3VPN_SERVICE_INDEX, lPortTag, vpnInterfaceName,
1292 vpnId, ArpReplyOrRequest.REPLY, NwConstants.DEL_FLOW, writeInvTxn);
1296 private void removePrefixFromBGP(String rd, String prefix, String nextHop, WriteTransaction writeConfigTxn) {
1298 LOG.info("VPN WITHDRAW: Removing Fib Entry rd {} prefix {}", rd, prefix);
1299 fibManager.removeOrUpdateFibEntry(broker, rd, prefix, nextHop, writeConfigTxn);
1300 bgpManager.withdrawPrefix(rd, prefix); // TODO: Might be needed to include nextHop here
1301 LOG.info("VPN WITHDRAW: Removed Fib Entry rd {} prefix {}", rd, prefix);
1302 } catch(Exception e) {
1303 LOG.error("Delete prefix failed", e);
1308 protected void update(InstanceIdentifier<VpnInterface> identifier, VpnInterface original, VpnInterface update) {
1309 LOG.trace("Updating VPN Interface : key {}, original value={}, update value={}", identifier, original, update);
1310 String oldVpnName = original.getVpnInstanceName();
1311 String newVpnName = update.getVpnInstanceName();
1312 BigInteger dpnId = update.getDpnId();
1313 List<Adjacency> oldAdjs = original.getAugmentation(Adjacencies.class).getAdjacency();
1314 List<Adjacency> newAdjs = update.getAugmentation(Adjacencies.class).getAdjacency();
1315 if (oldAdjs == null) {
1316 oldAdjs = new ArrayList<>();
1318 if (newAdjs == null) {
1319 newAdjs = new ArrayList<>();
1321 //handles switching between <internal VPN - external VPN>
1322 if (!oldVpnName.equals(newVpnName)) {
1323 remove(identifier, original);
1324 waitForFibToRemoveVpnPrefix(update.getName());
1325 add(identifier, update);
1327 //handle both addition and removal of adjacencies
1328 //currently, new adjacency may be an extra route
1329 if (!oldAdjs.equals(newAdjs)) {
1330 for (Adjacency adj : newAdjs) {
1331 if (oldAdjs.contains(adj)) {
1332 oldAdjs.remove(adj);
1334 // add new adjacency - right now only extra route will hit this path
1335 addNewAdjToVpnInterface(identifier, adj, dpnId);
1338 for (Adjacency adj : oldAdjs) {
1339 delAdjFromVpnInterface(identifier, adj, dpnId);
1344 public void processArpRequest(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715
1345 .IpAddress srcIP, PhysAddress srcMac, org.opendaylight.yang.gen.v1.urn.ietf
1346 .params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress targetIP, PhysAddress targetMac, String srcInterface){
1347 //Build ARP response with ARP requests TargetIp TargetMac as the Arp Response SrcIp and SrcMac
1348 SendArpResponseInput input = new SendArpResponseInputBuilder().setInterface(srcInterface)
1349 .setDstIpaddress(srcIP).setDstMacaddress(srcMac).setSrcIpaddress(targetIP).setSrcMacaddress(targetMac).build();
1350 final String msgFormat = String.format("Send ARP Response on interface %s to destination %s", srcInterface, srcIP);
1351 Future<RpcResult<Void>> future = arpManager.sendArpResponse(input);
1352 Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future), new FutureCallback<RpcResult<Void>>() {
1354 public void onFailure(Throwable error) {
1355 LOG.error("Error - {}", msgFormat, error);
1359 public void onSuccess(RpcResult<Void> result) {
1360 if(!result.isSuccessful()) {
1361 LOG.warn("Rpc call to {} failed", msgFormat, getErrorText(result.getErrors()));
1363 LOG.debug("Successful RPC Result - {}", msgFormat);
1369 private String getErrorText(Collection<RpcError> errors) {
1370 StringBuilder errorText = new StringBuilder();
1371 for(RpcError error : errors) {
1372 errorText.append(",").append(error.getErrorType()).append("-")
1373 .append(error.getMessage());
1375 return errorText.toString();
1378 private void addToLabelMapper(Long label, BigInteger dpnId, String prefix, List<String> nextHopIpList, Long vpnId,
1379 String vpnInterfaceName, Long elanTag, boolean isSubnetRoute, String rd,
1380 WriteTransaction writeOperTxn) {
1381 Preconditions.checkNotNull(label, "label cannot be null or empty!");
1382 Preconditions.checkNotNull(prefix, "prefix cannot be null or empty!");
1383 Preconditions.checkNotNull(vpnId, "vpnId cannot be null or empty!");
1384 Preconditions.checkNotNull(rd, "rd cannot be null or empty!");
1385 if (!isSubnetRoute) {
1386 // NextHop must be present for non-subnetroute entries
1387 Preconditions.checkNotNull(nextHopIpList, "nextHopIp cannot be null or empty!");
1389 LOG.info("Adding to label mapper : label {} dpn {} prefix {} nexthoplist {} vpnid {} vpnIntfcName {} rd {}", label, dpnId, prefix, nextHopIpList, vpnId, vpnInterfaceName, rd);
1390 if (dpnId != null) {
1391 InstanceIdentifier<LabelRouteInfo> lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
1392 .child(LabelRouteInfo.class, new LabelRouteInfoKey((long)label)).build();
1393 LabelRouteInfoBuilder lriBuilder = new LabelRouteInfoBuilder();
1394 lriBuilder.setLabel(label).setDpnId(dpnId).setPrefix(prefix).setNextHopIpList(nextHopIpList).setParentVpnid(vpnId)
1395 .setIsSubnetRoute(isSubnetRoute);
1396 if (elanTag != null) {
1397 lriBuilder.setElanTag(elanTag);
1399 if (vpnInterfaceName != null) {
1400 lriBuilder.setVpnInterfaceName(vpnInterfaceName);
1402 lriBuilder.setParentVpnRd(rd);
1403 VpnInstanceOpDataEntry vpnInstanceOpDataEntry = VpnUtil.getVpnInstanceOpData(broker, rd);
1404 if (vpnInstanceOpDataEntry != null) {
1405 List<String> vpnInstanceNames = Arrays.asList(vpnInstanceOpDataEntry.getVpnInstanceName());
1406 lriBuilder.setVpnInstanceList(vpnInstanceNames);
1408 LabelRouteInfo lri = lriBuilder.build();
1409 LOG.trace("Adding route info to label map: {}", lri);
1410 if (writeOperTxn != null) {
1411 writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL, lriIid, lri, true);
1413 VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, lriIid, lri);
1416 LOG.trace("Can't add entry to label map for lable {},dpnId is null", label);
1420 public synchronized void addSubnetRouteFibEntryToDS(String rd, String vpnName, String prefix, String nextHop, int label,
1421 long elantag, BigInteger dpnId, WriteTransaction writeTxn) {
1422 SubnetRoute route = new SubnetRouteBuilder().setElantag(elantag).build();
1423 RouteOrigin origin = RouteOrigin.STATIC; // Only case when a route is considered as directly connected
1424 VrfEntry vrfEntry = new VrfEntryBuilder().setDestPrefix(prefix).setNextHopAddressList(Arrays.asList(nextHop))
1425 .setLabel((long)label).setOrigin(origin.getValue())
1426 .addAugmentation(SubnetRoute.class, route).build();
1428 LOG.debug("Created vrfEntry for {} nexthop {} label {} and elantag {}", prefix, nextHop, label, elantag);
1430 //TODO: What should be parentVpnId? Get it from RD?
1431 long vpnId = VpnUtil.getVpnId(broker, vpnName);
1432 addToLabelMapper((long)label, dpnId, prefix, Arrays.asList(nextHop), vpnId, null, elantag, true, rd, null);
1433 List<VrfEntry> vrfEntryList = Arrays.asList(vrfEntry);
1435 InstanceIdentifierBuilder<VrfTables> idBuilder =
1436 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
1437 InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
1439 VrfTables vrfTableNew = new VrfTablesBuilder().setRouteDistinguisher(rd).
1440 setVrfEntry(vrfEntryList).build();
1442 if (writeTxn != null) {
1443 writeTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew, true);
1445 VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
1448 List<VpnInstance> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
1449 if (vpnsToImportRoute.size() > 0) {
1450 VrfEntry importingVrfEntry = new VrfEntryBuilder().setDestPrefix(prefix).setNextHopAddressList(Arrays.asList(nextHop))
1451 .setLabel((long) label).setOrigin(RouteOrigin.SELF_IMPORTED.getValue())
1452 .addAugmentation(SubnetRoute.class, route).build();
1453 List<VrfEntry> importingVrfEntryList = Arrays.asList(importingVrfEntry);
1454 for (VpnInstance vpnInstance : vpnsToImportRoute) {
1455 LOG.info("Exporting subnet route rd {} prefix {} nexthop {} label {} to vpn {}", rd, prefix, nextHop, label, vpnInstance.getVpnInstanceName());
1456 String importingRd = vpnInstance.getIpv4Family().getRouteDistinguisher();
1457 InstanceIdentifier<VrfTables> importingVrfTableId = InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(importingRd)).build();
1458 VrfTables importingVrfTable = new VrfTablesBuilder().setRouteDistinguisher(importingRd).setVrfEntry(importingVrfEntryList).build();
1459 if (writeTxn != null) {
1460 writeTxn.merge(LogicalDatastoreType.CONFIGURATION, importingVrfTableId, importingVrfTable, true);
1462 VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, importingVrfTableId, importingVrfTable);
1468 public synchronized void importSubnetRouteForNewVpn(String rd, String prefix, String nextHop, int label,
1469 SubnetRoute route, WriteTransaction writeConfigTxn) {
1471 RouteOrigin origin = RouteOrigin.SELF_IMPORTED;
1472 VrfEntry vrfEntry = new VrfEntryBuilder().setDestPrefix(prefix).setNextHopAddressList(Arrays.asList(nextHop))
1473 .setLabel((long)label).setOrigin(origin.getValue())
1474 .addAugmentation(SubnetRoute.class, route).build();
1475 LOG.debug("Created vrfEntry for {} nexthop {} label {} and elantag {}", prefix, nextHop, label, route.getElantag());
1476 List<VrfEntry> vrfEntryList = Arrays.asList(vrfEntry);
1477 InstanceIdentifierBuilder<VrfTables> idBuilder =
1478 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
1479 InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
1480 VrfTables vrfTableNew = new VrfTablesBuilder().setRouteDistinguisher(rd).
1481 setVrfEntry(vrfEntryList).build();
1482 if (writeConfigTxn != null) {
1483 writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew, true);
1485 VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
1489 public synchronized void deleteSubnetRouteFibEntryFromDS(String rd, String prefix, String vpnName){
1490 fibManager.removeOrUpdateFibEntry(broker, rd, prefix, null /* nextHopToRemove */, null);
1491 List<VpnInstance> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
1492 for (VpnInstance vpnInstance : vpnsToImportRoute) {
1493 String importingRd = vpnInstance.getIpv4Family().getRouteDistinguisher();
1494 LOG.info("Deleting imported subnet route rd {} prefix {} from vpn {}", rd, prefix, vpnInstance.getVpnInstanceName());
1495 fibManager.removeOrUpdateFibEntry(broker, importingRd, prefix, null /* nextHopToRemove */, null);
1499 protected void addNewAdjToVpnInterface(InstanceIdentifier<VpnInterface> identifier, Adjacency adj, BigInteger dpnId) {
1501 Optional<VpnInterface> optVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
1503 if (optVpnInterface.isPresent()) {
1504 VpnInterface currVpnIntf = optVpnInterface.get();
1505 String prefix = VpnUtil.getIpPrefix(adj.getIpAddress());
1506 String rd = getRouteDistinguisher(currVpnIntf.getVpnInstanceName());
1507 InstanceIdentifier<Adjacencies> adjPath = identifier.augmentation(Adjacencies.class);
1508 Optional<Adjacencies> optAdjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, adjPath);
1510 VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
1511 VpnUtil.getNextHopLabelKey((rd != null) ? rd : currVpnIntf.getVpnInstanceName(), prefix));
1513 List<Adjacency> adjacencies;
1514 if (optAdjacencies.isPresent()) {
1515 adjacencies = optAdjacencies.get().getAdjacency();
1517 //This code will not be hit since VM adjacency will always be there
1518 adjacencies = new ArrayList<>();
1521 adjacencies.add(new AdjacencyBuilder(adj).setLabel(label).setNextHopIpList(adj.getNextHopIpList())
1522 .setIpAddress(prefix).setKey(new AdjacencyKey(prefix)).build());
1524 Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencies);
1525 VpnInterface newVpnIntf = VpnUtil.getVpnInterface(currVpnIntf.getName(), currVpnIntf.getVpnInstanceName(), aug, dpnId, currVpnIntf.isScheduledForRemove());
1527 VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, newVpnIntf);
1528 for (String nh : adj.getNextHopIpList()) {
1529 addExtraRoute(adj.getIpAddress(), nh, rd, currVpnIntf.getVpnInstanceName(), (int) label,
1530 currVpnIntf.getName());
1535 protected void delAdjFromVpnInterface(InstanceIdentifier<VpnInterface> identifier, Adjacency adj, BigInteger dpnId) {
1536 Optional<VpnInterface> optVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
1538 if (optVpnInterface.isPresent()) {
1539 VpnInterface currVpnIntf = optVpnInterface.get();
1541 InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
1542 Optional<Adjacencies> optAdjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
1543 if (optAdjacencies.isPresent()) {
1544 List<Adjacency> adjacencies = optAdjacencies.get().getAdjacency();
1546 if (!adjacencies.isEmpty()) {
1547 String rd = getRouteDistinguisher(currVpnIntf.getVpnInstanceName());
1548 LOG.trace("Adjacencies are " + adjacencies);
1549 Iterator<Adjacency> adjIt = adjacencies.iterator();
1550 while (adjIt.hasNext()) {
1551 Adjacency adjElem = adjIt.next();
1552 if (adjElem.getIpAddress().equals(adj.getIpAddress())) {
1555 Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencies);
1556 VpnInterface newVpnIntf = VpnUtil.getVpnInterface(currVpnIntf.getName(),
1557 currVpnIntf.getVpnInstanceName(),
1558 aug, dpnId, currVpnIntf.isScheduledForRemove());
1560 VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, newVpnIntf);
1562 for (String nh : adj.getNextHopIpList()) {
1563 delExtraRoute(adj.getIpAddress(), nh, rd, currVpnIntf.getVpnInstanceName(),
1564 currVpnIntf.getName());
1576 protected void addExtraRoute(String destination, String nextHop, String rd, String routerID, int label,
1579 //add extra route to vpn mapping; advertise with nexthop as tunnel ip
1582 LogicalDatastoreType.OPERATIONAL,
1583 VpnUtil.getVpnToExtrarouteIdentifier( (rd != null) ? rd : routerID, destination),
1584 VpnUtil.getVpnToExtraroute(destination, Arrays.asList(nextHop)));
1586 BigInteger dpnId = null;
1587 if (intfName != null && !intfName.isEmpty()) {
1588 dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, intfName);
1589 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
1590 if (nextHopIp == null || nextHopIp.isEmpty()) {
1591 LOG.error("NextHop for interface {} is null / empty. Failed advertising extra route for prefix {}",
1592 intfName, destination);
1595 nextHop = nextHopIp;
1597 List<String> nextHopIpList = Arrays.asList(nextHop);
1599 /* Label mapper is required only for BGP VPN and not for Internal VPN */
1600 addToLabelMapper((long) label, dpnId, destination, nextHopIpList, VpnUtil.getVpnId(broker, routerID),
1601 intfName, null, false, rd, null);
1604 // TODO (eperefr): This is a limitation to be stated in docs. When configuring static route to go to
1605 // another VPN, there can only be one nexthop or, at least, the nexthop to the interVpnLink should be in
1607 InterVpnLink interVpnLink = VpnUtil.getInterVpnLinkByEndpointIp(broker, nextHop);
1608 if ( interVpnLink != null ) {
1609 // If the nexthop is the endpoint of Vpn2, then prefix must be advertised to Vpn1 in DC-GW, with nexthops
1610 // pointing to the DPNs where Vpn1 is instantiated. LFIB in these DPNS must have a flow entry, with lower
1611 // priority, where if Label matches then sets the lportTag of the Vpn2 endpoint and goes to LportDispatcher
1612 // This is like leaking one of the Vpn2 routes towards Vpn1
1613 boolean nexthopIsVpn2 = ( interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(nextHop) );
1614 String srcVpnUuid = (nexthopIsVpn2) ? interVpnLink.getSecondEndpoint().getVpnUuid().getValue()
1615 : interVpnLink.getFirstEndpoint().getVpnUuid().getValue();
1616 String dstVpnUuid = (nexthopIsVpn2) ? interVpnLink.getFirstEndpoint().getVpnUuid().getValue()
1617 : interVpnLink.getSecondEndpoint().getVpnUuid().getValue();
1618 String dstVpnRd = VpnUtil.getVpnRd(broker, dstVpnUuid);
1619 long newLabel = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
1620 VpnUtil.getNextHopLabelKey(dstVpnRd, destination));
1621 VpnUtil.leakRoute(broker, bgpManager, interVpnLink, srcVpnUuid, dstVpnUuid, destination, newLabel);
1624 addPrefixToBGP(rd, destination, nextHop, label, null);
1626 // ### add FIB route directly
1627 fibManager.addOrUpdateFibEntry(broker, routerID, destination, Arrays.asList(nextHop), label, RouteOrigin.STATIC, null);
1632 protected void delExtraRoute(String destination, String nextHop, String rd, String routerID, String intfName) {
1633 if (intfName != null && !intfName.isEmpty()) {
1634 BigInteger dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, intfName);
1635 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
1636 if (nextHopIp == null || nextHopIp.isEmpty()) {
1637 LOG.warn("NextHop for interface {} is null / empty. Failed advertising extra route for prefix {}",
1638 intfName, destination);
1640 nextHop = nextHopIp;
1644 removePrefixFromBGP(rd, destination, nextHop, null);
1646 // ### add FIB route directly
1647 fibManager.removeOrUpdateFibEntry(broker, routerID, destination, nextHop, null);
1651 class VpnInterfaceOpListener extends org.opendaylight.genius.mdsalutil.AbstractDataChangeListener<VpnInterface> {
1653 public VpnInterfaceOpListener() {
1654 super(VpnInterface.class);
1658 protected void remove(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface del) {
1659 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
1660 final String interfaceName = key.getName();
1661 final String vpnName = del.getVpnInstanceName();
1662 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1663 dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + interfaceName,
1664 new Callable<List<ListenableFuture<Void>>>() {
1666 public List<ListenableFuture<Void>> call() throws Exception {
1667 WriteTransaction writeOperTxn = broker.newWriteOnlyTransaction();
1668 postProcessVpnInterfaceRemoval(identifier, del, writeOperTxn);
1669 CheckedFuture<Void, TransactionCommitFailedException> futures = writeOperTxn.submit();
1672 } catch (InterruptedException | ExecutionException e) {
1673 LOG.error("Error handling removal of oper data for interface {} from vpn {}", interfaceName,
1675 throw new RuntimeException(e.getMessage());
1682 private void postProcessVpnInterfaceRemoval(InstanceIdentifier<VpnInterface> identifier, VpnInterface del,
1683 WriteTransaction writeOperTxn) {
1684 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
1685 String interfaceName = key.getName();
1686 String vpnName = del.getVpnInstanceName();
1688 LOG.trace("VpnInterfaceOpListener removed: interface name {} vpnName {}", interfaceName, vpnName);
1689 //decrement the vpn interface count in Vpn Instance Op Data
1690 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to
1691 .vpn.id.VpnInstance>
1692 id = VpnUtil.getVpnInstanceToVpnIdIdentifier(vpnName);
1693 Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
1694 .VpnInstance> vpnInstance
1695 = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
1697 if (vpnInstance.isPresent()) {
1699 rd = vpnInstance.get().getVrfId();
1700 //String rd = getRouteDistinguisher(del.getVpnInstanceName());
1702 VpnInstanceOpDataEntry vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
1703 LOG.trace("VpnInterfaceOpListener removed: interface name {} rd {} vpnName {} in Vpn Op Instance {}",
1704 interfaceName, rd, vpnName, vpnInstOp);
1706 if (vpnInstOp != null) {
1707 // Vpn Interface removed => No more adjacencies from it.
1708 // Hence clean up interface from vpn-dpn-interface list.
1709 Adjacency adjacency = del.getAugmentation(Adjacencies.class).getAdjacency().get(0);
1710 List<Prefixes> prefixToInterface = new ArrayList<>();
1711 Optional<Prefixes> prefix = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
1712 VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
1713 VpnUtil.getIpPrefix(adjacency.getIpAddress())));
1714 if (prefix.isPresent()) {
1715 prefixToInterface.add(prefix.get());
1717 if (prefixToInterface.isEmpty()) {
1718 for (String nh : adjacency.getNextHopIpList()) {
1719 prefix = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
1720 VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
1721 VpnUtil.getIpPrefix(nh)));
1722 if (prefix.isPresent())
1723 prefixToInterface.add(prefix.get());
1726 for (Prefixes pref : prefixToInterface) {
1727 if (writeOperTxn != null) {
1728 writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL,
1729 VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(), pref.getIpAddress()));
1731 VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
1732 VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(), pref.getIpAddress()),
1733 VpnUtil.DEFAULT_CALLBACK);
1735 updateVpnToDpnMapping(pref.getDpnId(), del.getVpnInstanceName(), interfaceName, false /* delete */);
1739 LOG.error("rd not retrievable as vpninstancetovpnid for vpn {} is absent, trying rd as ", vpnName, vpnName);
1741 notifyTaskIfRequired(interfaceName);
1744 private void notifyTaskIfRequired(String intfName) {
1745 Runnable notifyTask = vpnIntfMap.remove(intfName);
1746 if (notifyTask == null) {
1747 LOG.trace("VpnInterfaceOpListener update: No Notify Task queued for vpnInterface {}", intfName);
1750 executorService.execute(notifyTask);
1754 protected void update(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface original,
1755 final VpnInterface update) {
1756 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
1757 final String interfaceName = key.getName();
1759 if (original.getVpnInstanceName().equals(update.getVpnInstanceName())) {
1763 final String vpnName = update.getVpnInstanceName();
1764 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1765 dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + interfaceName,
1766 new Callable<List<ListenableFuture<Void>>>() {
1768 public List<ListenableFuture<Void>> call() throws Exception {
1769 postProcessVpnInterfaceUpdate(identifier, original, update);
1775 private void postProcessVpnInterfaceUpdate(InstanceIdentifier<VpnInterface> identifier, VpnInterface original,
1776 VpnInterface update) {
1777 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
1778 String interfaceName = key.getName();
1780 //increment the vpn interface count in Vpn Instance Op Data
1781 VpnInstanceOpDataEntry vpnInstOp = null;
1782 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to
1783 .vpn.id.VpnInstance>
1784 origId = VpnUtil.getVpnInstanceToVpnIdIdentifier(original.getVpnInstanceName());
1785 Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
1786 .VpnInstance> origVpnInstance
1787 = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, origId);
1789 if (origVpnInstance.isPresent()) {
1791 rd = origVpnInstance.get().getVrfId();
1793 vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
1794 LOG.trace("VpnInterfaceOpListener updated: interface name {} original rd {} original vpnName {}",
1795 interfaceName, rd, original.getVpnInstanceName());
1797 if (vpnInstOp != null) {
1798 Adjacency adjacency = original.getAugmentation(Adjacencies.class).getAdjacency().get(0);
1799 List<Prefixes> prefixToInterfaceList = new ArrayList<>();
1800 Optional<Prefixes> prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
1801 VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
1802 VpnUtil.getIpPrefix(adjacency.getIpAddress())));
1803 if (prefixToInterface.isPresent()) {
1804 prefixToInterfaceList.add(prefixToInterface.get());
1806 for (String adj : adjacency.getNextHopIpList()) {
1807 prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
1808 VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
1809 VpnUtil.getIpPrefix(adj)));
1810 if (prefixToInterface.isPresent()) {
1811 prefixToInterfaceList.add(prefixToInterface.get());
1815 for (Prefixes prefix : prefixToInterfaceList) {
1816 updateVpnToDpnMapping(prefix.getDpnId(), original.getVpnInstanceName(), interfaceName, false /* delete */);
1820 notifyTaskIfRequired(interfaceName);
1824 protected void add(InstanceIdentifier<VpnInterface> identifier, VpnInterface add) {
1828 void publishAddNotification(final BigInteger dpnId, final String vpnName, final String rd) {
1829 LOG.debug("Sending notification for add dpn {} in vpn {} event ", dpnId, vpnName);
1830 AddEventData data = new AddEventDataBuilder().setVpnName(vpnName).setRd(rd).setDpnId(dpnId).build();
1831 AddDpnEvent event = new AddDpnEventBuilder().setAddEventData(data).build();
1832 final ListenableFuture<? extends Object> eventFuture = notificationPublishService.offerNotification(event);
1833 Futures.addCallback(eventFuture, new FutureCallback<Object>() {
1835 public void onFailure(Throwable error) {
1836 LOG.warn("Error in notifying listeners for add dpn {} in vpn {} event ", dpnId, vpnName, error);
1840 public void onSuccess(Object arg) {
1841 LOG.trace("Successful in notifying listeners for add dpn {} in vpn {} event ", dpnId, vpnName);
1846 void publishRemoveNotification(final BigInteger dpnId, final String vpnName, final String rd) {
1847 LOG.debug("Sending notification for remove dpn {} in vpn {} event ", dpnId, vpnName);
1848 RemoveEventData data = new RemoveEventDataBuilder().setVpnName(vpnName).setRd(rd).setDpnId(dpnId).build();
1849 RemoveDpnEvent event = new RemoveDpnEventBuilder().setRemoveEventData(data).build();
1850 final ListenableFuture<? extends Object> eventFuture = notificationPublishService.offerNotification(event);
1851 Futures.addCallback(eventFuture, new FutureCallback<Object>() {
1853 public void onFailure(Throwable error) {
1854 LOG.warn("Error in notifying listeners for remove dpn {} in vpn {} event ", dpnId, vpnName, error);
1858 public void onSuccess(Object arg) {
1859 LOG.trace("Successful in notifying listeners for remove dpn {} in vpn {} event ", dpnId, vpnName);
1864 InstanceIdentifier<DpnVpninterfacesList> getRouterDpnId(String routerName, BigInteger dpnId) {
1865 return InstanceIdentifier.builder(NeutronRouterDpns.class)
1866 .child(RouterDpnList.class, new RouterDpnListKey(routerName))
1867 .child(DpnVpninterfacesList.class, new DpnVpninterfacesListKey(dpnId)).build();
1870 InstanceIdentifier<RouterDpnList> getRouterId(String routerName) {
1871 return InstanceIdentifier.builder(NeutronRouterDpns.class)
1872 .child(RouterDpnList.class, new RouterDpnListKey(routerName)).build();
1875 protected void addToNeutronRouterDpnsMap(String routerName, String vpnInterfaceName, WriteTransaction writeOperTxn) {
1876 BigInteger dpId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
1877 if(dpId.equals(BigInteger.ZERO)) {
1878 LOG.warn("Could not retrieve dp id for interface {} to handle router {} association model", vpnInterfaceName, routerName);
1881 InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
1883 Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
1884 .OPERATIONAL, routerDpnListIdentifier);
1885 RouterInterfaces routerInterface = new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName)).setInterface(vpnInterfaceName).build();
1886 if (optionalRouterDpnList.isPresent()) {
1887 writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
1888 RouterInterfaces.class, new RouterInterfacesKey(vpnInterfaceName)), routerInterface, true);
1890 RouterDpnListBuilder builder = new RouterDpnListBuilder();
1891 builder.setRouterId(routerName);
1892 DpnVpninterfacesListBuilder dpnVpnList = new DpnVpninterfacesListBuilder().setDpnId(dpId);
1893 List<RouterInterfaces> routerInterfaces = new ArrayList<>();
1894 routerInterfaces.add(routerInterface);
1895 builder.setDpnVpninterfacesList(Arrays.asList(dpnVpnList.build()));
1896 writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL,
1897 getRouterId(routerName),
1898 builder.build(), true);
1902 protected void removeFromNeutronRouterDpnsMap(String routerName, String vpnInterfaceName, WriteTransaction writeOperTxn) {
1903 BigInteger dpId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
1904 if(dpId.equals(BigInteger.ZERO)) {
1905 LOG.warn("Could not retrieve dp id for interface {} to handle router {} dissociation model", vpnInterfaceName, routerName);
1908 InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
1909 Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
1910 .OPERATIONAL, routerDpnListIdentifier);
1911 if (optionalRouterDpnList.isPresent()) {
1912 List<RouterInterfaces> routerInterfaces = optionalRouterDpnList.get().getRouterInterfaces();
1913 RouterInterfaces routerInterface = new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName)).setInterface(vpnInterfaceName).build();
1915 if (routerInterfaces != null && routerInterfaces.remove(routerInterface)) {
1916 if (routerInterfaces.isEmpty()) {
1917 if (writeOperTxn != null) {
1918 writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
1920 MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
1923 if (writeOperTxn != null) {
1924 writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
1925 RouterInterfaces.class,
1926 new RouterInterfacesKey(vpnInterfaceName)));
1928 MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
1929 RouterInterfaces.class,
1930 new RouterInterfacesKey(vpnInterfaceName)));
1937 protected void removeFromNeutronRouterDpnsMap(String routerName, String vpnInterfaceName, BigInteger dpId,
1938 WriteTransaction writeOperTxn) {
1939 if(dpId.equals(BigInteger.ZERO)) {
1940 LOG.warn("Could not retrieve dp id for interface {} to handle router {} dissociation model", vpnInterfaceName, routerName);
1943 InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
1944 Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
1945 .OPERATIONAL, routerDpnListIdentifier);
1946 if (optionalRouterDpnList.isPresent()) {
1947 List<RouterInterfaces> routerInterfaces = optionalRouterDpnList.get().getRouterInterfaces();
1948 RouterInterfaces routerInterface = new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName)).setInterface(vpnInterfaceName).build();
1949 if (routerInterfaces != null && routerInterfaces.remove(routerInterface)) {
1950 if (routerInterfaces.isEmpty()) {
1951 writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
1953 writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
1954 RouterInterfaces.class,
1955 new RouterInterfacesKey(vpnInterfaceName)));
1961 public void addMIPAdjacency(String vpnName,String vpnInterface, org.opendaylight.yang.gen.v1.urn.ietf.params.xml
1962 .ns.yang.ietf.inet.types.rev130715.IpAddress prefix){
1964 LOG.trace("Adding {} adjacency to VPN Interface {} ",prefix,vpnInterface);
1965 InstanceIdentifier<VpnInterface> vpnIfId = VpnUtil.getVpnInterfaceIdentifier(vpnInterface);
1966 InstanceIdentifier<Adjacencies> path = vpnIfId.augmentation(Adjacencies.class);
1967 Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
1968 String nextHopIpAddr = null;
1969 String nextHopMacAddress = null;
1970 String ip = prefix.getIpv4Address().getValue();
1971 if (adjacencies.isPresent()) {
1972 List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
1973 ip = VpnUtil.getIpPrefix(ip);
1974 for (Adjacency adjacs : adjacencyList) {
1975 if (adjacs.getMacAddress() != null && !adjacs.getMacAddress().isEmpty()) {
1976 nextHopIpAddr = adjacs.getIpAddress();
1977 nextHopMacAddress = adjacs.getMacAddress();
1981 if (nextHopMacAddress != null && ip != null) {
1982 String rd = VpnUtil.getVpnRd(broker, vpnName);
1984 VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
1985 VpnUtil.getNextHopLabelKey((rd != null) ? rd : vpnName, ip));
1986 String nextHopIp = nextHopIpAddr.split("/")[0];
1987 Adjacency newAdj = new AdjacencyBuilder().setIpAddress(ip).setKey
1988 (new AdjacencyKey(ip)).setNextHopIpList(Arrays.asList(nextHopIp)).build();
1989 adjacencyList.add(newAdj);
1990 Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencyList);
1991 VpnInterface newVpnIntf = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(vpnInterface)).
1992 setName(vpnInterface).setVpnInstanceName(vpnName).addAugmentation(Adjacencies.class, aug).build();
1993 VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vpnIfId, newVpnIntf);
1994 LOG.debug(" Successfully stored subnetroute Adjacency into VpnInterface {}", vpnInterface);
2000 public void removeMIPAdjacency(String vpnName, String vpnInterface, org.opendaylight.yang.gen.v1.urn.ietf.params
2001 .xml.ns.yang.ietf.inet.types.rev130715.IpAddress prefix) {
2002 String ip = VpnUtil.getIpPrefix(prefix.getIpv4Address().getValue());
2003 LOG.trace("Removing {} adjacency from Old VPN Interface {} ",ip,vpnInterface);
2004 InstanceIdentifier<VpnInterface> vpnIfId = VpnUtil.getVpnInterfaceIdentifier(vpnInterface);
2005 InstanceIdentifier<Adjacencies> path = vpnIfId.augmentation(Adjacencies.class);
2006 Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
2007 if (adjacencies.isPresent()) {
2008 InstanceIdentifier<Adjacency> adjacencyIdentifier = InstanceIdentifier.builder(VpnInterfaces.class).
2009 child(VpnInterface.class, new VpnInterfaceKey(vpnInterface)).augmentation(Adjacencies.class)
2010 .child(Adjacency.class, new AdjacencyKey(ip)).build();
2011 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, adjacencyIdentifier);
2012 LOG.trace("Successfully Deleted Adjacency into VpnInterface {}", vpnInterface);