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.util.concurrent.ThreadFactoryBuilder;
11 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
12 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
13 import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
15 import com.google.common.util.concurrent.FutureCallback;
16 import com.google.common.util.concurrent.Futures;
17 import com.google.common.util.concurrent.JdkFutureAdapters;
19 import org.opendaylight.controller.md.sal.binding.api.*;
20 import org.opendaylight.genius.mdsalutil.*;
21 import org.opendaylight.genius.mdsalutil.AbstractDataChangeListener;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRoute;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRouteBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronvpnService;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PrefixToInterface;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnListBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnListKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesListBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesListKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfacesBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfacesKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListBuilder;
43 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;
44 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;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpResponseInput;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpResponseInputBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
58 import java.math.BigInteger;
59 import java.util.Collection;
60 import java.util.Iterator;
61 import java.util.List;
62 import java.util.ArrayList;
63 import java.util.concurrent.*;
65 import com.google.common.base.Optional;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronvpnService;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
71 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
72 import org.opendaylight.yangtools.concepts.ListenerRegistration;
73 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
74 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
75 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
76 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
77 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
80 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
82 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
83 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
84 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
85 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
86 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
87 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
88 import org.opendaylight.yangtools.yang.common.RpcError;
89 import org.opendaylight.yangtools.yang.common.RpcResult;
90 import org.slf4j.Logger;
91 import org.slf4j.LoggerFactory;
93 public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface> implements AutoCloseable {
94 private static final Logger LOG = LoggerFactory.getLogger(VpnInterfaceManager.class);
95 private ListenerRegistration<DataChangeListener> listenerRegistration, opListenerRegistration;
96 private static final ThreadFactory threadFactory = new ThreadFactoryBuilder()
97 .setNameFormat("NV-VpnIntfMgr-%d").build();
98 private final DataBroker broker;
99 private final IBgpManager bgpManager;
100 private IFibManager fibManager;
101 private IMdsalApiManager mdsalManager;
102 private OdlInterfaceRpcService interfaceManager;
103 private ItmRpcService itmProvider;
104 private IdManagerService idManager;
105 private OdlArputilService arpManager;
106 private NeutronvpnService neuService;
107 private VpnSubnetRouteHandler vpnSubnetRouteHandler;
108 private ConcurrentHashMap<String, Runnable> vpnIntfMap = new ConcurrentHashMap<String, Runnable>();
109 private ExecutorService executorService = Executors.newSingleThreadExecutor();
110 private InterfaceStateChangeListener interfaceListener;
111 private VpnInterfaceOpListener vpnInterfaceOpListener;
112 private ArpNotificationHandler arpNotificationHandler;
113 protected enum UpdateRouteAction {
114 ADVERTISE_ROUTE, WITHDRAW_ROUTE
117 * Responsible for listening to data change related to VPN Interface
118 * Bind VPN Service on the interface and informs the BGP service
120 * @param db - dataBroker service reference
122 public VpnInterfaceManager(final DataBroker db, final IBgpManager bgpManager, NotificationService notificationService) {
123 super(VpnInterface.class);
125 this.bgpManager = bgpManager;
126 interfaceListener = new InterfaceStateChangeListener(db, this);
127 vpnInterfaceOpListener = new VpnInterfaceOpListener();
128 arpNotificationHandler = new ArpNotificationHandler(this, broker);
129 notificationService.registerNotificationListener(arpNotificationHandler);
130 vpnSubnetRouteHandler = new VpnSubnetRouteHandler(broker, bgpManager, this);
131 notificationService.registerNotificationListener(vpnSubnetRouteHandler);
132 registerListener(db);
135 public void setMdsalManager(IMdsalApiManager mdsalManager) {
136 this.mdsalManager = mdsalManager;
139 public void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {
140 this.interfaceManager = interfaceManager;
141 interfaceListener.setInterfaceManager(interfaceManager);
144 public void setITMProvider(ItmRpcService itmProvider) {
145 this.itmProvider = itmProvider;
148 public void setFibManager(IFibManager fibManager) {
149 this.fibManager = fibManager;
152 public IFibManager getFibManager() {
153 return this.fibManager;
156 public void setIdManager(IdManagerService idManager) {
157 this.idManager = idManager;
158 vpnSubnetRouteHandler.setIdManager(idManager);
161 public void setArpManager(OdlArputilService arpManager) {
162 this.arpManager = arpManager;
165 public void setNeutronvpnManager(NeutronvpnService neuService) { this.neuService = neuService; }
167 public VpnSubnetRouteHandler getVpnSubnetRouteHandler() {
168 return this.vpnSubnetRouteHandler;
172 public void close() throws Exception {
173 if (listenerRegistration != null) {
175 listenerRegistration.close();
176 opListenerRegistration.close();
177 } catch (final Exception e) {
178 LOG.error("Error when cleaning up DataChangeListener.", e);
180 listenerRegistration = null;
181 opListenerRegistration = null;
183 LOG.info("VPN Interface Manager Closed");
186 private void registerListener(final DataBroker db) {
188 listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
189 getWildCardPath(), VpnInterfaceManager.this, DataChangeScope.SUBTREE);
190 opListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
191 getWildCardPath(), vpnInterfaceOpListener, DataChangeScope.SUBTREE);
192 } catch (final Exception e) {
193 LOG.error("VPN Service DataChange listener registration fail!", e);
194 throw new IllegalStateException("VPN Service registration Listener failed.", e);
198 private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> getInterfaceListenerPath() {
199 return InstanceIdentifier.create(InterfacesState.class)
200 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class);
204 protected void add(final InstanceIdentifier<VpnInterface> identifier,
205 final VpnInterface vpnInterface) {
206 LOG.trace("VPN Interface key: {} , value: {}", identifier, vpnInterface );
207 addInterface(identifier, vpnInterface);
210 private void addInterface(final InstanceIdentifier<VpnInterface> identifier,
211 final VpnInterface vpnInterface) {
212 LOG.trace("VPN Interface add event - key: {}, value: {}" ,identifier, vpnInterface );
213 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
214 String interfaceName = key.getName();
216 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState =
217 InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName);
218 if (interfaceState != null) {
219 // Interface state is up
220 processVpnInterfaceUp(InterfaceUtils.getDpIdFromInterface(interfaceState), interfaceName, interfaceState.getIfIndex());
222 LOG.trace("VPN interfaces are not yet operational.");
226 protected void processVpnInterfaceUp(BigInteger dpId, String interfaceName, int lPortTag) {
228 VpnInterface vpnInterface = VpnUtil.getConfiguredVpnInterface(broker, interfaceName);
229 if(vpnInterface == null) {
230 LOG.info("Unable to process add/up for interface {} as it is not configured", interfaceName);
233 String vpnName = vpnInterface.getVpnInstanceName();
234 LOG.info("Binding vpn service to interface {} ", interfaceName);
235 long vpnId = VpnUtil.getVpnId(broker, vpnName);
236 if (vpnId == VpnConstants.INVALID_ID) {
237 LOG.trace("VpnInstance to VPNId mapping is not yet available, bailing out now.");
240 boolean waitForVpnInterfaceOpRemoval = false;
242 VpnInterface opVpnInterface = null;
243 synchronized (interfaceName.intern()) {
244 opVpnInterface = VpnUtil.getOperationalVpnInterface(broker, vpnInterface.getName());
245 if (opVpnInterface != null ) {
246 String opVpnName = opVpnInterface.getVpnInstanceName();
247 String primaryInterfaceIp = null;
248 if(opVpnName.equals(vpnName)) {
249 // Please check if the primary VRF Entry does not exist for VPNInterface
250 // If so, we have to process ADD, as this might be a DPN Restart with Remove and Add triggered
252 // However, if the primary VRF Entry for this VPNInterface exists, please continue bailing out !
253 List<Adjacency> adjs = VpnUtil.getAdjacenciesForVpnInterfaceFromConfig(broker, interfaceName);
255 LOG.info("VPN Interface {} addition failed as adjacencies for this vpn interface could not be obtained",
259 numAdjs = adjs.size();
260 for (Adjacency adj : adjs) {
261 if (adj.getMacAddress() != null && !adj.getMacAddress().isEmpty()) {
262 primaryInterfaceIp = adj.getNextHopIp();
266 if (primaryInterfaceIp == null) {
267 LOG.info("VPN Interface {} addition failed as primary adjacency for this vpn interface could not be obtained",
271 // Get the rd of the vpn instance
272 String rd = getRouteDistinguisher(opVpnName);
273 VrfEntry vrf = VpnUtil.getVrfEntry(broker, rd, primaryInterfaceIp);
275 LOG.info("VPN Interface {} already provisioned , bailing out from here.", interfaceName);
278 waitForVpnInterfaceOpRemoval = true;
280 LOG.info("vpn interface {} to go to configured vpn {}, but in operational vpn {}", interfaceName, vpnName, opVpnName);
283 if (!waitForVpnInterfaceOpRemoval) {
284 // Add the VPNInterface and quit
285 bindService(dpId, vpnName, interfaceName, lPortTag);
286 updateDpnDbs(dpId, vpnName, interfaceName, true);
287 processVpnInterfaceAdjacencies(dpId, VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
292 // FIB didn't get a chance yet to clean up this VPNInterface
293 // Let us give it a chance here !
294 LOG.info("VPN Interface {} waiting for FIB to clean up! ", interfaceName);
296 Runnable notifyTask = new VpnNotifyTask();
297 vpnIntfMap.put(interfaceName, notifyTask);
298 synchronized (notifyTask) {
300 notifyTask.wait(VpnConstants.MAX_WAIT_TIME_IN_MILLISECONDS);
301 } catch (InterruptedException e) {
305 vpnIntfMap.remove(interfaceName);
308 opVpnInterface = VpnUtil.getOperationalVpnInterface(broker, interfaceName);
309 if (opVpnInterface != null) {
310 LOG.error("VPN Interface {} removal by FIB did not complete on time, bailing addition ...", interfaceName);
313 // VPNInterface got removed, proceed with Add
314 synchronized (interfaceName.intern()) {
315 bindService(dpId, vpnName, interfaceName, lPortTag);
316 updateDpnDbs(dpId, vpnName, interfaceName, true);
317 processVpnInterfaceAdjacencies(dpId, VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
321 private void updateDpnDbs(BigInteger dpId, String vpnName, String interfaceName, boolean add) {
322 long vpnId = VpnUtil.getVpnId(broker, vpnName);
324 dpId = InterfaceUtils.getDpnForInterface(interfaceManager, interfaceName);
326 if(!dpId.equals(BigInteger.ZERO)) {
328 updateMappingDbs(vpnId, dpId, interfaceName, vpnName);
330 removeFromMappingDbs(vpnId, dpId, interfaceName, vpnName);
335 private void bindService(BigInteger dpId, String vpnInstanceName, String vpnInterfaceName, int lPortTag) {
336 int priority = VpnConstants.DEFAULT_FLOW_PRIORITY;
337 long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName);
339 int instructionKey = 0;
340 List<Instruction> instructions = new ArrayList<>();
342 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID, ++instructionKey));
343 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.L3_FIB_TABLE, ++instructionKey));
347 InterfaceUtils.getBoundServices(String.format("%s.%s.%s", "vpn",vpnInstanceName, vpnInterfaceName),
348 VpnConstants.L3VPN_SERVICE_IDENTIFIER, priority,
349 VpnConstants.COOKIE_VM_INGRESS_TABLE, instructions);
350 VpnUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
351 InterfaceUtils.buildServiceId(vpnInterfaceName, VpnConstants.L3VPN_SERVICE_IDENTIFIER), serviceInfo);
352 makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
353 vpnId, ArpReplyOrRequest.REQUEST, NwConstants.ADD_FLOW);
354 makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
355 vpnId, ArpReplyOrRequest.REPLY, NwConstants.ADD_FLOW);
359 private void processVpnInterfaceAdjacencies(BigInteger dpnId, final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
360 String intfName = intf.getName();
362 synchronized (intfName) {
364 InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
365 Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
367 if (adjacencies.isPresent()) {
368 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
369 List<Adjacency> value = new ArrayList<>();
371 // Get the rd of the vpn instance
372 String rd = getRouteDistinguisher(intf.getVpnInstanceName());
374 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
375 if (nextHopIp == null){
376 LOG.error("NextHop for interface {} is null", intfName);
379 LOG.trace("NextHops are {}", nextHops);
380 for (Adjacency nextHop : nextHops) {
381 String prefix = VpnUtil.getIpPrefix(nextHop.getIpAddress());
382 long label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, VpnUtil
383 .getNextHopLabelKey((rd == null) ? intf.getVpnInstanceName() : rd, prefix));
384 String adjNextHop = nextHop.getNextHopIp();
385 value.add(new AdjacencyBuilder(nextHop).setLabel(label).setNextHopIp((adjNextHop != null && !adjNextHop.isEmpty()) ? adjNextHop : nextHopIp)
386 .setIpAddress(prefix).setKey(new AdjacencyKey(prefix)).build());
387 if(nextHop.getMacAddress() != null && !nextHop.getMacAddress().isEmpty()) {
390 LogicalDatastoreType.OPERATIONAL,
391 VpnUtil.getPrefixToInterfaceIdentifier(
392 VpnUtil.getVpnId(broker, intf.getVpnInstanceName()), prefix),
393 VpnUtil.getPrefixToInterface(dpnId, intf.getName(), prefix));
395 //Extra route adjacency
398 LogicalDatastoreType.OPERATIONAL,
399 VpnUtil.getVpnToExtrarouteIdentifier(
400 (rd != null) ? rd : intf.getVpnInstanceName(), nextHop.getIpAddress()),
401 VpnUtil.getVpnToExtraroute(nextHop.getIpAddress(), nextHop.getNextHopIp()));
406 Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(value);
407 VpnInterface opInterface = VpnUtil.getVpnInterface(intfName, intf.getVpnInstanceName(), aug);
408 InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(intfName);
409 VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, interfaceId, opInterface);
410 for (Adjacency nextHop : aug.getAdjacency()) {
411 long label = nextHop.getLabel();
412 //String adjNextHop = nextHop.getNextHopIp();
414 addPrefixToBGP(rd, nextHop.getIpAddress(),
417 // ### add FIB route directly
418 addFibEntryToDS(intf.getVpnInstanceName(), nextHop.getIpAddress(),
419 nextHopIp, (int) label);
426 private void makeArpFlow(BigInteger dpId,short sIndex, int lPortTag, String vpnInterfaceName,
427 long vpnId, ArpReplyOrRequest replyOrRequest, int addOrRemoveFlow){
428 List<MatchInfo> matches = new ArrayList<>();
429 BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lPortTag, ++sIndex, BigInteger.valueOf(vpnId));
430 BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
431 MetaDataUtil.METADATA_MASK_LPORT_TAG, MetaDataUtil.METADATA_MASK_VRFID);
433 // Matching Arp reply flows
434 matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_ARP }));
435 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
436 metadata, metadataMask }));
438 matches.add(new MatchInfo(MatchFieldType.arp_op, new long[] { replyOrRequest.getArpOperation() }));
440 // Instruction to punt to controller
441 List<InstructionInfo> instructions = new ArrayList<>();
442 List<ActionInfo> actionsInfos = new ArrayList<>();
443 actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[] {}));
444 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
446 // Install the flow entry in L3_INTERFACE_TABLE
447 String flowRef = VpnUtil.getFlowRef(dpId, NwConstants.L3_INTERFACE_TABLE,
448 NwConstants.ETHTYPE_ARP, lPortTag, replyOrRequest.getArpOperation());
449 FlowEntity flowEntity;
450 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_INTERFACE_TABLE, flowRef,
451 NwConstants.DEFAULT_ARP_FLOW_PRIORITY, replyOrRequest.getName(), 0, 0,
452 VpnUtil.getCookieArpFlow(lPortTag), matches, instructions);
454 if (addOrRemoveFlow == NwConstants.ADD_FLOW) {
455 LOG.debug("Creating ARP Flow for interface {}",vpnInterfaceName);
456 mdsalManager.installFlow(flowEntity);
458 LOG.debug("Deleting ARP Flow for interface {}",vpnInterfaceName);
459 mdsalManager.removeFlow(flowEntity);
463 private String getRouteDistinguisher(String vpnName) {
464 InstanceIdentifier<VpnInstance> id = InstanceIdentifier.builder(VpnInstances.class)
465 .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
466 Optional<VpnInstance> vpnInstance = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
468 if(vpnInstance.isPresent()) {
469 VpnInstance instance = vpnInstance.get();
470 VpnAfConfig config = instance.getIpv4Family();
471 rd = config.getRouteDistinguisher();
476 private synchronized void updateMappingDbs(long vpnId, BigInteger dpnId, String intfName, String vpnName) {
477 String routeDistinguisher = getRouteDistinguisher(vpnName);
478 String rd = (routeDistinguisher == null) ? vpnName : routeDistinguisher;
479 InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
480 Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
481 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
482 vpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
484 if (dpnInVpn.isPresent()) {
485 VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id.child(
486 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance
487 .op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
488 new VpnInterfacesKey(intfName)), vpnInterface);
490 VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
491 VpnUtil.getVpnInstanceOpDataIdentifier(rd),
492 VpnUtil.getVpnInstanceOpDataBuilder(rd, vpnId));
493 VpnToDpnListBuilder vpnToDpnList = new VpnToDpnListBuilder().setDpnId(dpnId);
494 List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
495 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = new ArrayList<>();
496 vpnInterfaces.add(vpnInterface);
497 VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id,
498 vpnToDpnList.setVpnInterfaces(vpnInterfaces).build());
501 * FIXME: DC Gateway tunnel should be built dynamically
502 //this is the first VM in this VPN on the DPN, may be a new DPN has come up,
503 //if tunnel to DC GW does not exist, create it
504 //if(!tunnelExists(dpnID, bgpManager.getDCGWIP()))
505 String dcGW = bgpManager.getDCGwIP();
506 if(dcGW != null && !dcGW.isEmpty())
508 LOG.debug("Building tunnel from DPN {} to DC GW {}", dpnId, dcGW);
509 itmProvider.buildTunnelFromDPNToDCGW(dpnId, new IpAddress(dcGW.toCharArray()));
511 fibManager.populateFibOnNewDpn(dpnId, vpnId, (rd == null) ? vpnName : rd);
515 private synchronized void removeFromMappingDbs(long vpnId, BigInteger dpnId, String intfName, String vpnName) {
516 //TODO: Delay 'DPN' removal so that other services can cleanup the entries for this dpn
517 String rd = VpnUtil.getVpnRd(broker, vpnName);
518 InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
519 Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
520 if (dpnInVpn.isPresent()) {
521 List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
522 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
523 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
524 currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
526 if (vpnInterfaces.remove(currVpnInterface)) {
527 if (vpnInterfaces.isEmpty()) {
528 VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id, VpnUtil.DEFAULT_CALLBACK);
529 fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd);
531 VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
532 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
533 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
534 new VpnInterfacesKey(intfName)), VpnUtil.DEFAULT_CALLBACK);
540 private void addPrefixToBGP(String rd, String prefix, String nextHopIp, long label) {
542 //FIXME: TBD once odl-fib yang has nexthoplist and related changes follow
543 //bgpManager.addPrefix(rd, prefix, nextHopIp, (int)label);
544 } catch(Exception e) {
545 LOG.error("Add prefix failed", e);
550 private InstanceIdentifier<VpnInterface> getWildCardPath() {
551 return InstanceIdentifier.create(VpnInterfaces.class).child(VpnInterface.class);
555 protected void remove( InstanceIdentifier<VpnInterface> identifier, VpnInterface vpnInterface) {
556 LOG.trace("Remove event - key: {}, value: {}" ,identifier, vpnInterface );
557 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
558 String interfaceName = key.getName();
560 InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
561 Optional<VpnInterface> existingVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, interfaceId);
562 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState =
563 InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName);
565 if (existingVpnInterface.isPresent() && interfaceState != null) {
566 processVpnInterfaceDown(InterfaceUtils.getDpIdFromInterface(interfaceState), interfaceName, interfaceState.getIfIndex(), false);
568 LOG.warn("VPN interface {} was unavailable in operational data store to handle remove event", interfaceName);
572 protected void processVpnInterfaceDown(BigInteger dpId, String interfaceName, int lPortTag, boolean isInterfaceStateDown) {
573 VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(broker, interfaceName);
574 if(vpnInterface == null) {
575 LOG.info("Unable to process delete/down for interface {} as it is not available in operational data store", interfaceName);
578 String vpnName = vpnInterface.getVpnInstanceName();
579 InstanceIdentifier<VpnInterface> identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
581 synchronized (interfaceName.intern()) {
582 removeAdjacenciesFromVpn(identifier, vpnInterface);
583 LOG.info("Unbinding vpn service from interface {} ", interfaceName);
584 unbindService(dpId, vpnName, interfaceName, lPortTag, isInterfaceStateDown);
587 // FIB didn't get a chance yet to clean up this VPNInterface
588 // Let us give it a chance here !
589 LOG.info("VPN Interface {} removal waiting for FIB to clean up ! ", interfaceName);
591 Runnable notifyTask = new VpnNotifyTask();
592 vpnIntfMap.put(interfaceName, notifyTask);
593 synchronized (notifyTask) {
595 notifyTask.wait(VpnConstants.PER_INTERFACE_MAX_WAIT_TIME_IN_MILLISECONDS);
596 } catch (InterruptedException e) {
600 vpnIntfMap.remove(interfaceName);
605 private void removeAdjacenciesFromVpn(final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
607 InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
608 Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
610 String rd = VpnUtil.getVpnRd(broker, intf.getVpnInstanceName());
611 LOG.trace("removeAdjacenciesFromVpn: For interface {} RD recovered for vpn {} as rd {}", intf.getName(),
612 intf.getVpnInstanceName(), rd);
613 if (adjacencies.isPresent()) {
614 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
616 if (!nextHops.isEmpty()) {
617 LOG.trace("NextHops are " + nextHops);
618 for (Adjacency nextHop : nextHops) {
619 // Commenting the release of ID here as it will be released by FIB
620 /* VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME,
621 VpnUtil.getNextHopLabelKey(rd, nextHop.getIpAddress()));
622 VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
623 VpnUtil.getPrefixToInterfaceIdentifier(
624 VpnUtil.getVpnId(broker, intf.getVpnInstanceName()),
625 nextHop.getIpAddress()),
626 VpnUtil.DEFAULT_CALLBACK);*/
627 if (rd.equals(intf.getVpnInstanceName())) {
628 //this is an internal vpn - the rd is assigned to the vpn instance name;
629 //remove from FIB directly
630 removeFibEntryFromDS(intf.getVpnInstanceName(), nextHop.getIpAddress());
632 removePrefixFromBGP(rd, nextHop.getIpAddress());
640 private void unbindService(BigInteger dpId, String vpnInstanceName, String vpnInterfaceName,
641 int lPortTag, boolean isInterfaceStateDown) {
642 if (!isInterfaceStateDown) {
643 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION,
644 InterfaceUtils.buildServiceId(vpnInterfaceName,
645 VpnConstants.L3VPN_SERVICE_IDENTIFIER));
647 long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName);
648 makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
649 vpnId, ArpReplyOrRequest.REQUEST, NwConstants.DEL_FLOW);
650 makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
651 vpnId, ArpReplyOrRequest.REPLY, NwConstants.DEL_FLOW);
655 private void removePrefixFromBGP(String rd, String prefix) {
656 removeFibEntryFromDS(rd, prefix);
658 bgpManager.withdrawPrefix(rd, prefix);
659 } catch(Exception e) {
660 LOG.error("Delete prefix failed", e);
665 protected void update(InstanceIdentifier<VpnInterface> identifier, VpnInterface original, VpnInterface update) {
666 if (LOG.isTraceEnabled()) {
667 LOG.trace("Updating VPN Interface : key " + identifier + ", original value=" + original + ", update " +
670 String oldVpnName = original.getVpnInstanceName();
671 String newVpnName = update.getVpnInstanceName();
672 List<Adjacency> oldAdjs = original.getAugmentation(Adjacencies.class).getAdjacency();
673 List<Adjacency> newAdjs = update.getAugmentation(Adjacencies.class).getAdjacency();
674 if (oldAdjs == null) {
675 oldAdjs = new ArrayList<>();
677 if (newAdjs == null) {
678 newAdjs = new ArrayList<>();
680 //handles switching between <internal VPN - external VPN>
681 if (!oldVpnName.equals(newVpnName)) {
682 remove(identifier, original);
683 add(identifier, update);
685 //handle both addition and removal of adjacencies
686 //currently, new adjacency may be an extra route
687 if (!oldAdjs.equals(newAdjs)) {
688 for (Adjacency adj : newAdjs) {
689 if (oldAdjs.contains(adj)) {
692 // add new adjacency - right now only extra route will hit this path
693 addNewAdjToVpnInterface(identifier, adj);
696 for (Adjacency adj : oldAdjs) {
697 delAdjFromVpnInterface(identifier, adj);
702 public void processArpRequest(IpAddress srcIP, PhysAddress srcMac, IpAddress targetIP, PhysAddress targetMac,String srcInterface){
703 //Build ARP response with ARP requests TargetIp TargetMac as the Arp Response SrcIp and SrcMac
704 SendArpResponseInput input = new SendArpResponseInputBuilder().setInterface(srcInterface)
705 .setDstIpaddress(srcIP).setDstMacaddress(srcMac).setSrcIpaddress(targetIP).setSrcMacaddress(targetMac).build();
706 final String msgFormat = String.format("Send ARP Response on interface %s to destination %s", srcInterface, srcIP);
707 Future<RpcResult<Void>> future = arpManager.sendArpResponse(input);
708 Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future), new FutureCallback<RpcResult<Void>>() {
710 public void onFailure(Throwable error) {
711 LOG.error("Error - {}", msgFormat, error);
715 public void onSuccess(RpcResult<Void> result) {
716 if(!result.isSuccessful()) {
717 LOG.warn("Rpc call to {} failed", msgFormat, getErrorText(result.getErrors()));
719 LOG.debug("Successful RPC Result - {}", msgFormat);
725 private String getErrorText(Collection<RpcError> errors) {
726 StringBuilder errorText = new StringBuilder();
727 for(RpcError error : errors) {
728 errorText.append(",").append(error.getErrorType()).append("-")
729 .append(error.getMessage());
731 return errorText.toString();
734 private String getTunnelInterfaceFlowRef(BigInteger dpnId, short tableId, String ifName) {
735 return new StringBuilder().append(dpnId).append(tableId).append(ifName).toString();
740 public synchronized void addFibEntryToDS(String rd, String prefix,
741 String nexthop, int label) {
743 VrfEntry vrfEntry = new VrfEntryBuilder().setDestPrefix(prefix).
744 setNextHopAddress(nexthop).setLabel((long)label).build();
745 LOG.debug("Created vrfEntry for {} nexthop {} label {}", prefix, nexthop, label);
747 List<VrfEntry> vrfEntryList = new ArrayList<>();
748 vrfEntryList.add(vrfEntry);
750 InstanceIdentifierBuilder<VrfTables> idBuilder =
751 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
752 InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
754 VrfTables vrfTableNew = new VrfTablesBuilder().setRouteDistinguisher(rd).
755 setVrfEntry(vrfEntryList).build();
757 VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
760 public synchronized void addSubnetRouteFibEntryToDS(String rd, String prefix,
761 String nexthop, int label,long elantag) {
763 SubnetRoute route = new SubnetRouteBuilder().setElantag(elantag).build();
765 VrfEntry vrfEntry = new VrfEntryBuilder().setDestPrefix(prefix).
766 setNextHopAddress(nexthop).setLabel((long)label).addAugmentation(SubnetRoute.class,route).build();
767 LOG.debug("Created vrfEntry for {} nexthop {} label {} and elantag {}", prefix, nexthop, label, elantag);
769 List<VrfEntry> vrfEntryList = new ArrayList<VrfEntry>();
770 vrfEntryList.add(vrfEntry);
772 InstanceIdentifierBuilder<VrfTables> idBuilder =
773 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
774 InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
776 VrfTables vrfTableNew = new VrfTablesBuilder().setRouteDistinguisher(rd).
777 setVrfEntry(vrfEntryList).build();
779 VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
782 public synchronized void removeFibEntryFromDS(String rd, String prefix) {
784 LOG.debug("Removing fib entry with destination prefix {} from vrf table for rd {}", prefix, rd);
786 InstanceIdentifierBuilder<VrfEntry> idBuilder =
787 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).child(VrfEntry.class, new VrfEntryKey(prefix));
788 InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
789 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
793 public synchronized void removeVrfFromDS(String rd) {
794 LOG.debug("Removing vrf table for rd {}", rd);
796 InstanceIdentifierBuilder<VrfTables> idBuilder =
797 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
798 InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
800 VpnUtil.delete(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, VpnUtil.DEFAULT_CALLBACK);
804 protected void addNewAdjToVpnInterface(InstanceIdentifier<VpnInterface> identifier, Adjacency adj) {
806 Optional<VpnInterface> optVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
808 if (optVpnInterface.isPresent()) {
809 VpnInterface currVpnIntf = optVpnInterface.get();
810 String prefix = VpnUtil.getIpPrefix(adj.getIpAddress());
811 String rd = getRouteDistinguisher(currVpnIntf.getVpnInstanceName());
812 InstanceIdentifier<Adjacencies> adjPath = identifier.augmentation(Adjacencies.class);
813 Optional<Adjacencies> optAdjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, adjPath);
815 VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
816 VpnUtil.getNextHopLabelKey((rd != null) ? rd : currVpnIntf.getVpnInstanceName(), prefix));
818 List<Adjacency> adjacencies;
819 if (optAdjacencies.isPresent()) {
820 adjacencies = optAdjacencies.get().getAdjacency();
822 //This code will not be hit since VM adjacency will always be there
823 adjacencies = new ArrayList<>();
826 adjacencies.add(new AdjacencyBuilder(adj).setLabel(label).setNextHopIp(adj.getNextHopIp())
827 .setIpAddress(prefix).setKey(new AdjacencyKey(prefix)).build());
829 Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencies);
830 VpnInterface newVpnIntf = VpnUtil.getVpnInterface(currVpnIntf.getName(), currVpnIntf.getVpnInstanceName(), aug);
832 VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, newVpnIntf);
833 addExtraRoute(adj.getIpAddress(), adj.getNextHopIp(), rd, currVpnIntf.getVpnInstanceName(), (int) label, currVpnIntf.getName());
839 protected void delAdjFromVpnInterface(InstanceIdentifier<VpnInterface> identifier, Adjacency adj) {
840 Optional<VpnInterface> optVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
842 if (optVpnInterface.isPresent()) {
843 VpnInterface currVpnIntf = optVpnInterface.get();
845 InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
846 Optional<Adjacencies> optAdjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
847 if (optAdjacencies.isPresent()) {
848 List<Adjacency> adjacencies = optAdjacencies.get().getAdjacency();
850 if (!adjacencies.isEmpty()) {
851 String rd = getRouteDistinguisher(currVpnIntf.getVpnInstanceName());
852 LOG.trace("Adjacencies are " + adjacencies);
853 Iterator<Adjacency> adjIt = adjacencies.iterator();
854 while (adjIt.hasNext()) {
855 Adjacency adjElem = adjIt.next();
856 if (adjElem.getIpAddress().equals(adj.getIpAddress())) {
857 // Commenting the release of ID here as it will be released by FIB
858 /* VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME,
859 VpnUtil.getNextHopLabelKey(rd, adj.getIpAddress()));*/
862 Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencies);
863 VpnInterface newVpnIntf = VpnUtil.getVpnInterface(currVpnIntf.getName(),
864 currVpnIntf.getVpnInstanceName(),
867 VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, newVpnIntf);
869 delExtraRoute(adj.getIpAddress(), rd, currVpnIntf.getVpnInstanceName());
880 protected void addExtraRoute(String destination, String nextHop, String rd, String routerID, int label, String intfName) {
882 //add extra route to vpn mapping; advertise with nexthop as tunnel ip
885 LogicalDatastoreType.OPERATIONAL,
886 VpnUtil.getVpnToExtrarouteIdentifier(
887 (rd != null) ? rd : routerID, destination),
888 VpnUtil.getVpnToExtraroute(destination, nextHop));
890 if (intfName != null && !intfName.isEmpty()) {
891 BigInteger dpnId = InterfaceUtils.getDpnForInterface(interfaceManager, intfName);
892 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
893 if (nextHopIp == null || nextHopIp.isEmpty()) {
894 LOG.warn("NextHop for interface {} is null / empty. Failed advertising extra route for prefix {}", intfName, destination);
899 addPrefixToBGP(rd, destination, nextHop, label);
901 // ### add FIB route directly
902 addFibEntryToDS(routerID, destination, nextHop, label);
906 protected void delExtraRoute(String destination, String rd, String routerID) {
908 removePrefixFromBGP(rd, destination);
910 // ### add FIB route directly
911 removeFibEntryFromDS(routerID, destination);
915 class VpnInterfaceOpListener extends AbstractDataChangeListener<VpnInterface> {
917 public VpnInterfaceOpListener() {
918 super(VpnInterface.class);
922 protected void remove(InstanceIdentifier<VpnInterface> identifier, VpnInterface del) {
923 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
924 String interfaceName = key.getName();
925 String vpnName = del.getVpnInstanceName();
927 LOG.trace("VpnInterfaceOpListener removed: interface name {} vpnName {}", interfaceName, vpnName);
928 //decrement the vpn interface count in Vpn Instance Op Data
929 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
930 id = VpnUtil.getVpnInstanceToVpnIdIdentifier(vpnName);
931 Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> vpnInstance
932 = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
934 if (vpnInstance.isPresent()) {
936 rd = vpnInstance.get().getVrfId();
937 //String rd = getRouteDistinguisher(del.getVpnInstanceName());
939 VpnInstanceOpDataEntry vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
940 LOG.trace("VpnInterfaceOpListener removed: interface name {} rd {} vpnName {} in Vpn Op Instance {}",
941 interfaceName, rd, vpnName, vpnInstOp);
943 if (vpnInstOp != null) {
944 // Vpn Interface removed => No more adjacencies from it.
945 // Hence clean up interface from vpn-dpn-interface list.
946 Adjacency adjacency = del.getAugmentation(Adjacencies.class).getAdjacency().get(0);
947 Optional<Prefixes> prefixToInterface = Optional.absent();
948 prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
949 VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
950 VpnUtil.getIpPrefix(adjacency.getIpAddress())));
951 if (!prefixToInterface.isPresent()) {
952 prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
953 VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
954 VpnUtil.getIpPrefix(adjacency.getNextHopIp())));
956 if (prefixToInterface.isPresent()) {
957 VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
958 VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
959 prefixToInterface.get().getIpAddress()),
960 VpnUtil.DEFAULT_CALLBACK);
961 synchronized (interfaceName.intern()) {
962 updateDpnDbs(prefixToInterface.get().getDpnId(), del.getVpnInstanceName(), interfaceName, false);
966 // //ifCnt = vpnInstOp.getVpnInterfaceCount();
967 // LOG.trace("VpnInterfaceOpListener removed: interface name {} rd {} vpnName {} Intf count {}",
968 // interfaceName, rd, vpnName, ifCnt);
969 // if ((ifCnt != null) && (ifCnt > 0)) {
970 // VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
971 // VpnUtil.getVpnInstanceOpDataIdentifier(rd),
972 // VpnUtil.updateIntfCntInVpnInstOpData(ifCnt - 1, rd), VpnUtil.DEFAULT_CALLBACK);
976 LOG.error("rd not retrievable as vpninstancetovpnid for vpn {} is absent, trying rd as ", vpnName, vpnName);
978 notifyTaskIfRequired(interfaceName);
981 private void notifyTaskIfRequired(String intfName) {
982 Runnable notifyTask = vpnIntfMap.remove(intfName);
983 if (notifyTask == null) {
984 LOG.trace("VpnInterfaceOpListener update: No Notify Task queued for vpnInterface {}", intfName);
987 executorService.execute(notifyTask);
991 protected void update(InstanceIdentifier<VpnInterface> identifier, VpnInterface original, VpnInterface update) {
992 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
993 String interfaceName = key.getName();
995 if (original.getVpnInstanceName().equals(update.getVpnInstanceName())) {
999 //increment the vpn interface count in Vpn Instance Op Data
1001 VpnInstanceOpDataEntry vpnInstOp = null;
1002 // InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to
1003 // .vpn.id.VpnInstance>
1004 // updId = VpnUtil.getVpnInstanceToVpnIdIdentifier(update.getVpnInstanceName());
1005 // Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
1006 // .VpnInstance> updVpnInstance
1007 // = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, updId);
1009 // if (updVpnInstance.isPresent()) {
1010 // String rd = null;
1011 // rd = updVpnInstance.get().getVrfId();
1013 // vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
1015 // if (vpnInstOp != null && vpnInstOp.getVpnInterfaceCount() != null) {
1016 // ifCnt = vpnInstOp.getVpnInterfaceCount();
1019 // LOG.trace("VpnInterfaceOpListener update: interface name {} rd {} interface count in updated Vpn Op
1020 // Instance {}", interfaceName, rd, ifCnt);
1022 // VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
1023 // VpnUtil.getVpnInstanceOpDataIdentifier(rd),
1024 // VpnUtil.updateIntfCntInVpnInstOpData(ifCnt + 1, rd), VpnUtil.DEFAULT_CALLBACK);
1027 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to
1028 .vpn.id.VpnInstance>
1029 origId = VpnUtil.getVpnInstanceToVpnIdIdentifier(original.getVpnInstanceName());
1030 Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
1031 .VpnInstance> origVpnInstance
1032 = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, origId);
1034 if (origVpnInstance.isPresent()) {
1036 rd = origVpnInstance.get().getVrfId();
1038 vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
1039 LOG.trace("VpnInterfaceOpListener updated: interface name {} original rd {} original vpnName {}",
1040 interfaceName, rd, original.getVpnInstanceName());
1042 if (vpnInstOp != null) {
1043 Adjacency adjacency = original.getAugmentation(Adjacencies.class).getAdjacency().get(0);
1044 Optional<Prefixes> prefixToInterface = Optional.absent();
1045 prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
1046 VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
1047 VpnUtil.getIpPrefix(adjacency.getIpAddress())));
1048 if (!prefixToInterface.isPresent()) {
1049 prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
1050 VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
1051 VpnUtil.getIpPrefix(adjacency.getNextHopIp())));
1053 if (prefixToInterface.isPresent()) {
1054 // VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
1055 // VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
1056 // prefixToInterface.get().getIpAddress()),
1057 // VpnUtil.DEFAULT_CALLBACK);
1058 synchronized (interfaceName.intern()) {
1059 updateDpnDbs(prefixToInterface.get().getDpnId(), original.getVpnInstanceName(), interfaceName, false);
1064 notifyTaskIfRequired(interfaceName);
1065 // if (vpnInstOp != null && vpnInstOp.getVpnInterfaceCount() != null) {
1066 // ifCnt = vpnInstOp.getVpnInterfaceCount();
1068 // LOG.debug("VpnInterfaceOpListener update: Vpn interface count not recoverable from original, to handle update for rd {}", rd);
1071 // LOG.trace("VpnInterfaceOpListener update: interface name {} rd {} interface count in original Vpn Op Instance {}", interfaceName, rd, ifCnt);
1074 // VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
1075 // VpnUtil.getVpnInstanceOpDataIdentifier(rd),
1076 // VpnUtil.updateIntfCntInVpnInstOpData(ifCnt - 1, rd), VpnUtil.DEFAULT_CALLBACK);
1082 protected void add(InstanceIdentifier<VpnInterface> identifier, VpnInterface add) {
1083 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
1084 String interfaceName = key.getName();
1086 //increment the vpn interface count in Vpn Instance Op Data
1088 // String rd = getRouteDistinguisher(add.getVpnInstanceName());
1089 // if(rd == null || rd.isEmpty()) rd = add.getVpnInstanceName();
1090 // VpnInstanceOpDataEntry vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
1091 // if(vpnInstOp != null && vpnInstOp.getVpnInterfaceCount() != null) {
1092 // ifCnt = vpnInstOp.getVpnInterfaceCount();
1095 // LOG.trace("VpnInterfaceOpListener add: interface name {} rd {} interface count in Vpn Op Instance {}",
1096 // interfaceName, rd, ifCnt);
1098 // VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
1099 // VpnUtil.getVpnInstanceOpDataIdentifier(rd),
1100 // VpnUtil.updateIntfCntInVpnInstOpData(ifCnt + 1, rd), VpnUtil.DEFAULT_CALLBACK);
1105 protected void updatePrefixesForDPN(BigInteger dpnId, UpdateRouteAction action) {
1107 LOG.info("Tunnel event triggered {} for Dpn:{} ", action.name(), dpnId);
1108 InstanceIdentifierBuilder<VpnInstances> idBuilder = InstanceIdentifier.builder(VpnInstances.class);
1109 InstanceIdentifier<VpnInstances> vpnInstancesId = idBuilder.build();
1110 Optional<VpnInstances> vpnInstances = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vpnInstancesId);
1112 if (vpnInstances.isPresent()) {
1113 List<VpnInstance> vpnInstanceList = vpnInstances.get().getVpnInstance();
1114 Iterator<VpnInstance> vpnInstIter = vpnInstanceList.iterator();
1115 while (vpnInstIter.hasNext()) {
1116 VpnInstance vpnInstance = vpnInstIter.next();
1118 VpnAfConfig vpnConfig = vpnInstance.getIpv4Family();
1119 String rd = vpnConfig.getRouteDistinguisher();
1120 if (rd == null || rd.isEmpty()) {
1121 rd = vpnInstance.getVpnInstanceName();
1123 InstanceIdentifier<VpnToDpnList> id =
1124 VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
1125 Optional<VpnToDpnList> dpnInVpn =
1126 VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
1127 if (dpnInVpn.isPresent()) {
1128 // if (action == UpdateRouteAction.ADVERTISE_ROUTE) {
1129 // fibManager.populateFibOnNewDpn(dpnId, VpnUtil
1130 // .getVpnId(broker, vpnInstance.getVpnInstanceName()), rd);
1132 List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
1133 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces>
1134 vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
1135 for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
1136 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces vpnInterface : vpnInterfaces) {
1137 InstanceIdentifier<VpnInterface> vpnIntfId =
1138 VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getInterfaceName());
1139 InstanceIdentifier<Adjacencies> path =
1140 vpnIntfId.augmentation(Adjacencies.class);
1141 Optional<Adjacencies> adjacencies =
1142 VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
1144 if (adjacencies.isPresent()) {
1145 List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
1146 Iterator<Adjacency> adjacencyIterator = adjacencyList.iterator();
1148 while (adjacencyIterator.hasNext()) {
1149 Adjacency adjacency = adjacencyIterator.next();
1151 if (action == UpdateRouteAction.ADVERTISE_ROUTE) {
1152 //FIXME: TBD once odl-fib yang has nexthoplist and related changes follow
1153 //bgpManager.addPrefix(rd, adjacency.getIpAddress(), adjacency.getNextHopIp(), adjacency.getLabel().intValue());
1156 else if (action == UpdateRouteAction.WITHDRAW_ROUTE)
1157 bgpManager.deletePrefix(rd, adjacency.getIpAddress());
1158 } catch (Exception e) {
1159 LOG.error("Exception when updating prefix {} in vrf {} to BGP",
1160 adjacency.getIpAddress(), rd);
1166 // if (action == UpdateRouteAction.WITHDRAW_ROUTE) {
1167 // fibManager.cleanUpDpnForVpn(dpnId, VpnUtil.getVpnId(broker, vpnInstance.getVpnInstanceName()), rd);
1170 } catch (Exception e) {
1171 LOG.error("updatePrefixesForDPN {} in vpn {} failed", dpnId, vpnInstance.getVpnInstanceName(), e);
1177 InstanceIdentifier<DpnVpninterfacesList> getRouterDpnId(String routerName, BigInteger dpnId) {
1178 return InstanceIdentifier.builder(NeutronRouterDpns.class)
1179 .child(RouterDpnList.class, new RouterDpnListKey(routerName))
1180 .child(DpnVpninterfacesList.class, new DpnVpninterfacesListKey(dpnId)).build();
1183 InstanceIdentifier<RouterDpnList> getRouterId(String routerName) {
1184 return InstanceIdentifier.builder(NeutronRouterDpns.class)
1185 .child(RouterDpnList.class, new RouterDpnListKey(routerName)).build();
1188 protected void addToNeutronRouterDpnsMap(String routerName, String vpnInterfaceName) {
1189 BigInteger dpId = InterfaceUtils.getDpnForInterface(interfaceManager, vpnInterfaceName);
1190 if(dpId.equals(BigInteger.ZERO)) {
1191 LOG.warn("Could not retrieve dp id for interface {} to handle router {} association model", vpnInterfaceName, routerName);
1194 InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
1196 Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
1197 .OPERATIONAL, routerDpnListIdentifier);
1198 RouterInterfaces routerInterface = new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName)).setInterface(vpnInterfaceName).build();
1199 if (optionalRouterDpnList.isPresent()) {
1200 MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
1201 RouterInterfaces.class, new RouterInterfacesKey(vpnInterfaceName)), routerInterface);
1203 MDSALUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
1204 getRouterId(routerName),
1205 new RouterDpnListBuilder().setRouterId(routerName).build());
1206 //VpnToDpnListBuilder vpnToDpnList = new VpnToDpnListBuilder().setDpnId(dpnId);
1207 DpnVpninterfacesListBuilder dpnVpnList = new DpnVpninterfacesListBuilder().setDpnId(dpId);
1208 List<RouterInterfaces> routerInterfaces = new ArrayList<>();
1209 routerInterfaces.add(routerInterface);
1210 MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier,
1211 dpnVpnList.setRouterInterfaces(routerInterfaces).build());
1215 protected void removeFromNeutronRouterDpnsMap(String routerName, String vpnInterfaceName) {
1216 BigInteger dpId = InterfaceUtils.getDpnForInterface(interfaceManager, vpnInterfaceName);
1217 if(dpId.equals(BigInteger.ZERO)) {
1218 LOG.warn("Could not retrieve dp id for interface {} to handle router {} dissociation model", vpnInterfaceName, routerName);
1221 InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
1222 Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
1223 .OPERATIONAL, routerDpnListIdentifier);
1224 if (optionalRouterDpnList.isPresent()) {
1225 List<RouterInterfaces> routerInterfaces = optionalRouterDpnList.get().getRouterInterfaces();
1226 RouterInterfaces routerInterface = new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName)).setInterface(vpnInterfaceName).build();
1228 if (routerInterfaces != null && routerInterfaces.remove(routerInterface)) {
1229 if (routerInterfaces.isEmpty()) {
1230 MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
1232 MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
1233 RouterInterfaces.class,
1234 new RouterInterfacesKey(vpnInterfaceName)));
1240 protected void removeFromNeutronRouterDpnsMap(String routerName, String vpnInterfaceName,BigInteger dpId) {
1241 if(dpId.equals(BigInteger.ZERO)) {
1242 LOG.warn("Could not retrieve dp id for interface {} to handle router {} dissociation model", vpnInterfaceName, routerName);
1245 InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
1246 Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
1247 .OPERATIONAL, routerDpnListIdentifier);
1248 if (optionalRouterDpnList.isPresent()) {
1249 List<RouterInterfaces> routerInterfaces = optionalRouterDpnList.get().getRouterInterfaces();
1250 RouterInterfaces routerInterface = new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName)).setInterface(vpnInterfaceName).build();
1252 if (routerInterfaces != null && routerInterfaces.remove(routerInterface)) {
1253 if (routerInterfaces.isEmpty()) {
1254 MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
1256 MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
1257 RouterInterfaces.class,
1258 new RouterInterfacesKey(vpnInterfaceName)));