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.vpnservice;
10 import org.opendaylight.vpnservice.utilities.InterfaceUtils;
11 import com.google.common.util.concurrent.FutureCallback;
12 import com.google.common.util.concurrent.Futures;
13 import com.google.common.util.concurrent.JdkFutureAdapters;
15 import org.opendaylight.controller.md.sal.binding.api.*;
17 import org.opendaylight.vpnservice.mdsalutil.*;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyKey;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListBuilder;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.OdlArputilService;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.SendArpResponseInput;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.SendArpResponseInputBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.itm.rpcs.rev151217.ItmRpcService;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServices;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesKey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntry;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntryKey;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
40 import java.math.BigInteger;
41 import java.util.Collection;
42 import java.util.Iterator;
43 import java.util.List;
44 import java.util.ArrayList;
45 import java.util.concurrent.Future;
47 import com.google.common.base.Optional;
49 import org.opendaylight.bgpmanager.api.IBgpManager;
50 import org.opendaylight.fibmanager.api.IFibManager;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
52 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
53 import org.opendaylight.yangtools.concepts.ListenerRegistration;
54 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
55 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
56 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
57 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.Adjacency;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
61 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.Adjacencies;
63 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
64 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
65 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
66 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
67 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
68 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
69 import org.opendaylight.yangtools.yang.common.RpcError;
70 import org.opendaylight.yangtools.yang.common.RpcResult;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
74 public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface> implements AutoCloseable {
75 private static final Logger LOG = LoggerFactory.getLogger(VpnInterfaceManager.class);
76 private ListenerRegistration<DataChangeListener> listenerRegistration;
77 private final DataBroker broker;
78 private final IBgpManager bgpManager;
79 private IFibManager fibManager;
80 private IMdsalApiManager mdsalManager;
81 private OdlInterfaceRpcService interfaceManager;
82 private ItmRpcService itmProvider;
83 private IdManagerService idManager;
84 private OdlArputilService arpManager;
85 private InterfaceStateChangeListener interfaceListener;
86 private ArpNotificationHandler arpNotificationHandler;
87 protected enum UpdateRouteAction {
88 ADVERTISE_ROUTE, WITHDRAW_ROUTE
91 * Responsible for listening to data change related to VPN Interface
92 * Bind VPN Service on the interface and informs the BGP service
94 * @param db - dataBroker service reference
96 public VpnInterfaceManager(final DataBroker db, final IBgpManager bgpManager, NotificationService notificationService) {
97 super(VpnInterface.class);
99 this.bgpManager = bgpManager;
100 interfaceListener = new InterfaceStateChangeListener(db, this);
101 arpNotificationHandler = new ArpNotificationHandler(this, broker);
102 notificationService.registerNotificationListener(arpNotificationHandler);
103 registerListener(db);
106 public void setMdsalManager(IMdsalApiManager mdsalManager) {
107 this.mdsalManager = mdsalManager;
110 public void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {
111 this.interfaceManager = interfaceManager;
112 interfaceListener.setInterfaceManager(interfaceManager);
115 public void setITMProvider(ItmRpcService itmProvider) {
116 this.itmProvider = itmProvider;
119 public void setFibManager(IFibManager fibManager) {
120 this.fibManager = fibManager;
123 public void setIdManager(IdManagerService idManager) {
124 this.idManager = idManager;
127 public void setArpManager(OdlArputilService arpManager) {
128 this.arpManager = arpManager;
132 public void close() throws Exception {
133 if (listenerRegistration != null) {
135 listenerRegistration.close();
136 } catch (final Exception e) {
137 LOG.error("Error when cleaning up DataChangeListener.", e);
139 listenerRegistration = null;
141 LOG.info("VPN Interface Manager Closed");
144 private void registerListener(final DataBroker db) {
146 listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
147 getWildCardPath(), VpnInterfaceManager.this, DataChangeScope.SUBTREE);
148 } catch (final Exception e) {
149 LOG.error("VPN Service DataChange listener registration fail!", e);
150 throw new IllegalStateException("VPN Service registration Listener failed.", e);
154 private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> getInterfaceListenerPath() {
155 return InstanceIdentifier.create(InterfacesState.class)
156 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class);
160 protected void add(final InstanceIdentifier<VpnInterface> identifier,
161 final VpnInterface vpnInterface) {
162 LOG.trace("key: {} , value: {}", identifier, vpnInterface );
163 addInterface(identifier, vpnInterface);
166 private void addInterface(final InstanceIdentifier<VpnInterface> identifier,
167 final VpnInterface vpnInterface) {
168 LOG.trace("Add event - key: {}, value: {}" ,identifier, vpnInterface );
169 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
170 String interfaceName = key.getName();
172 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState =
173 InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName);
174 if (interfaceState != null) {
175 // Interface state is up
176 processVpnInterfaceUp(interfaceName, interfaceState.getIfIndex());
180 protected synchronized void processVpnInterfaceUp(String interfaceName, int lPortTag) {
182 VpnInterface vpnInterface = VpnUtil.getConfiguredVpnInterface(broker, interfaceName);
183 if(vpnInterface == null) {
184 LOG.info("Unable to process add/up for interface {} as it is not configured", interfaceName);
187 String vpnName = vpnInterface.getVpnInstanceName();
188 LOG.info("Binding vpn service to interface {} ", interfaceName);
189 bindService(vpnName, interfaceName, lPortTag);
190 updateDpnDbs(vpnName, interfaceName, true);
191 processVpnInterfaceAdjacencies(VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
195 private void updateDpnDbs(String vpnName, String interfaceName, boolean add) {
196 long vpnId = VpnUtil.getVpnId(broker, vpnName);
197 BigInteger dpId = InterfaceUtils.getDpnForInterface(interfaceManager, interfaceName);
198 if(!dpId.equals(BigInteger.ZERO)) {
200 updateMappingDbs(vpnId, dpId, interfaceName, vpnName);
202 removeFromMappingDbs(vpnId, dpId, interfaceName, vpnName);
207 private void bindService(String vpnInstanceName, String vpnInterfaceName, int lPortTag) {
208 int priority = VpnConstants.DEFAULT_FLOW_PRIORITY;
209 long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName);
211 int instructionKey = 0;
212 List<Instruction> instructions = new ArrayList<Instruction>();
214 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID, ++instructionKey));
215 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(VpnConstants.FIB_TABLE, ++instructionKey));
219 InterfaceUtils.getBoundServices(String.format("%s.%s.%s", "vpn",vpnInstanceName, vpnInterfaceName),
220 VpnConstants.L3VPN_SERVICE_IDENTIFIER, priority,
221 VpnConstants.COOKIE_VM_INGRESS_TABLE, instructions);
222 VpnUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
223 InterfaceUtils.buildServiceId(vpnInterfaceName, VpnConstants.L3VPN_SERVICE_IDENTIFIER), serviceInfo);
224 makeArpFlow(VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName, vpnId, ArpReplyOrRequest.REQUEST, NwConstants.ADD_FLOW);
228 private void processVpnInterfaceAdjacencies(final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
229 String intfName = intf.getName();
231 synchronized (intfName) {
233 InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
234 Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
236 if (adjacencies.isPresent()) {
237 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
238 List<Adjacency> value = new ArrayList<>();
240 // Get the rd of the vpn instance
241 String rd = getRouteDistinguisher(intf.getVpnInstanceName());
243 BigInteger dpnId = InterfaceUtils.getDpnForInterface(interfaceManager, intfName);
244 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
245 if (nextHopIp == null){
246 LOG.error("NextHop for interface {} is null", intfName);
249 LOG.trace("NextHops are {}", nextHops);
250 for (Adjacency nextHop : nextHops) {
251 String prefix = VpnUtil.getIpPrefix(nextHop.getIpAddress());
252 long label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, VpnUtil
253 .getNextHopLabelKey((rd == null) ? intf.getVpnInstanceName() : rd, prefix));
254 String adjNextHop = nextHop.getNextHopIp();
255 value.add(new AdjacencyBuilder(nextHop).setLabel(label).setNextHopIp((adjNextHop != null && !adjNextHop.isEmpty()) ? adjNextHop : nextHopIp)
256 .setIpAddress(prefix).setKey(new AdjacencyKey(prefix)).build());
257 if(nextHop.getMacAddress() != null && !nextHop.getMacAddress().isEmpty()) {
260 LogicalDatastoreType.OPERATIONAL,
261 VpnUtil.getPrefixToInterfaceIdentifier(
262 VpnUtil.getVpnId(broker, intf.getVpnInstanceName()), prefix),
263 VpnUtil.getPrefixToInterface(dpnId, intf.getName(), prefix));
267 Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(value);
268 VpnInterface opInterface = VpnUtil.getVpnInterface(intfName, intf.getVpnInstanceName(), aug);
269 InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(intfName);
270 VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, interfaceId, opInterface);
271 for (Adjacency nextHop : aug.getAdjacency()) {
272 long label = nextHop.getLabel();
273 String adjNextHop = nextHop.getNextHopIp();
275 addPrefixToBGP(rd, nextHop.getIpAddress(),
276 (adjNextHop != null && !adjNextHop.isEmpty()) ? adjNextHop : nextHopIp, label);
278 // ### add FIB route directly
279 addFibEntryToDS(intf.getVpnInstanceName(), nextHop.getIpAddress(),
280 (adjNextHop != null && !adjNextHop.isEmpty()) ? adjNextHop : nextHopIp, (int) label);
287 private void makeArpFlow(short sIndex, int lPortTag, String vpnInterfaceName, long vpnId, ArpReplyOrRequest replyOrRequest, int addOrRemoveFlow){
288 List<MatchInfo> matches = new ArrayList<MatchInfo>();
289 BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lPortTag, sIndex, BigInteger.valueOf(vpnId));
290 BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
291 MetaDataUtil.METADATA_MASK_LPORT_TAG, MetaDataUtil.METADATA_MASK_VRFID);
293 // Matching Arp reply flows
294 matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_ARP }));
295 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
296 metadata, metadataMask }));
298 matches.add(new MatchInfo(MatchFieldType.arp_op, new long[] { replyOrRequest.getArpOperation() }));
300 // Instruction to punt to controller
301 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
302 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
303 actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[] {}));
304 instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
306 // Install the flow entry in L3_INTERFACE_TABLE
307 BigInteger dpId = InterfaceUtils.getDpnForInterface(interfaceManager, vpnInterfaceName);
308 String flowRef = VpnUtil.getFlowRef(dpId, VpnConstants.L3_INTERFACE_TABLE,
309 NwConstants.ETHTYPE_ARP, lPortTag, replyOrRequest.getArpOperation());
310 FlowEntity flowEntity;
311 flowEntity = MDSALUtil.buildFlowEntity(dpId, VpnConstants.L3_INTERFACE_TABLE, flowRef,
312 NwConstants.DEFAULT_ARP_FLOW_PRIORITY, replyOrRequest.getName(), 0, 0,
313 VpnUtil.getCookieArpFlow(lPortTag), matches, instructions);
315 if (addOrRemoveFlow == NwConstants.ADD_FLOW) {
316 LOG.debug("Creating ARP Flow for interface {}",vpnInterfaceName);
317 mdsalManager.installFlow(flowEntity);
319 LOG.debug("Deleting ARP Flow for interface {}",vpnInterfaceName);
320 mdsalManager.removeFlow(flowEntity);
324 private String getRouteDistinguisher(String vpnName) {
325 InstanceIdentifier<VpnInstance> id = InstanceIdentifier.builder(VpnInstances.class)
326 .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
327 Optional<VpnInstance> vpnInstance = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
329 if(vpnInstance.isPresent()) {
330 VpnInstance instance = vpnInstance.get();
331 VpnAfConfig config = instance.getIpv4Family();
332 rd = config.getRouteDistinguisher();
337 private synchronized void updateMappingDbs(long vpnId, BigInteger dpnId, String intfName, String vpnName) {
338 String routeDistinguisher = getRouteDistinguisher(vpnName);
339 String rd = (routeDistinguisher == null) ? vpnName : routeDistinguisher;
340 InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
341 Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
342 org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
343 vpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
345 if (dpnInVpn.isPresent()) {
346 VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id.child(
347 org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance
348 .op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
349 new VpnInterfacesKey(intfName)), vpnInterface);
351 VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
352 VpnUtil.getVpnInstanceOpDataIdentifier(rd),
353 VpnUtil.getVpnInstanceOpData(rd, vpnId));
354 VpnToDpnListBuilder vpnToDpnList = new VpnToDpnListBuilder().setDpnId(dpnId);
355 List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
356 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = new ArrayList<>();
357 vpnInterfaces.add(vpnInterface);
358 VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id,
359 vpnToDpnList.setVpnInterfaces(vpnInterfaces).build());
362 * FIXME: DC Gateway tunnel should be built dynamically
363 //this is the first VM in this VPN on the DPN, may be a new DPN has come up,
364 //if tunnel to DC GW does not exist, create it
365 //if(!tunnelExists(dpnID, bgpManager.getDCGWIP()))
366 String dcGW = bgpManager.getDCGwIP();
367 if(dcGW != null && !dcGW.isEmpty())
369 LOG.debug("Building tunnel from DPN {} to DC GW {}", dpnId, dcGW);
370 itmProvider.buildTunnelFromDPNToDCGW(dpnId, new IpAddress(dcGW.toCharArray()));
372 fibManager.populateFibOnNewDpn(dpnId, vpnId, (rd == null) ? vpnName : rd);
376 private synchronized void removeFromMappingDbs(long vpnId, BigInteger dpnId, String intfName, String vpnName) {
377 //TODO: Delay 'DPN' removal so that other services can cleanup the entries for this dpn
378 String rd = VpnUtil.getVpnRd(broker, vpnName);
379 InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
380 Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
381 if (dpnInVpn.isPresent()) {
382 List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
383 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
384 org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
385 currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
387 if (vpnInterfaces.remove(currVpnInterface)) {
388 if (vpnInterfaces.isEmpty()) {
389 VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id, VpnUtil.DEFAULT_CALLBACK);
390 fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd);
392 VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
393 org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
394 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
395 new VpnInterfacesKey(intfName)), VpnUtil.DEFAULT_CALLBACK);
401 private void addPrefixToBGP(String rd, String prefix, String nextHopIp, long label) {
403 bgpManager.addPrefix(rd, prefix, nextHopIp, (int)label);
404 } catch(Exception e) {
405 LOG.error("Add prefix failed", e);
410 private InstanceIdentifier<VpnInterface> getWildCardPath() {
411 return InstanceIdentifier.create(VpnInterfaces.class).child(VpnInterface.class);
415 protected void remove( InstanceIdentifier<VpnInterface> identifier, VpnInterface vpnInterface) {
416 LOG.trace("Remove event - key: {}, value: {}" ,identifier, vpnInterface );
417 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
418 String interfaceName = key.getName();
420 InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
421 Optional<VpnInterface> existingVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, interfaceId);
422 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState =
423 InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName);
425 if (existingVpnInterface.isPresent() && interfaceState != null) {
426 processVpnInterfaceDown(interfaceName, interfaceState.getIfIndex());
428 LOG.warn("VPN interface {} was unavailable in operational data store to handle remove event", interfaceName);
432 protected synchronized void processVpnInterfaceDown(String interfaceName, int lPortTag) {
433 VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(broker, interfaceName);
434 if(vpnInterface == null) {
435 LOG.info("Unable to process delete/down for interface {} as it is not available in operational data store", interfaceName);
438 String vpnName = vpnInterface.getVpnInstanceName();
439 InstanceIdentifier<VpnInterface> identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
441 removeAdjacenciesFromVpn(identifier, vpnInterface);
442 LOG.info("Unbinding vpn service from interface {} ", interfaceName);
443 unbindService(vpnName, interfaceName, lPortTag);
444 updateDpnDbs(vpnName, interfaceName, false);
445 VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, identifier, VpnUtil.DEFAULT_CALLBACK);
448 private void removeAdjacenciesFromVpn(final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
450 InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
451 Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
453 String rd = VpnUtil.getVpnRd(broker, intf.getVpnInstanceName());
454 if (adjacencies.isPresent()) {
455 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
457 if (!nextHops.isEmpty()) {
458 LOG.trace("NextHops are " + nextHops);
459 for (Adjacency nextHop : nextHops) {
460 VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME,
461 VpnUtil.getNextHopLabelKey(rd, nextHop.getIpAddress()));
462 VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
463 VpnUtil.getPrefixToInterfaceIdentifier(
464 VpnUtil.getVpnId(broker, intf.getVpnInstanceName()),
465 nextHop.getIpAddress()),
466 VpnUtil.DEFAULT_CALLBACK);
467 if (rd.equals(intf.getVpnInstanceName())) {
468 //this is an internal vpn - the rd is assigned to the vpn instance name;
469 //remove from FIB directly
470 removeFibEntryFromDS(intf.getVpnInstanceName(), nextHop.getIpAddress());
472 removePrefixFromBGP(rd, nextHop.getIpAddress());
480 private void unbindService(String vpnInstanceName, String vpnInterfaceName, int lPortTag) {
481 VpnUtil.delete(broker, LogicalDatastoreType.CONFIGURATION,
482 InterfaceUtils.buildServiceId(vpnInterfaceName,VpnConstants.L3VPN_SERVICE_IDENTIFIER),
483 VpnUtil.DEFAULT_CALLBACK);
484 long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName);
485 makeArpFlow(VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
486 vpnId, ArpReplyOrRequest.REQUEST, NwConstants.DEL_FLOW);
490 private void removePrefixFromBGP(String rd, String prefix) {
492 bgpManager.deletePrefix(rd, prefix);
493 } catch(Exception e) {
494 LOG.error("Delete prefix failed", e);
499 protected void update(InstanceIdentifier<VpnInterface> identifier,
500 VpnInterface original, VpnInterface update) {
501 LOG.trace("Update VPN Interface {} , original {}, update {}",
502 identifier, original, update);
503 String vpnName = original.getVpnInstanceName();
505 boolean vpnNameChanged = false;
506 String rd = getRouteDistinguisher(vpnName);
508 String newVpnName = update.getVpnInstanceName();
509 if(!vpnName.equals(newVpnName)) {
510 //VPN for this interface got changed.
511 //Remove the interface from old VPN and add it to new VPN
512 newRd = getRouteDistinguisher(newVpnName);
513 if(newRd.equals("")) {
514 LOG.warn("VPN Instance {} not found. Update operation aborted", newVpnName);
517 vpnNameChanged = true;
518 LOG.debug("New VPN Name for the interface {} is {}", newVpnName, original.getName());
521 List<Adjacency> oldAdjs = original.getAugmentation(Adjacencies.class).getAdjacency();
522 List<Adjacency> newAdjs = update.getAugmentation(Adjacencies.class).getAdjacency();
523 if(vpnNameChanged && newAdjs != null && !newAdjs.isEmpty()) {
524 long label = VpnConstants.INVALID_ID;
525 InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
526 Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
527 if (adjacencies.isPresent()) {
528 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
529 for(Adjacency nextHop : nextHops) {
530 label = nextHop.getLabel();
531 if(label == VpnConstants.INVALID_ID) {
532 //Generate label using ID Manager
533 label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
534 VpnUtil.getNextHopLabelKey(newRd, nextHop.getIpAddress()));
537 removePrefixFromBGP(rd, nextHop.getIpAddress());
539 removeFibEntryFromDS(vpnName, nextHop.getIpAddress());
541 //updatePrefixToBGP(newRd, nextHop, nextHopIp, label);
543 processVpnInterfaceAdjacencies(identifier, update);
544 VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, update);
546 } else if (oldAdjs != newAdjs) {
547 //handle both addition and removal of adjacencies
548 //currently, new adjacency may be an extra route
549 for (Adjacency adj : newAdjs) {
550 if (oldAdjs.contains(adj)) {
553 // add new adjacency - right now only extra route will hit this path
554 addNewAdjToVpnInterface(identifier, adj);
558 for (Adjacency adj : oldAdjs) {
559 delAdjFromVpnInterface(identifier, adj);
563 LOG.debug("No Update information is available for VPN Interface to proceed");
568 public void processArpRequest(IpAddress srcIP, PhysAddress srcMac, IpAddress targetIP, String srcInterface){
569 SendArpResponseInput input = new SendArpResponseInputBuilder().setInterface(srcInterface)
570 .setIpaddress(srcIP).setSrcIpAddress(targetIP).setMacaddress(srcMac).build();
571 final String msgFormat = String.format("Send ARP Response on interface %s to destination %s", srcInterface, srcIP);
572 Future<RpcResult<Void>> future = arpManager.sendArpResponse(input);
573 Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future), new FutureCallback<RpcResult<Void>>() {
575 public void onFailure(Throwable error) {
576 LOG.error("Error - {}", msgFormat, error);
580 public void onSuccess(RpcResult<Void> result) {
581 if(!result.isSuccessful()) {
582 LOG.warn("Rpc call to {} failed", msgFormat, getErrorText(result.getErrors()));
584 LOG.debug("Successful RPC Result - {}", msgFormat);
590 private String getErrorText(Collection<RpcError> errors) {
591 StringBuilder errorText = new StringBuilder();
592 for(RpcError error : errors) {
593 errorText.append(",").append(error.getErrorType()).append("-")
594 .append(error.getMessage());
596 return errorText.toString();
599 private String getTunnelInterfaceFlowRef(BigInteger dpnId, short tableId, String ifName) {
600 return new StringBuilder().append(dpnId).append(tableId).append(ifName).toString();
605 public synchronized void addFibEntryToDS(String rd, String prefix,
606 String nexthop, int label) {
608 VrfEntry vrfEntry = new VrfEntryBuilder().setDestPrefix(prefix).
609 setNextHopAddress(nexthop).setLabel((long)label).build();
610 LOG.debug("Created vrfEntry for {} nexthop {} label {}", prefix, nexthop, label);
612 List<VrfEntry> vrfEntryList = new ArrayList<VrfEntry>();
613 vrfEntryList.add(vrfEntry);
615 InstanceIdentifierBuilder<VrfTables> idBuilder =
616 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
617 InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
619 VrfTables vrfTableNew = new VrfTablesBuilder().setRouteDistinguisher(rd).
620 setVrfEntry(vrfEntryList).build();
622 VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, vrfTableId, vrfTableNew);
625 public synchronized void removeFibEntryFromDS(String rd, String prefix) {
627 LOG.debug("Removing fib entry with destination prefix {} from vrf table for rd {}", prefix, rd);
629 InstanceIdentifierBuilder<VrfEntry> idBuilder =
630 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).child(VrfEntry.class, new VrfEntryKey(prefix));
631 InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
632 VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, vrfEntryId, VpnUtil.DEFAULT_CALLBACK);
636 public synchronized void removeVrfFromDS(String rd) {
637 LOG.debug("Removing vrf table for rd {}", rd);
639 InstanceIdentifierBuilder<VrfTables> idBuilder =
640 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
641 InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
643 VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, vrfTableId, VpnUtil.DEFAULT_CALLBACK);
647 protected void addNewAdjToVpnInterface(InstanceIdentifier<VpnInterface> identifier, Adjacency adj) {
649 Optional<VpnInterface> optVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
651 if (optVpnInterface.isPresent()) {
652 VpnInterface currVpnIntf = optVpnInterface.get();
653 String prefix = VpnUtil.getIpPrefix(adj.getIpAddress());
654 String rd = getRouteDistinguisher(currVpnIntf.getVpnInstanceName());
655 InstanceIdentifier<Adjacencies> adjPath = identifier.augmentation(Adjacencies.class);
656 Optional<Adjacencies> optAdjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, adjPath);
658 VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
659 VpnUtil.getNextHopLabelKey((rd != null) ? rd : currVpnIntf.getVpnInstanceName(), prefix));
661 List<Adjacency> adjacencies;
662 if (optAdjacencies.isPresent()) {
663 adjacencies = optAdjacencies.get().getAdjacency();
665 //This code will not be hit since VM adjacency will always be there
666 adjacencies = new ArrayList<>();
669 adjacencies.add(new AdjacencyBuilder(adj).setLabel(label).setNextHopIp(adj.getNextHopIp())
670 .setIpAddress(prefix).setKey(new AdjacencyKey(prefix)).build());
672 Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencies);
673 VpnInterface newVpnIntf = VpnUtil.getVpnInterface(currVpnIntf.getName(), currVpnIntf.getVpnInstanceName(), aug);
675 VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, newVpnIntf);
676 addExtraRoute(adj.getIpAddress(), adj.getNextHopIp(), rd, currVpnIntf.getVpnInstanceName(), (int) label);
682 protected void delAdjFromVpnInterface(InstanceIdentifier<VpnInterface> identifier, Adjacency adj) {
683 Optional<VpnInterface> optVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
685 if (optVpnInterface.isPresent()) {
686 VpnInterface currVpnIntf = optVpnInterface.get();
688 InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
689 Optional<Adjacencies> optAdjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
690 if (optAdjacencies.isPresent()) {
691 List<Adjacency> adjacencies = optAdjacencies.get().getAdjacency();
693 if (!adjacencies.isEmpty()) {
694 String rd = getRouteDistinguisher(currVpnIntf.getVpnInstanceName());
695 LOG.trace("Adjacencies are " + adjacencies);
696 Iterator<Adjacency> adjIt = adjacencies.iterator();
697 while (adjIt.hasNext()) {
698 Adjacency adjElem = adjIt.next();
699 if (adjElem.getIpAddress().equals(adj.getIpAddress())) {
700 VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME,
701 VpnUtil.getNextHopLabelKey(rd, adj.getIpAddress()));
704 Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencies);
705 VpnInterface newVpnIntf = VpnUtil.getVpnInterface(currVpnIntf.getName(), currVpnIntf.getVpnInstanceName(), aug);
707 VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, newVpnIntf);
709 delExtraRoute(adj.getIpAddress(), rd, currVpnIntf.getVpnInstanceName());
720 protected void addExtraRoute(String destination, String nextHop, String rd, String routerID, int label) {
722 addPrefixToBGP(rd, destination, nextHop, label);
724 // ### add FIB route directly
725 addFibEntryToDS(routerID, destination, nextHop, label);
729 protected void delExtraRoute(String destination, String rd, String routerID) {
731 removePrefixFromBGP(rd, destination);
733 // ### add FIB route directly
734 removeFibEntryFromDS(routerID, destination);
738 protected void updatePrefixesForDPN(BigInteger dpnId, UpdateRouteAction action) {
740 InstanceIdentifierBuilder<VpnInstances> idBuilder = InstanceIdentifier.builder(VpnInstances.class);
741 InstanceIdentifier<VpnInstances> vpnInstancesId = idBuilder.build();
742 Optional<VpnInstances> vpnInstances = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vpnInstancesId);
744 if (vpnInstances.isPresent()) {
745 List<VpnInstance> vpnInstanceList = vpnInstances.get().getVpnInstance();
746 Iterator<VpnInstance> vpnInstIter = vpnInstanceList.iterator();
747 while (vpnInstIter.hasNext()) {
748 VpnInstance vpnInstance = vpnInstIter.next();
749 VpnAfConfig vpnConfig = vpnInstance.getIpv4Family();
750 String rd = vpnConfig.getRouteDistinguisher();
752 InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
753 Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
754 if (dpnInVpn.isPresent()) {
755 if (action == UpdateRouteAction.ADVERTISE_ROUTE) {
756 fibManager.populateFibOnNewDpn(dpnId, VpnUtil
757 .getVpnId(broker, vpnInstance.getVpnInstanceName()), rd);
759 List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
760 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
761 for(org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
762 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces vpnInterface : vpnInterfaces) {
763 InstanceIdentifier<VpnInterface> vpnIntfId = VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getInterfaceName());
764 InstanceIdentifier<Adjacencies> path = vpnIntfId.augmentation(Adjacencies.class);
765 Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
767 if (adjacencies.isPresent()) {
768 List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
769 Iterator<Adjacency> adjacencyIterator = adjacencyList.iterator();
771 while (adjacencyIterator.hasNext()) {
772 Adjacency adjacency = adjacencyIterator.next();
774 if(action == UpdateRouteAction.ADVERTISE_ROUTE)
775 bgpManager.addPrefix(rd, adjacency.getIpAddress(), adjacency.getNextHopIp(), adjacency.getLabel().intValue());
776 else if(action == UpdateRouteAction.WITHDRAW_ROUTE)
777 bgpManager.deletePrefix(rd, adjacency.getIpAddress());
778 } catch (Exception e) {
779 LOG.error("Exception when updating prefix {} in vrf {} to BGP", adjacency.getIpAddress(), rd);
785 if (action == UpdateRouteAction.WITHDRAW_ROUTE) {
786 fibManager.cleanUpDpnForVpn(dpnId, VpnUtil
787 .getVpnId(broker, vpnInstance.getVpnInstanceName()), rd);