2 * Copyright (c) 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
9 package org.opendaylight.netvirt.natservice.internal;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Strings;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import com.google.common.util.concurrent.MoreExecutors;
17 import java.math.BigInteger;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.List;
23 import java.util.concurrent.ExecutionException;
24 import javax.annotation.Nonnull;
25 import javax.annotation.PostConstruct;
26 import javax.inject.Inject;
27 import javax.inject.Singleton;
28 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
29 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
30 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
31 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
32 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
33 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
34 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
35 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
36 import org.opendaylight.genius.mdsalutil.BucketInfo;
37 import org.opendaylight.genius.mdsalutil.FlowEntity;
38 import org.opendaylight.genius.mdsalutil.GroupEntity;
39 import org.opendaylight.genius.mdsalutil.MDSALUtil;
40 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
41 import org.opendaylight.genius.mdsalutil.NwConstants;
42 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
43 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
44 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
45 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
46 import org.opendaylight.netvirt.elanmanager.api.IElanService;
47 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
48 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
49 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryOutput;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryOutput;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersList;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.dpn.routers.list.RoutersList;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
80 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
81 import org.opendaylight.yangtools.yang.common.RpcResult;
82 import org.slf4j.Logger;
83 import org.slf4j.LoggerFactory;
86 public class NatTunnelInterfaceStateListener
87 extends AsyncDataTreeChangeListenerBase<StateTunnelList, NatTunnelInterfaceStateListener> {
89 private static final Logger LOG = LoggerFactory.getLogger(NatTunnelInterfaceStateListener.class);
90 private final DataBroker dataBroker;
91 private final ManagedNewTransactionRunner txRunner;
92 private final IFibManager fibManager;
93 private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
94 private final NaptSwitchHA naptSwitchHA;
95 private final IMdsalApiManager mdsalManager;
96 private final IdManagerService idManager;
97 private final IBgpManager bgpManager;
98 private final ExternalRoutersListener externalRouterListner;
99 private final SnatServiceManager natServiceManager;
100 private final OdlInterfaceRpcService interfaceService;
101 private final FloatingIPListener floatingIPListener;
102 private final FibRpcService fibRpcService;
103 private final IElanService elanManager;
104 private final IInterfaceManager interfaceManager;
105 private final NatMode natMode;
107 protected enum TunnelAction {
114 * Responsible for listening to tunnel interface state change.
116 * @param dataBroker - dataBroker service reference
117 * @param bgpManager Used to advertise routes to the BGP Router
118 * @param fibManager - FIB Manager
119 * @param defaultRouteProgrammer - Default Route Programmer
120 * @param naptSwitchHA - NAPT Switch HA
121 * @param mdsalManager - MDSAL Manager
122 * @param idManager - ID manager
123 * @param externalRouterListner - External Router Listener
124 * @param natServiceManager - Nat Service Manager
125 * @param interfaceService - Interface Service
126 * @param floatingIPListener - Floating IP Listener
127 * @param fibRpcService - FIB RPC Service
128 * @param config - Nat Service Config
129 * @param elanManager - Elan Manager
130 * @param interfaceManager - Interface Manager
133 public NatTunnelInterfaceStateListener(final DataBroker dataBroker,
134 final IBgpManager bgpManager,
135 final IFibManager fibManager,
136 final SNATDefaultRouteProgrammer defaultRouteProgrammer,
137 final NaptSwitchHA naptSwitchHA,
138 final IMdsalApiManager mdsalManager,
139 final IdManagerService idManager,
140 final ExternalRoutersListener externalRouterListner,
141 final SnatServiceManager natServiceManager,
142 final OdlInterfaceRpcService interfaceService,
143 final FloatingIPListener floatingIPListener,
144 final FibRpcService fibRpcService,
145 final NatserviceConfig config,
146 final IElanService elanManager,
147 final IInterfaceManager interfaceManager) {
148 super(StateTunnelList.class, NatTunnelInterfaceStateListener.class);
149 this.dataBroker = dataBroker;
150 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
151 this.bgpManager = bgpManager;
152 this.fibManager = fibManager;
153 this.defaultRouteProgrammer = defaultRouteProgrammer;
154 this.naptSwitchHA = naptSwitchHA;
155 this.mdsalManager = mdsalManager;
156 this.idManager = idManager;
157 this.externalRouterListner = externalRouterListner;
158 this.natServiceManager = natServiceManager;
159 this.interfaceService = interfaceService;
160 this.floatingIPListener = floatingIPListener;
161 this.fibRpcService = fibRpcService;
162 this.elanManager = elanManager;
163 this.interfaceManager = interfaceManager;
164 if (config != null) {
165 this.natMode = config.getNatMode();
167 this.natMode = NatMode.Controller;
174 LOG.info("{} init", getClass().getSimpleName());
175 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
179 protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
180 return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
184 protected NatTunnelInterfaceStateListener getDataTreeChangeListener() {
185 return NatTunnelInterfaceStateListener.this;
189 protected void add(InstanceIdentifier<StateTunnelList> instanceIdentifier, StateTunnelList add) {
190 LOG.trace("add : TEP addtion---- {}", add);
191 hndlTepEvntsForDpn(add, TunnelAction.TUNNEL_EP_ADD);
195 protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
196 LOG.trace("remove : TEP deletion---- {}", del);
197 hndlTepEvntsForDpn(del, TunnelAction.TUNNEL_EP_DELETE);
201 protected void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original,
202 StateTunnelList update) {
203 LOG.trace("update : Tunnel updation---- {}", update);
204 //UPDATE IS A SEQUENCE OF DELETE AND ADD EVENTS . DELETE MIGHT HAVE CHANGED THE PRIMARY AND ADVERTISED. SO
208 private int getTunnelType(StateTunnelList stateTunnelList) {
210 if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
211 tunTypeVal = NatConstants.ITMTunnelLocType.Internal.getValue();
212 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
213 tunTypeVal = NatConstants.ITMTunnelLocType.External.getValue();
214 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
215 tunTypeVal = NatConstants.ITMTunnelLocType.Hwvtep.getValue();
217 tunTypeVal = NatConstants.ITMTunnelLocType.Invalid.getValue();
222 // TODO Clean up the exception handling
223 @SuppressWarnings("checkstyle:IllegalCatch")
224 void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerId, long routerVpnId,
225 Uuid networkId, ProviderTypes extNwProvType, WriteTransaction writeFlowInvTx) {
226 //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
227 //remove miss entry to NAPT switch
228 //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
230 if (routerId == NatConstants.INVALID_ID) {
231 LOG.error("removeSNATFromDPN : SNAT -> Invalid routerId returned for routerName {}", routerName);
234 Collection<String> externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
235 if (extNwProvType == null) {
238 Map<String, Long> externalIpLabel;
239 if (extNwProvType == ProviderTypes.VXLAN) {
240 externalIpLabel = null;
242 externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
245 final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
246 if (externalVpnName == null) {
247 LOG.error("removeSNATFromDPN : SNAT -> No VPN associated with ext nw {} in router {}",
248 networkId, routerId);
252 BigInteger naptSwitch = dpnId;
254 naptSwitchHA.isNaptSwitchDown(routerName, routerId, dpnId, naptSwitch,
255 routerVpnId, externalIpCache, false, writeFlowInvTx);
257 LOG.debug("removeSNATFromDPN:SNAT->NaptSwitchDown:Switch with DpnId {} is not naptSwitch for router {}",
259 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
260 FlowEntity flowEntity = null;
262 flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId,
263 routerVpnId, NatConstants.DEL_FLOW);
264 if (flowEntity == null) {
265 LOG.error("removeSNATFromDPN : SNAT -> Failed to populate flowentity for "
266 + "router {} with dpnId {} groupIs {}", routerName, dpnId, groupId);
269 LOG.debug("removeSNATFromDPN : SNAT->Removing default SNAT miss entry flow entity {}", flowEntity);
270 mdsalManager.removeFlowToTx(flowEntity, writeFlowInvTx);
272 } catch (Exception ex) {
273 LOG.error("removeSNATFromDPN : SNAT->Failed to remove default SNAT miss entry flow entity {}",
277 LOG.debug("removeSNATFromDPN:SNAT->Removed default SNAT miss entry flow for dpnID {}, routername {}",
281 GroupEntity groupEntity = null;
283 groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
284 GroupTypes.GroupAll, Collections.emptyList() /*listBucketInfo*/);
285 LOG.info("removeSNATFromDPN : SNAT->Removing NAPT GroupEntity:{} on Dpn {}", groupEntity, dpnId);
286 mdsalManager.removeGroup(groupEntity);
287 } catch (Exception ex) {
288 LOG.error("removeSNATFromDPN : SNAT->Failed to remove group entity {}", groupEntity, ex);
291 LOG.debug("removeSNATFromDPN : SNAT->Removed default SNAT miss entry flow for dpnID {}, routerName {}",
294 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, routerId, dpnId,
295 externalIpLabel, writeFlowInvTx);
296 //remove table 26 flow ppointing to table46
297 FlowEntity flowEntity = null;
299 flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId,
300 NatConstants.DEL_FLOW);
301 if (flowEntity == null) {
302 LOG.error("removeSNATFromDPN : SNAT->Failed to populate flowentity for router {} with dpnId {}",
306 LOG.debug("removeSNATFromDPN : SNAT->Removing default SNAT miss entry flow entity for "
307 + "router {} with dpnId {} in napt switch {}", routerName, dpnId, naptSwitch);
308 mdsalManager.removeFlowToTx(flowEntity, writeFlowInvTx);
310 } catch (Exception ex) {
311 LOG.error("removeSNATFromDPN : SNAT->Failed to remove default SNAT miss entry flow entity {}",
315 LOG.debug("removeSNATFromDPN : SNAT->Removed default SNAT miss entry flow for dpnID {} "
316 + "with routername {}", dpnId, routerName);
318 //best effort to check IntExt model
319 naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel, writeFlowInvTx);
321 } catch (Exception ex) {
322 LOG.error("removeSNATFromDPN : SNAT->Exception while handling naptSwitch down for router {}",
327 // TODO Clean up the exception handling
328 @SuppressWarnings("checkstyle:IllegalCatch")
329 private void hndlTepEvntsForDpn(StateTunnelList stateTunnelList, TunnelAction tunnelAction) {
330 final BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
331 final String srcTepIp = String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue());
332 final String destTepIp = String.valueOf(stateTunnelList.getDstInfo().getTepIp().getValue());
333 LOG.trace("hndlTepEvntsForDpn : Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ",
334 srcDpnId, srcTepIp, destTepIp);
335 int tunTypeVal = getTunnelType(stateTunnelList);
336 LOG.trace("hndlTepEvntsForDpn : tunTypeVal is {}", tunTypeVal);
338 String srcTepId = stateTunnelList.getSrcInfo().getTepDeviceId();
339 String tunnelType = stateTunnelList.getTransportType().toString();
340 String tunnelName = stateTunnelList.getTunnelInterfaceName();
342 if (tunTypeVal == NatConstants.ITMTunnelLocType.Invalid.getValue()) {
343 LOG.warn("hndlTepEvntsForDpn : Ignoring TEP event {} for the DPN {} "
344 + "since its a INVALID TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and " + "TUNNEL NAME {} ",
345 tunnelAction, srcTepId, tunnelType, srcTepIp, destTepIp, tunnelName);
349 switch (tunnelAction) {
352 txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
353 if (isTunnelInLogicalGroup(stateTunnelList)
354 || !hndlTepAddForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp,
356 LOG.debug("hndlTepEvntsForDpn : Unable to process TEP ADD");
359 } catch (InterruptedException | ExecutionException e) {
360 LOG.error("Error processing tunnel endpoint addition", e);
363 case TUNNEL_EP_DELETE:
365 txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
366 if (!handleTepDelForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp, tx)) {
367 LOG.debug("hndlTepEvntsForDpn : Unable to process TEP DEL");
370 } catch (InterruptedException | ExecutionException e) {
371 LOG.error("Error processing tunnel endpoint removal", e);
374 case TUNNEL_EP_UPDATE:
377 LOG.warn("hndlTepEvntsForDpn: unknown tunnelAction: {}", tunnelAction);
380 } catch (Exception e) {
381 LOG.error("hndlTepEvntsForDpn : Unable to handle the TEP event.", e);
385 private boolean hndlTepAddForAllRtrs(BigInteger srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
386 String destTepIp, WriteTransaction writeFlowInvTx) {
387 LOG.trace("hndlTepAddForAllRtrs: TEP ADD ----- for EXTERNAL/HWVTEP ITM Tunnel, TYPE {} ,State is UP b/w SRC IP"
388 + " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
390 InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
391 Optional<DpnRoutersList> optionalRouterDpnList =
392 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
393 LogicalDatastoreType.OPERATIONAL, dpnRoutersListId);
394 if (!optionalRouterDpnList.isPresent()) {
395 LOG.info("hndlTepAddForAllRtrs : RouterDpnList model is empty for DPN {}. Hence ignoring TEP add event "
396 + "for the ITM TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ",
397 srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
401 List<RoutersList> routersList = optionalRouterDpnList.get().getRoutersList();
402 if (routersList == null) {
403 LOG.debug("hndlTepAddForAllRtrs : Ignoring TEP add for the DPN {} since no routers are associated"
404 + " for the DPN having the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
405 + "TUNNEL NAME {} ", srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
409 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
410 for (RoutersList router : routersList) {
411 String routerName = router.getRouter();
412 long routerId = NatUtil.getVpnId(dataBroker, routerName);
413 if (routerId == NatConstants.INVALID_ID) {
414 LOG.error("hndlTepAddForAllRtrs :Invalid ROUTER-ID {} returned for routerName {}",
415 routerId, routerName);
418 LOG.debug("hndlTepAddForAllRtrs : TEP ADD : DNAT -> Advertising routes for router {} ", routerName);
419 Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
420 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
421 routerName, externalNetworkId);
422 if (extNwProvType == null) {
425 hndlTepAddForDnatInEachRtr(router, routerId, nextHopIp, srcDpnId, extNwProvType, writeFlowInvTx);
427 LOG.debug("hndlTepAddForAllRtrs : TEP ADD : SNAT -> Advertising routes for router {} ", routerName);
428 hndlTepAddForSnatInEachRtr(router, routerId, srcDpnId, tunnelType, srcTepIp, destTepIp,
429 tunnelName, nextHopIp, extNwProvType, writeFlowInvTx);
434 // TODO Clean up the exception handling
435 @SuppressWarnings("checkstyle:IllegalCatch")
436 private boolean handleTepDelForAllRtrs(BigInteger srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
437 String destTepIp, WriteTransaction writeFlowInvTx) {
439 LOG.trace("handleTepDelForAllRtrs : TEP DEL ----- for EXTERNAL/HWVTEP ITM Tunnel,TYPE {},State is UP b/w SRC IP"
440 + " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
442 // When tunnel EP is deleted on a DPN , VPN gets two deletion event.
443 // One for a DPN on which tunnel EP was deleted and another for other-end DPN.
444 // Handle only the DPN on which it was deleted , ignore other event.
445 // DPN on which TEP is deleted , endpoint IP will be null.
446 String endpointIpForDPN = null;
448 endpointIpForDPN = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
449 } catch (Exception e) {
450 /* this dpn does not have the VTEP */
451 LOG.error("handleTepDelForAllRtrs : DPN {} does not have the VTEP", srcDpnId);
452 endpointIpForDPN = null;
455 if (endpointIpForDPN != null) {
456 LOG.trace("handleTepDelForAllRtrs : Ignore TEP DELETE event received for DPN {} VTEP IP {} since its "
457 + "the other end DPN w.r.t the delted TEP", srcDpnId, srcTepIp);
461 List<RoutersList> routersList = null;
462 InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
463 Optional<DpnRoutersList> optionalRouterDpnList =
464 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
465 LogicalDatastoreType.OPERATIONAL, dpnRoutersListId);
466 if (optionalRouterDpnList.isPresent()) {
467 routersList = optionalRouterDpnList.get().getRoutersList();
469 LOG.warn("handleTepDelForAllRtrs : RouterDpnList is empty for DPN {}.Hence ignoring TEP DEL event "
470 + "for the ITM TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ",
471 srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
475 if (routersList == null) {
476 LOG.error("handleTepDelForAllRtrs : DPN {} does not have the Routers presence", srcDpnId);
480 for (RoutersList router : routersList) {
481 String routerName = router.getRouter();
482 LOG.debug("handleTepDelForAllRtrs : TEP DEL : DNAT -> Withdrawing routes for router {} ", routerName);
483 long routerId = NatUtil.getVpnId(dataBroker, routerName);
484 if (routerId == NatConstants.INVALID_ID) {
485 LOG.error("handleTepDelForAllRtrs :Invalid ROUTER-ID {} returned for routerName {}",
486 routerId, routerName);
489 Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
490 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
491 routerName, externalNetworkId);
492 if (extNwProvType == null) {
495 hndlTepDelForDnatInEachRtr(router, routerId, srcDpnId, extNwProvType);
496 LOG.debug("handleTepDelForAllRtrs : TEP DEL : SNAT -> Withdrawing and Advertising routes for router {} ",
498 hndlTepDelForSnatInEachRtr(router, routerId, srcDpnId, tunnelType, srcTepIp, destTepIp,
499 tunnelName, extNwProvType, writeFlowInvTx);
504 private void hndlTepAddForSnatInEachRtr(RoutersList router, long routerId, final BigInteger srcDpnId,
505 String tunnelType, String srcTepIp, String destTepIp, String tunnelName, String nextHopIp,
506 ProviderTypes extNwProvType, WriteTransaction writeFlowInvTx) {
508 /*SNAT : Remove the old routes to the external IP having the old TEP IP as the next hop IP
509 Advertise to the BGP about the new route to the external IP having the new TEP IP
510 added as the next hop IP
512 String routerName = router.getRouter();
514 // Check if this is externalRouter else ignore
515 InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
516 Optional<Routers> routerData =
517 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
518 LogicalDatastoreType.CONFIGURATION, extRoutersId);
519 if (!routerData.isPresent()) {
520 LOG.warn("hndlTepAddForSnatInEachRtr : SNAT->Ignoring TEP add for router {} since its not External Router",
525 BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
526 if (naptId == null || naptId.equals(BigInteger.ZERO)) {
527 LOG.warn("hndlTepAddForSnatInEachRtr : SNAT -> Ignoring TEP add for the DPN {} having the router {} since"
528 + " the router is not part of the NAT service - the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
529 + "TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
532 if (natMode == NatMode.Conntrack) {
533 natServiceManager.notify(routerData.get(), naptId, srcDpnId,
534 SnatServiceManager.Action.SNAT_ROUTER_ENBL);
536 Uuid bgpVpnUuId = NatUtil.getVpnForRouter(dataBroker, routerName);
537 //Check if the DPN having the router is the NAPT switch
538 if (!naptId.equals(srcDpnId)) {
540 1) Install default NAT rule from table 21 to 26
541 2) Install the group which forward packet to the tunnel port for the NAPT switch.
542 3) Install the flow 26 which forwards the packet to the group.
544 if (!hndlTepAddOnNonNaptSwitch(srcDpnId, naptId, tunnelType, srcTepIp, destTepIp, tunnelName,
545 routerName, routerId, bgpVpnUuId, writeFlowInvTx)) {
546 LOG.error("hndlTepAddForSnatInEachRtr : Unable to process the TEP add event on NON-NAPT switch {}",
552 if (!hndlTepAddOnNaptSwitch(srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName, routerId,
553 routerData, nextHopIp, bgpVpnUuId, extNwProvType, writeFlowInvTx)) {
554 LOG.debug("hndlTepAddForSnatInEachRtr : Unable to process the TEP add event on NAPT switch {}",
562 private boolean hndlTepAddOnNonNaptSwitch(BigInteger srcDpnId, BigInteger primaryDpnId, String tunnelType,
563 String srcTepIp, String destTepIp, String tunnelName, String routerName,
564 long routerId, Uuid vpnName, WriteTransaction writeFlowInvTx) {
567 1) Install default NAT rule from table 21 to 26
568 2) Install the group which forward packet to the tunnel port for the NAPT switch.
569 3) Install the flow 26 which forwards the packet to the group.
571 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Processing TEP add for the DPN {} having the router {} since "
572 + "its THE NON NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
573 + "and TUNNEL NAME {} ",
574 srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
575 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Install default NAT rule from table 21 to 26");
577 if (vpnName == null) {
578 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Internal VPN associated to router {}", routerId);
580 if (vpnId == NatConstants.INVALID_ID) {
581 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid Internal VPN ID returned for routerName {}",
585 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerName);
586 //Install default entry in FIB to SNAT table
587 LOG.debug("hndlTepAddOnNonNaptSwitch : Installing default route in FIB on DPN {} for router {} with"
588 + " vpn {}...", srcDpnId, routerName, vpnId);
589 defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, writeFlowInvTx);
591 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Install the group which forward packet to the tunnel port "
592 + "for the NAPT switch {} and the flow 26 which forwards to group", primaryDpnId);
593 externalRouterListner.handleSwitches(srcDpnId, routerName, routerId, primaryDpnId);
595 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> External BGP VPN (Private BGP) associated to router {}",
597 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
598 if (vpnId == NatConstants.INVALID_ID) {
599 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid Private BGP VPN ID returned for routerName {}",
603 if (routerId == NatConstants.INVALID_ID) {
604 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid routId returned for routerName {}", routerId);
607 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
608 //Install default entry in FIB to SNAT table
609 LOG.debug("hndlTepAddOnNonNaptSwitch : Installing default route in FIB on dpn {} for routerId {} "
610 + "with vpnId {}...", srcDpnId, routerId, vpnId);
611 defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, routerId, writeFlowInvTx);
613 LOG.debug("hndlTepAddOnNonNaptSwitch : Install group in non NAPT switch {} for router {}",
614 srcDpnId, routerName);
615 List<BucketInfo> bucketInfoForNonNaptSwitches =
616 externalRouterListner.getBucketInfoForNonNaptSwitches(srcDpnId, primaryDpnId, routerName, routerId);
617 long groupId = externalRouterListner.installGroup(srcDpnId, routerName, bucketInfoForNonNaptSwitches);
619 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> in the SNAT miss entry pointing to group {} "
620 + "in the non NAPT switch {}", groupId, srcDpnId);
621 FlowEntity flowEntity =
622 externalRouterListner.buildSnatFlowEntityWithUpdatedVpnId(srcDpnId, routerName, groupId, vpnId);
623 mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
628 private boolean hndlTepAddOnNaptSwitch(BigInteger srcDpnId, String tunnelType, String srcTepIp,
629 String destTepIp, String tunnelName, long routerId,
630 Optional<Routers> routerData, String nextHopIp, Uuid vpnName,
631 ProviderTypes extNwProvType, WriteTransaction writeFlowInvTx) {
632 if (!routerData.isPresent()) {
633 LOG.warn("hndlTepAddOnNaptSwitch: routerData is not present");
636 Routers router = routerData.get();
637 String routerName = router.getRouterName();
638 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Processing TEP add for the DPN {} having the router {} since "
639 + "its THE NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
640 + "and TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
642 Uuid networkId = router.getNetworkId();
643 if (networkId == null) {
644 LOG.warn("hndlTepAddOnNaptSwitch : SNAT -> Ignoring TEP add since the router {} is not associated to the "
645 + "external network", routerName);
649 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Router {} is associated with Ext nw {}", routerId, networkId);
651 if (vpnName == null) {
652 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Internal VPN associated to router {}", routerId);
653 vpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
654 if (vpnId == NatConstants.INVALID_ID) {
655 LOG.error("hndlTepAddOnNaptSwitch : Invalid External VPN-ID returned for routerName {}", routerName);
658 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Retrieved External VPN-ID {} for router {}", vpnId, routerId);
660 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Private BGP VPN associated to router {}", routerId);
661 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
662 if (vpnId == null || vpnId == NatConstants.INVALID_ID) {
663 LOG.error("hndlTepAddOnNaptSwitch : Invalid vpnId returned for routerName {}", routerName);
666 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
669 /*1) Withdraw the old route to the external IP from the BGP which was having the
670 next hop as the old TEP IP.
671 2) Advertise to the BGP about the new route to the external IP having the
672 new TEP IP as the next hop.
673 3) Populate a new FIB entry with the next hop IP as the new TEP IP using the
677 //Withdraw the old route to the external IP from the BGP which was having the
678 //next hop as the old TEP IP.
679 final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
680 if (externalVpnName == null) {
681 LOG.error("hndlTepAddOnNaptSwitch : SNAT -> No VPN associated with ext nw {} in router {}",
682 networkId, routerId);
685 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
686 LOG.debug("hndlTepAddOnNaptSwitch : Clearing the FIB entries but not the BGP routes");
687 for (String externalIp : externalIps) {
688 String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
689 LOG.debug("hndlTepAddOnNaptSwitch : Removing Fib entry rd {} prefix {}", rd, externalIp);
690 fibManager.removeFibEntry(rd, externalIp, null);
694 Advertise to the BGP about the new route to the external IP having the
695 new TEP IP as the next hop.
696 Populate a new FIB entry with the next hop IP as the new TEP IP using the
699 String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
700 if (extNwProvType == null) {
703 String gwMacAddress = null;
705 if (extNwProvType == ProviderTypes.VXLAN) {
706 // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
707 gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
708 if (gwMacAddress != null) {
709 LOG.debug("hndlTepAddOnNaptSwitch : External Gateway MAC address {} found for External Router ID {}",
710 gwMacAddress, routerId);
712 LOG.error("hndlTepAddOnNaptSwitch : No External Gateway MAC address found for External Router ID {}",
716 //get l3Vni value for external VPN
717 l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
718 if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
719 LOG.debug("hndlTepAddOnNaptSwitch : L3VNI value is not configured in Internet VPN {} and RD {} "
720 + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
721 + "NAT flows", vpnName, rd);
722 l3Vni = NatOverVxlanUtil.getInternetVpnVni(idManager, externalVpnName, routerId).longValue();
726 for (final String externalIp : externalIps) {
728 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
729 if (extNwProvType == ProviderTypes.VXLAN) {
730 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Advertise the route to the externalIp {} "
731 + "having nextHopIp {}", externalIp, nextHopIp);
732 NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, externalVpnName, rd,
733 externalIp, nextHopIp, l3Vni, tunnelName, gwMacAddress, writeFlowInvTx, RouteOrigin.STATIC,
738 Long label = externalRouterListner.checkExternalIpLabel(routerId,
740 if (label == null || label == NatConstants.INVALID_ID) {
741 LOG.error("hndlTepAddOnNaptSwitch : SNAT->Unable to advertise to the DC GW "
742 + "since label is invalid");
745 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Advertise the route to the externalIp {} "
746 + "having nextHopIp {}", externalIp, nextHopIp);
748 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
749 l3vni = NatOverVxlanUtil.getInternetVpnVni(idManager, externalVpnName, l3vni).longValue();
751 Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(externalIp, router);
752 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, externalVpnName, rd, externalSubnetId,
753 fibExternalIp, nextHopIp, networkId.getValue(), null /* mac-address */, label, l3vni,
754 RouteOrigin.STATIC, srcDpnId);
758 LOG.debug("hndlTepAddOnNaptSwitch: SNAT -> Install custom FIB routes "
759 + "(Table 21 -> Push MPLS label to Tunnel port");
760 List<Instruction> customInstructions = new ArrayList<>();
761 int customInstructionIndex = 0;
762 long externalSubnetVpnId = NatUtil.getExternalSubnetVpnIdForRouterExternalIp(dataBroker, externalIp,
764 if (externalSubnetVpnId != NatConstants.INVALID_ID) {
765 LOG.debug("hndlTepAddOnNaptSwitch : Will install custom FIB router with external subnet VPN ID {}",
766 externalSubnetVpnId);
767 BigInteger subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(externalSubnetVpnId);
768 customInstructions.add(new InstructionWriteMetadata(subnetIdMetaData,
769 MetaDataUtil.METADATA_MASK_VRFID).buildInstruction(customInstructionIndex));
770 customInstructionIndex++;
772 customInstructions.add(new InstructionGotoTable(NwConstants.INBOUND_NAPT_TABLE)
773 .buildInstruction(customInstructionIndex));
774 CreateFibEntryInput input =
775 new CreateFibEntryInputBuilder().setVpnName(externalVpnName).setSourceDpid(srcDpnId)
776 .setInstruction(customInstructions).setIpAddress(fibExternalIp)
777 .setServiceId(serviceId).setInstruction(customInstructions).build();
778 ListenableFuture<RpcResult<CreateFibEntryOutput>> listenableFuture = fibRpcService.createFibEntry(input);
780 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
783 public void onFailure(@Nonnull Throwable error) {
784 LOG.error("hndlTepAddOnNaptSwitch : SNAT->Error in generate label or fib install process",
789 public void onSuccess(@Nonnull RpcResult<CreateFibEntryOutput> result) {
790 if (result.isSuccessful()) {
791 LOG.info("hndlTepAddOnNaptSwitch : SNAT -> Successfully installed custom FIB routes "
792 + "for prefix {}", externalIp);
794 LOG.error("hndlTepAddOnNaptSwitch : SNAT -> Error in rpc call to create custom Fib entries "
795 + "for prefix {} in DPN {}, {}", externalIp, srcDpnId, result.getErrors());
798 }, MoreExecutors.directExecutor());
804 private void hndlTepAddForDnatInEachRtr(RoutersList router, long routerId, String nextHopIp,
805 BigInteger tepAddedDpnId, ProviderTypes extNwProvType, WriteTransaction writeFlowInvTx) {
806 //DNAT : Advertise the new route to the floating IP having the new TEP IP as the next hop IP
807 final String routerName = router.getRouter();
809 InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
810 Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType
811 .CONFIGURATION, routerPortsId);
812 if (!optRouterPorts.isPresent()) {
813 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Could not read Router Ports data object with id: {} "
814 + "from DNAT FloatinIpInfo", routerName);
817 RouterPorts routerPorts = optRouterPorts.get();
818 Uuid extNwId = routerPorts.getExternalNetworkId();
819 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId);
820 if (vpnName == null) {
821 LOG.info("hndlTepAddForDnatInEachRtr : DNAT -> No External VPN associated with ext nw {} for router {}",
822 extNwId, routerName);
826 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
827 if (extNwProvType == null) {
830 String gwMacAddress = null;
832 if (extNwProvType == ProviderTypes.VXLAN) {
833 // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
834 gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
835 if (gwMacAddress != null) {
836 LOG.debug("hndlTepAddForDnatInEachRtr : External GwMAC address {} found for External Router ID {}",
837 gwMacAddress, routerId);
839 LOG.error("hndlTepAddForDnatInEachRtr : No External GwMAC address found for External Router ID {}",
843 //get l3Vni value for external VPN
844 l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
845 if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
846 LOG.debug("hndlTepAddForDnatInEachRtr : L3VNI value is not configured in Internet VPN {} and RD {} "
847 + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
848 + "NAT flows", vpnName, rd);
849 l3Vni = NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, routerId).longValue();
852 List<Ports> interfaces = routerPorts.getPorts();
853 for (Ports port : interfaces) {
854 //Get the DPN on which this interface resides
855 final String interfaceName = port.getPortName();
856 final BigInteger fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
857 if (fipCfgdDpnId.equals(BigInteger.ZERO)) {
858 LOG.info("hndlTepAddForDnatInEachRtr : DNAT->Skip processing Floating ip configuration for the port {},"
859 + "since no DPN present for it", interfaceName);
862 if (!fipCfgdDpnId.equals(tepAddedDpnId)) {
863 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> TEP added DPN {} is not the DPN {} which has the "
864 + "floating IP configured for the port: {}",
865 tepAddedDpnId, fipCfgdDpnId, interfaceName);
868 List<InternalToExternalPortMap> intExtPortMapList = port.getInternalToExternalPortMap();
869 for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) {
870 final String internalIp = intExtPortMap.getInternalIp();
871 final String externalIp = intExtPortMap.getExternalIp();
872 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertising the FIB route to the floating IP {} "
873 + "configured for the port: {}", externalIp, interfaceName);
875 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
877 if (extNwProvType == ProviderTypes.VXLAN) {
878 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertise the route to the externalIp {} "
879 + "having nextHopIp {}", externalIp, nextHopIp);
880 NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, vpnName, rd,
881 externalIp, nextHopIp, l3Vni, interfaceName, gwMacAddress, writeFlowInvTx,
882 RouteOrigin.STATIC, fipCfgdDpnId);
885 long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
886 if (label == NatConstants.INVALID_ID) {
887 LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Unable to advertise to the DC GW since label "
891 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertise the route to the externalIp {} "
892 + "having nextHopIp {}", externalIp, nextHopIp);
894 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
895 l3vni = NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, l3vni).longValue();
897 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd, null,
898 fibExternalIp, nextHopIp, null, null, label, l3vni, RouteOrigin.STATIC,
903 //Install custom FIB routes (Table 21 -> Push MPLS label to Tunnel port
904 List<Instruction> customInstructions = new ArrayList<>();
905 customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(0));
906 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
907 .setSourceDpid(fipCfgdDpnId).setInstruction(customInstructions)
908 .setIpAddress(fibExternalIp).setServiceId(serviceId).setInstruction(customInstructions)
910 ListenableFuture<RpcResult<CreateFibEntryOutput>> listenableFuture =
911 fibRpcService.createFibEntry(input);
913 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
916 public void onFailure(@Nonnull Throwable error) {
917 LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Error in generate label or fib install process",
922 public void onSuccess(@Nonnull RpcResult<CreateFibEntryOutput> result) {
923 if (result.isSuccessful()) {
924 LOG.info("hndlTepAddForDnatInEachRtr : DNAT -> Successfully installed custom FIB routes "
925 + "for prefix {}", externalIp);
927 LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Error in rpc call to create custom Fib "
928 + "entries for prefix {} in DPN {}, {}", externalIp, fipCfgdDpnId, result.getErrors());
931 }, MoreExecutors.directExecutor());
936 private void hndlTepDelForSnatInEachRtr(RoutersList router, long routerId, BigInteger dpnId, String tunnelType,
937 String srcTepIp, String destTepIp, String tunnelName,
938 ProviderTypes extNwProvType, WriteTransaction writeFlowInvTx) {
940 1) Elect a new switch as the primary NAPT
941 2) Advertise the new routes to BGP for the newly elected TEP IP as the DPN IP
942 3) This will make sure old routes are withdrawn and new routes are advertised.
945 String routerName = router.getRouter();
946 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Trying to clear routes to the External fixed IP associated "
947 + "to the router {}", routerName);
949 // Check if this is externalRouter else ignore
950 InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
951 Optional<Routers> routerData =
952 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
953 LogicalDatastoreType.CONFIGURATION, extRoutersId);
954 if (!routerData.isPresent()) {
955 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Ignoring TEP del for router {} since its not External Router",
960 //Check if the DPN having the router is the NAPT switch
961 BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
962 if (naptId == null || naptId.equals(BigInteger.ZERO) || !naptId.equals(dpnId)) {
963 LOG.warn("hndlTepDelForSnatInEachRtr : SNAT -> Ignoring TEP delete for the DPN {} since"
964 + " its NOT a NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
965 + "TUNNEL NAME {} ", dpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
968 if (natMode == NatMode.Conntrack) {
969 natServiceManager.notify(routerData.get(), naptId, dpnId, SnatServiceManager.Action.SNAT_ROUTER_DISBL);
973 Uuid networkId = routerData.get().getNetworkId();
974 if (networkId == null) {
975 LOG.error("hndlTepDelForSnatInEachRtr : SNAT->Ignoring TEP delete for the DPN {} having the router {} "
976 + "since the Router instance {} not found in ExtRouters model b/w SRC IP {} and DST "
977 + "IP {} and TUNNEL NAME {} ", dpnId, routerData.get().getRouterName(), tunnelType,
978 srcTepIp, destTepIp, tunnelName);
982 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Router {} is associated with ext nw {}", routerId, networkId);
983 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
985 if (bgpVpnUuid == null) {
986 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Internal VPN-ID {} associated to router {}",
987 routerId, routerName);
990 //Install default entry in FIB to SNAT table
991 LOG.debug("hndlTepDelForSnatInEachRtr : Installing default route in FIB on DPN {} for router {} with"
992 + " vpn {}...", dpnId, routerName, bgpVpnId);
993 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, writeFlowInvTx);
995 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
996 if (bgpVpnId == NatConstants.INVALID_ID) {
997 LOG.error("hndlTepDelForSnatInEachRtr :SNAT->Invalid Private BGP VPN ID returned for routerName {}",
1001 LOG.debug("hndlTepDelForSnatInEachRtr :SNAT->External BGP VPN (Private BGP) {} associated to router {}",
1002 bgpVpnId, routerName);
1003 //Install default entry in FIB to SNAT table
1004 LOG.debug("hndlTepDelForSnatInEachRtr : Installing default route in FIB on dpn {} for routerId {} "
1005 + "with vpnId {}...", dpnId, routerId, bgpVpnId);
1006 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, routerId, writeFlowInvTx);
1009 if (routerData.get().isEnableSnat()) {
1010 LOG.info("hndlTepDelForSnatInEachRtr : SNAT enabled for router {}", routerId);
1012 long routerVpnId = routerId;
1013 if (bgpVpnId != NatConstants.INVALID_ID) {
1014 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Private BGP VPN ID (Internal BGP VPN ID) {} "
1015 + "associated to the router {}", bgpVpnId, routerName);
1016 routerVpnId = bgpVpnId;
1018 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Internal L3 VPN ID (Router ID) {} "
1019 + "associated to the router {}", routerVpnId, routerName);
1021 //Re-elect the other available switch as the NAPT switch and program the NAT flows.
1022 removeSNATFromDPN(dpnId, routerName, routerId, routerVpnId, networkId, extNwProvType, writeFlowInvTx);
1024 LOG.info("hndlTepDelForSnatInEachRtr : SNAT is not enabled for router {} to handle addDPN event {}",
1030 private void hndlTepDelForDnatInEachRtr(RoutersList router, long routerId, BigInteger tepDeletedDpnId,
1031 ProviderTypes extNwProvType) {
1032 //DNAT : Withdraw the routes from the BGP
1033 String routerName = router.getRouter();
1035 LOG.debug("hndlTepDelForDnatInEachRtr : DNAT -> Trying to clear routes to the Floating IP "
1036 + "associated to the router {}", routerName);
1038 InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
1039 Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType
1040 .CONFIGURATION, routerPortsId);
1041 if (!optRouterPorts.isPresent()) {
1042 LOG.debug("hndlTepDelForDnatInEachRtr : DNAT -> Could not read Router Ports data object with id: {} "
1043 + "from DNAT FloatingIpInfo", routerName);
1046 RouterPorts routerPorts = optRouterPorts.get();
1047 Uuid extNwId = routerPorts.getExternalNetworkId();
1048 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId);
1049 if (vpnName == null) {
1050 LOG.error("hndlTepDelForDnatInEachRtr : DNAT -> No External VPN associated with Ext N/W {} for Router {}",
1051 extNwId, routerName);
1054 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
1055 if (extNwProvType == null) {
1059 if (extNwProvType == ProviderTypes.VXLAN) {
1060 //get l3Vni value for external VPN
1061 l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
1062 if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
1063 LOG.debug("hndlTepDelForDnatInEachRtr : L3VNI value is not configured in Internet VPN {} and RD {} "
1064 + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
1065 + "NAT flows", vpnName, rd);
1066 l3Vni = NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, routerId).longValue();
1069 List<Ports> interfaces = routerPorts.getPorts();
1070 for (Ports port : interfaces) {
1071 //Get the DPN on which this interface resides
1072 String interfaceName = port.getPortName();
1073 BigInteger fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
1074 if (fipCfgdDpnId.equals(BigInteger.ZERO)) {
1075 LOG.info("hndlTepDelForDnatInEachRtr : DNAT -> Abort processing Floating ip configuration. "
1076 + "No DPN for port : {}", interfaceName);
1079 if (!fipCfgdDpnId.equals(tepDeletedDpnId)) {
1080 LOG.info("hndlTepDelForDnatInEachRtr : DNAT -> TEP deleted DPN {} is not the DPN {} which has the "
1081 + "floating IP configured for the port: {}",
1082 tepDeletedDpnId, fipCfgdDpnId, interfaceName);
1085 List<InternalToExternalPortMap> intExtPortMapList = port.getInternalToExternalPortMap();
1086 for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) {
1087 String internalIp = intExtPortMap.getInternalIp();
1088 String externalIp = intExtPortMap.getExternalIp();
1089 externalIp = NatUtil.validateAndAddNetworkMask(externalIp);
1090 LOG.debug("hndlTepDelForDnatInEachRtr : DNAT -> Withdrawing the FIB route to the floating IP {} "
1091 + "configured for the port: {}",
1092 externalIp, interfaceName);
1093 NatUtil.removePrefixFromBGP(bgpManager, fibManager, rd, externalIp, vpnName, LOG);
1095 if (extNwProvType == ProviderTypes.VXLAN) {
1098 long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
1099 if (label == NatConstants.INVALID_ID) {
1100 LOG.error("hndlTepDelForDnatInEachRtr : DNAT -> Unable to remove the table 21 entry pushing the"
1101 + " MPLS label to the tunnel since label is invalid");
1107 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
1108 .setSourceDpid(fipCfgdDpnId).setIpAddress(externalIp).setServiceId(serviceId)
1109 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.FloatingIP).build();
1110 ListenableFuture<RpcResult<RemoveFibEntryOutput>> listenableFuture =
1111 fibRpcService.removeFibEntry(input);
1113 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<RemoveFibEntryOutput>>() {
1116 public void onFailure(@Nonnull Throwable error) {
1117 LOG.error("hndlTepDelForDnatInEachRtr : DNAT -> Error in removing the table 21 entry pushing "
1118 + "the MPLS label to the tunnel since label is invalid ", error);
1122 public void onSuccess(@Nonnull RpcResult<RemoveFibEntryOutput> result) {
1123 if (result.isSuccessful()) {
1124 LOG.info("hndlTepDelForDnatInEachRtr : DNAT -> Successfully removed the entry pushing the "
1125 + "MPLS label to the tunnel");
1127 LOG.error("hndlTepDelForDnatInEachRtr : DNAT -> Error in fib rpc call to remove the table "
1128 + "21 entry pushing the MPLS label to the tunnnel due to {}", result.getErrors());
1131 }, MoreExecutors.directExecutor());
1136 protected boolean isTunnelInLogicalGroup(StateTunnelList stateTunnelList) {
1137 String ifaceName = stateTunnelList.getTunnelInterfaceName();
1138 if (getTunnelType(stateTunnelList) == NatConstants.ITMTunnelLocType.Internal.getValue()) {
1139 Interface configIface = interfaceManager.getInterfaceInfoFromConfigDataStore(ifaceName);
1140 IfTunnel ifTunnel = configIface != null ? configIface.augmentation(IfTunnel.class) : null;
1141 if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) {
1142 ParentRefs refs = configIface.augmentation(ParentRefs.class);
1143 if (refs != null && !Strings.isNullOrEmpty(refs.getParentInterface())) {
1144 return true; //multiple VxLAN tunnels enabled, i.e. only logical tunnel should be treated
1148 LOG.trace("isTunnelInLogicalGroup: ignoring the tunnel event for {}", ifaceName);