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 static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
12 import static org.opendaylight.netvirt.natservice.internal.NatUtil.requireNonNullElse;
14 import com.google.common.base.Optional;
15 import com.google.common.base.Strings;
16 import com.google.common.util.concurrent.FutureCallback;
17 import com.google.common.util.concurrent.Futures;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import com.google.common.util.concurrent.MoreExecutors;
20 import java.math.BigInteger;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.List;
26 import java.util.concurrent.ExecutionException;
27 import javax.annotation.Nonnull;
28 import javax.annotation.PostConstruct;
29 import javax.inject.Inject;
30 import javax.inject.Singleton;
31 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
32 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
33 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
34 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
35 import org.opendaylight.genius.infra.Datastore.Configuration;
36 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
37 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
38 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
39 import org.opendaylight.genius.infra.TypedWriteTransaction;
40 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
41 import org.opendaylight.genius.mdsalutil.BucketInfo;
42 import org.opendaylight.genius.mdsalutil.FlowEntity;
43 import org.opendaylight.genius.mdsalutil.MDSALUtil;
44 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
45 import org.opendaylight.genius.mdsalutil.NwConstants;
46 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
47 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
48 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
49 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
50 import org.opendaylight.netvirt.elanmanager.api.IElanService;
51 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
52 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
53 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryOutput;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibEntryInputs;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryOutput;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersList;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.dpn.routers.list.RoutersList;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
84 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
85 import org.opendaylight.yangtools.yang.common.RpcResult;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
90 public class NatTunnelInterfaceStateListener
91 extends AsyncDataTreeChangeListenerBase<StateTunnelList, NatTunnelInterfaceStateListener> {
93 private static final Logger LOG = LoggerFactory.getLogger(NatTunnelInterfaceStateListener.class);
94 private final DataBroker dataBroker;
95 private final ManagedNewTransactionRunner txRunner;
96 private final IFibManager fibManager;
97 private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
98 private final NaptSwitchHA naptSwitchHA;
99 private final IMdsalApiManager mdsalManager;
100 private final IdManagerService idManager;
101 private final IBgpManager bgpManager;
102 private final ExternalRoutersListener externalRouterListner;
103 private final SnatServiceManager natServiceManager;
104 private final OdlInterfaceRpcService interfaceService;
105 private final FloatingIPListener floatingIPListener;
106 private final FibRpcService fibRpcService;
107 private final IElanService elanManager;
108 private final IInterfaceManager interfaceManager;
109 private final NatOverVxlanUtil natOverVxlanUtil;
110 private final NatMode natMode;
112 protected enum TunnelAction {
119 * Responsible for listening to tunnel interface state change.
121 * @param dataBroker - dataBroker service reference
122 * @param bgpManager Used to advertise routes to the BGP Router
123 * @param fibManager - FIB Manager
124 * @param defaultRouteProgrammer - Default Route Programmer
125 * @param naptSwitchHA - NAPT Switch HA
126 * @param mdsalManager - MDSAL Manager
127 * @param idManager - ID manager
128 * @param externalRouterListner - External Router Listener
129 * @param natServiceManager - Nat Service Manager
130 * @param interfaceService - Interface Service
131 * @param floatingIPListener - Floating IP Listener
132 * @param fibRpcService - FIB RPC Service
133 * @param config - Nat Service Config
134 * @param elanManager - Elan Manager
135 * @param interfaceManager - Interface Manager
136 * @param natOverVxlanUtils - Nat Over Vxlan Utility
139 public NatTunnelInterfaceStateListener(final DataBroker dataBroker,
140 final IBgpManager bgpManager,
141 final IFibManager fibManager,
142 final SNATDefaultRouteProgrammer defaultRouteProgrammer,
143 final NaptSwitchHA naptSwitchHA,
144 final IMdsalApiManager mdsalManager,
145 final IdManagerService idManager,
146 final ExternalRoutersListener externalRouterListner,
147 final SnatServiceManager natServiceManager,
148 final OdlInterfaceRpcService interfaceService,
149 final FloatingIPListener floatingIPListener,
150 final FibRpcService fibRpcService,
151 final NatserviceConfig config,
152 final IElanService elanManager,
153 final IInterfaceManager interfaceManager,
154 final NatOverVxlanUtil natOverVxlanUtils) {
155 super(StateTunnelList.class, NatTunnelInterfaceStateListener.class);
156 this.dataBroker = dataBroker;
157 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
158 this.bgpManager = bgpManager;
159 this.fibManager = fibManager;
160 this.defaultRouteProgrammer = defaultRouteProgrammer;
161 this.naptSwitchHA = naptSwitchHA;
162 this.mdsalManager = mdsalManager;
163 this.idManager = idManager;
164 this.externalRouterListner = externalRouterListner;
165 this.natServiceManager = natServiceManager;
166 this.interfaceService = interfaceService;
167 this.floatingIPListener = floatingIPListener;
168 this.fibRpcService = fibRpcService;
169 this.elanManager = elanManager;
170 this.interfaceManager = interfaceManager;
171 this.natOverVxlanUtil = natOverVxlanUtils;
172 if (config != null) {
173 this.natMode = config.getNatMode();
175 this.natMode = NatMode.Controller;
182 LOG.info("{} init", getClass().getSimpleName());
183 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
187 protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
188 return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
192 protected NatTunnelInterfaceStateListener getDataTreeChangeListener() {
193 return NatTunnelInterfaceStateListener.this;
197 protected void add(InstanceIdentifier<StateTunnelList> instanceIdentifier, StateTunnelList add) {
198 LOG.trace("add : TEP addtion---- {}", add);
199 hndlTepEvntsForDpn(add, TunnelAction.TUNNEL_EP_ADD);
203 protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
204 LOG.trace("remove : TEP deletion---- {}", del);
205 hndlTepEvntsForDpn(del, TunnelAction.TUNNEL_EP_DELETE);
209 protected void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original,
210 StateTunnelList update) {
211 LOG.trace("update : Tunnel updation---- {}", update);
212 //UPDATE IS A SEQUENCE OF DELETE AND ADD EVENTS . DELETE MIGHT HAVE CHANGED THE PRIMARY AND ADVERTISED. SO
216 private int getTunnelType(StateTunnelList stateTunnelList) {
218 if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
219 tunTypeVal = NatConstants.ITMTunnelLocType.Internal.getValue();
220 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
221 tunTypeVal = NatConstants.ITMTunnelLocType.External.getValue();
222 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
223 tunTypeVal = NatConstants.ITMTunnelLocType.Hwvtep.getValue();
225 tunTypeVal = NatConstants.ITMTunnelLocType.Invalid.getValue();
230 // TODO Clean up the exception handling
231 @SuppressWarnings("checkstyle:IllegalCatch")
232 void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerId, long routerVpnId,
233 Uuid networkId, ProviderTypes extNwProvType, TypedReadWriteTransaction<Configuration> confTx) {
234 //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
235 //remove miss entry to NAPT switch
236 //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
238 if (routerId == NatConstants.INVALID_ID) {
239 LOG.error("removeSNATFromDPN : SNAT -> Invalid routerId returned for routerName {}", routerName);
242 Collection<String> externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
243 if (extNwProvType == null) {
246 Map<String, Long> externalIpLabel;
247 if (extNwProvType == ProviderTypes.VXLAN) {
248 externalIpLabel = null;
250 externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
253 final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
254 if (externalVpnName == null) {
255 LOG.error("removeSNATFromDPN : SNAT -> No VPN associated with ext nw {} in router {}",
256 networkId, routerId);
260 BigInteger naptSwitch = dpnId;
262 naptSwitchHA.isNaptSwitchDown(routerName, routerId, dpnId, naptSwitch,
263 routerVpnId, externalIpCache, false, confTx);
265 LOG.debug("removeSNATFromDPN:SNAT->NaptSwitchDown:Switch with DpnId {} is not naptSwitch for router {}",
267 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
268 FlowEntity flowEntity = null;
270 flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId,
271 routerVpnId, NatConstants.DEL_FLOW);
272 if (flowEntity == null) {
273 LOG.error("removeSNATFromDPN : SNAT -> Failed to populate flowentity for "
274 + "router {} with dpnId {} groupIs {}", routerName, dpnId, groupId);
277 LOG.debug("removeSNATFromDPN : SNAT->Removing default SNAT miss entry flow entity {}", flowEntity);
278 mdsalManager.removeFlow(confTx, flowEntity);
280 } catch (Exception ex) {
281 LOG.error("removeSNATFromDPN : SNAT->Failed to remove default SNAT miss entry flow entity {}",
285 LOG.debug("removeSNATFromDPN:SNAT->Removed default SNAT miss entry flow for dpnID {}, routername {}",
290 LOG.info("removeSNATFromDPN : SNAT->Removing NAPT Group :{} on Dpn {}", groupId, dpnId);
291 mdsalManager.removeGroup(confTx, dpnId, groupId);
292 } catch (Exception ex) {
293 LOG.error("removeSNATFromDPN : SNAT->Failed to remove group {}", groupId, ex);
296 LOG.debug("removeSNATFromDPN : SNAT->Removed default SNAT miss entry flow for dpnID {}, routerName {}",
299 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, routerId, dpnId, externalIpLabel, confTx);
300 //remove table 26 flow ppointing to table46
301 FlowEntity flowEntity = null;
303 flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId,
304 NatConstants.DEL_FLOW);
305 if (flowEntity == null) {
306 LOG.error("removeSNATFromDPN : SNAT->Failed to populate flowentity for router {} with dpnId {}",
310 LOG.debug("removeSNATFromDPN : SNAT->Removing default SNAT miss entry flow entity for "
311 + "router {} with dpnId {} in napt switch {}", routerName, dpnId, naptSwitch);
312 mdsalManager.removeFlow(confTx, flowEntity);
314 } catch (Exception ex) {
315 LOG.error("removeSNATFromDPN : SNAT->Failed to remove default SNAT miss entry flow entity {}",
319 LOG.debug("removeSNATFromDPN : SNAT->Removed default SNAT miss entry flow for dpnID {} "
320 + "with routername {}", dpnId, routerName);
322 //best effort to check IntExt model
323 naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel, confTx);
325 } catch (InterruptedException | ExecutionException e) {
326 LOG.error("removeSNATFromDPN : SNAT->Exception while handling naptSwitch down for router {}",
331 private void hndlTepEvntsForDpn(StateTunnelList stateTunnelList, TunnelAction tunnelAction) {
332 final BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
333 final String srcTepIp = stateTunnelList.getSrcInfo().getTepIp().stringValue();
334 final String destTepIp = stateTunnelList.getDstInfo().getTepIp().stringValue();
335 LOG.trace("hndlTepEvntsForDpn : Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ",
336 srcDpnId, srcTepIp, destTepIp);
337 int tunTypeVal = getTunnelType(stateTunnelList);
338 LOG.trace("hndlTepEvntsForDpn : tunTypeVal is {}", tunTypeVal);
339 String srcTepId = stateTunnelList.getSrcInfo().getTepDeviceId();
340 String tunnelType = stateTunnelList.getTransportType().toString();
341 String tunnelName = stateTunnelList.getTunnelInterfaceName();
343 if (tunTypeVal == NatConstants.ITMTunnelLocType.Invalid.getValue()) {
344 LOG.warn("hndlTepEvntsForDpn : Ignoring TEP event {} for the DPN {} "
345 + "since its a INVALID TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and " + "TUNNEL NAME {} ",
346 tunnelAction, srcTepId, tunnelType, srcTepIp, destTepIp, tunnelName);
350 switch (tunnelAction) {
353 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
354 if (isTunnelInLogicalGroup(stateTunnelList)
355 || !hndlTepAddForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp,
357 LOG.debug("hndlTepEvntsForDpn : Unable to process TEP ADD");
360 } catch (InterruptedException | ExecutionException e) {
361 LOG.error("Error processing tunnel endpoint addition", e);
364 case TUNNEL_EP_DELETE:
366 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
367 if (!handleTepDelForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp, tx)) {
368 LOG.debug("hndlTepEvntsForDpn : Unable to process TEP DEL");
371 } catch (InterruptedException | ExecutionException e) {
372 LOG.error("Error processing tunnel endpoint removal", e);
375 case TUNNEL_EP_UPDATE:
378 LOG.warn("hndlTepEvntsForDpn: unknown tunnelAction: {}", tunnelAction);
383 private boolean hndlTepAddForAllRtrs(BigInteger srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
384 String destTepIp, TypedReadWriteTransaction<Configuration> writeFlowInvTx)
385 throws ExecutionException, InterruptedException {
386 LOG.trace("hndlTepAddForAllRtrs: TEP ADD ----- for EXTERNAL/HWVTEP ITM Tunnel, TYPE {} ,State is UP b/w SRC IP"
387 + " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
389 InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
390 Optional<DpnRoutersList> optionalRouterDpnList =
391 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
392 LogicalDatastoreType.OPERATIONAL, dpnRoutersListId);
393 if (!optionalRouterDpnList.isPresent()) {
394 LOG.info("hndlTepAddForAllRtrs : RouterDpnList model is empty for DPN {}. Hence ignoring TEP add event "
395 + "for the ITM TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ",
396 srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
400 List<RoutersList> routersList = optionalRouterDpnList.get().getRoutersList();
401 if (routersList == null) {
402 LOG.debug("hndlTepAddForAllRtrs : Ignoring TEP add for the DPN {} since no routers are associated"
403 + " for the DPN having the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
404 + "TUNNEL NAME {} ", srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
408 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
409 for (RoutersList router : routersList) {
410 String routerName = router.getRouter();
411 long routerId = NatUtil.getVpnId(dataBroker, routerName);
412 if (routerId == NatConstants.INVALID_ID) {
413 LOG.error("hndlTepAddForAllRtrs :Invalid ROUTER-ID {} returned for routerName {}",
414 routerId, routerName);
417 LOG.debug("hndlTepAddForAllRtrs : TEP ADD : DNAT -> Advertising routes for router {} ", routerName);
418 Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
419 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
420 routerName, externalNetworkId);
421 if (extNwProvType == null) {
424 hndlTepAddForDnatInEachRtr(router, routerId, nextHopIp, srcDpnId, extNwProvType, writeFlowInvTx);
426 LOG.debug("hndlTepAddForAllRtrs : TEP ADD : SNAT -> Advertising routes for router {} ", routerName);
427 hndlTepAddForSnatInEachRtr(router, routerId, srcDpnId, tunnelType, srcTepIp, destTepIp,
428 tunnelName, nextHopIp, extNwProvType, writeFlowInvTx);
433 // TODO Clean up the exception handling
434 @SuppressWarnings("checkstyle:IllegalCatch")
435 private boolean handleTepDelForAllRtrs(BigInteger srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
436 String destTepIp, TypedReadWriteTransaction<Configuration> writeFlowInvTx)
437 throws ExecutionException, InterruptedException {
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);
454 if (endpointIpForDPN != null) {
455 LOG.trace("handleTepDelForAllRtrs : Ignore TEP DELETE event received for DPN {} VTEP IP {} since its "
456 + "the other end DPN w.r.t the delted TEP", srcDpnId, srcTepIp);
460 List<RoutersList> routersList = null;
461 InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
462 Optional<DpnRoutersList> optionalRouterDpnList =
463 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
464 LogicalDatastoreType.OPERATIONAL, dpnRoutersListId);
465 if (optionalRouterDpnList.isPresent()) {
466 routersList = optionalRouterDpnList.get().getRoutersList();
468 LOG.warn("handleTepDelForAllRtrs : RouterDpnList is empty for DPN {}.Hence ignoring TEP DEL event "
469 + "for the ITM TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ",
470 srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
474 if (routersList == null) {
475 LOG.error("handleTepDelForAllRtrs : DPN {} does not have the Routers presence", srcDpnId);
479 for (RoutersList router : routersList) {
480 String routerName = router.getRouter();
481 LOG.debug("handleTepDelForAllRtrs : TEP DEL : DNAT -> Withdrawing routes for router {} ", routerName);
482 long routerId = NatUtil.getVpnId(dataBroker, routerName);
483 if (routerId == NatConstants.INVALID_ID) {
484 LOG.error("handleTepDelForAllRtrs :Invalid ROUTER-ID {} returned for routerName {}",
485 routerId, routerName);
488 Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
489 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
490 routerName, externalNetworkId);
491 if (extNwProvType == null) {
494 hndlTepDelForDnatInEachRtr(router, routerId, srcDpnId, extNwProvType);
495 LOG.debug("handleTepDelForAllRtrs : TEP DEL : SNAT -> Withdrawing and Advertising routes for router {} ",
497 hndlTepDelForSnatInEachRtr(router, routerId, srcDpnId, tunnelType, srcTepIp, destTepIp,
498 tunnelName, extNwProvType, writeFlowInvTx);
503 private void hndlTepAddForSnatInEachRtr(RoutersList router, long routerId, final BigInteger srcDpnId,
504 String tunnelType, String srcTepIp, String destTepIp, String tunnelName, String nextHopIp,
505 ProviderTypes extNwProvType, TypedReadWriteTransaction<Configuration> writeFlowInvTx)
506 throws ExecutionException, InterruptedException {
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;
518 routerData = writeFlowInvTx.read(extRoutersId).get();
519 } catch (InterruptedException | ExecutionException e) {
520 LOG.error("Error reading router data for {}", extRoutersId, e);
521 routerData = Optional.absent();
523 if (!routerData.isPresent()) {
524 LOG.warn("hndlTepAddForSnatInEachRtr : SNAT->Ignoring TEP add for router {} since its not External Router",
529 BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
530 if (naptId == null || naptId.equals(BigInteger.ZERO)) {
531 LOG.warn("hndlTepAddForSnatInEachRtr : SNAT -> Ignoring TEP add for the DPN {} having the router {} since"
532 + " the router is not part of the NAT service - the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
533 + "TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
536 if (natMode == NatMode.Conntrack) {
537 Routers extRouter = routerData.get();
538 natServiceManager.notify(writeFlowInvTx, extRouter, null, naptId, srcDpnId,
539 SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_ENBL);
540 if (extRouter.isEnableSnat()) {
541 natServiceManager.notify(writeFlowInvTx, extRouter, null, naptId, srcDpnId,
542 SnatServiceManager.Action.SNAT_ROUTER_ENBL);
545 Uuid bgpVpnUuId = NatUtil.getVpnForRouter(dataBroker, routerName);
546 //Check if the DPN having the router is the NAPT switch
547 if (!naptId.equals(srcDpnId)) {
549 1) Install default NAT rule from table 21 to 26
550 2) Install the group which forward packet to the tunnel port for the NAPT switch.
551 3) Install the flow 26 which forwards the packet to the group.
553 if (!hndlTepAddOnNonNaptSwitch(srcDpnId, naptId, tunnelType, srcTepIp, destTepIp, tunnelName,
554 routerName, routerId, bgpVpnUuId, writeFlowInvTx)) {
555 LOG.error("hndlTepAddForSnatInEachRtr : Unable to process the TEP add event on NON-NAPT switch {}",
561 if (!hndlTepAddOnNaptSwitch(srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName, routerId,
562 routerData, nextHopIp, bgpVpnUuId, extNwProvType, writeFlowInvTx)) {
563 LOG.debug("hndlTepAddForSnatInEachRtr : Unable to process the TEP add event on NAPT switch {}",
571 private boolean hndlTepAddOnNonNaptSwitch(BigInteger srcDpnId, BigInteger primaryDpnId, String tunnelType,
572 String srcTepIp, String destTepIp, String tunnelName, String routerName, long routerId, Uuid vpnName,
573 TypedWriteTransaction<Configuration> confTx) {
576 1) Install default NAT rule from table 21 to 26
577 2) Install the group which forward packet to the tunnel port for the NAPT switch.
578 3) Install the flow 26 which forwards the packet to the group.
580 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Processing TEP add for the DPN {} having the router {} since "
581 + "its THE NON NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
582 + "and TUNNEL NAME {} ",
583 srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
584 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Install default NAT rule from table 21 to 26");
586 if (vpnName == null) {
587 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Internal VPN associated to router {}", routerId);
589 if (vpnId == NatConstants.INVALID_ID) {
590 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid Internal VPN ID returned for routerName {}",
594 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerName);
595 //Install default entry in FIB to SNAT table
596 LOG.debug("hndlTepAddOnNonNaptSwitch : Installing default route in FIB on DPN {} for router {} with"
597 + " vpn {}...", srcDpnId, routerName, vpnId);
598 defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, confTx);
600 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Install the group which forward packet to the tunnel port "
601 + "for the NAPT switch {} and the flow 26 which forwards to group", primaryDpnId);
602 externalRouterListner.handleSwitches(srcDpnId, routerName, routerId, primaryDpnId);
604 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> External BGP VPN (Private BGP) associated to router {}",
606 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
607 if (vpnId == NatConstants.INVALID_ID) {
608 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid Private BGP VPN ID returned for routerName {}",
612 if (routerId == NatConstants.INVALID_ID) {
613 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid routId returned for routerName {}", routerId);
616 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
617 //Install default entry in FIB to SNAT table
618 LOG.debug("hndlTepAddOnNonNaptSwitch : Installing default route in FIB on dpn {} for routerId {} "
619 + "with vpnId {}...", srcDpnId, routerId, vpnId);
620 defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, routerId, confTx);
622 LOG.debug("hndlTepAddOnNonNaptSwitch : Install group in non NAPT switch {} for router {}",
623 srcDpnId, routerName);
624 List<BucketInfo> bucketInfoForNonNaptSwitches =
625 externalRouterListner.getBucketInfoForNonNaptSwitches(srcDpnId, primaryDpnId, routerName, routerId);
626 long groupId = externalRouterListner.installGroup(srcDpnId, routerName, bucketInfoForNonNaptSwitches);
628 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> in the SNAT miss entry pointing to group {} "
629 + "in the non NAPT switch {}", groupId, srcDpnId);
630 FlowEntity flowEntity =
631 externalRouterListner.buildSnatFlowEntityWithUpdatedVpnId(srcDpnId, routerName, groupId, vpnId);
632 mdsalManager.addFlow(confTx, flowEntity);
637 private boolean hndlTepAddOnNaptSwitch(BigInteger srcDpnId, String tunnelType, String srcTepIp,
638 String destTepIp, String tunnelName, long routerId,
639 Optional<Routers> routerData, String nextHopIp, Uuid vpnName,
640 ProviderTypes extNwProvType, TypedWriteTransaction<Configuration> confTx) {
641 if (!routerData.isPresent()) {
642 LOG.warn("hndlTepAddOnNaptSwitch: routerData is not present");
645 Routers router = routerData.get();
646 String routerName = router.getRouterName();
647 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Processing TEP add for the DPN {} having the router {} since "
648 + "its THE NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
649 + "and TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
651 Uuid networkId = router.getNetworkId();
652 if (networkId == null) {
653 LOG.warn("hndlTepAddOnNaptSwitch : SNAT -> Ignoring TEP add since the router {} is not associated to the "
654 + "external network", routerName);
658 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Router {} is associated with Ext nw {}", routerId, networkId);
660 if (vpnName == null) {
661 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Internal VPN associated to router {}", routerId);
662 vpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
663 if (vpnId == NatConstants.INVALID_ID) {
664 LOG.error("hndlTepAddOnNaptSwitch : Invalid External VPN-ID returned for routerName {}", routerName);
667 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Retrieved External VPN-ID {} for router {}", vpnId, routerId);
669 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Private BGP VPN associated to router {}", routerId);
670 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
671 if (vpnId == NatConstants.INVALID_ID) {
672 LOG.error("hndlTepAddOnNaptSwitch : Invalid vpnId returned for routerName {}", routerName);
675 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
678 /*1) Withdraw the old route to the external IP from the BGP which was having the
679 next hop as the old TEP IP.
680 2) Advertise to the BGP about the new route to the external IP having the
681 new TEP IP as the next hop.
682 3) Populate a new FIB entry with the next hop IP as the new TEP IP using the
686 //Withdraw the old route to the external IP from the BGP which was having the
687 //next hop as the old TEP IP.
688 final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
689 if (externalVpnName == null) {
690 LOG.error("hndlTepAddOnNaptSwitch : SNAT -> No VPN associated with ext nw {} in router {}",
691 networkId, routerId);
694 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
695 LOG.debug("hndlTepAddOnNaptSwitch : Clearing the FIB entries but not the BGP routes");
696 for (String externalIp : externalIps) {
697 String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
698 LOG.debug("hndlTepAddOnNaptSwitch : Removing Fib entry rd {} prefix {}", rd, externalIp);
699 fibManager.removeFibEntry(rd, externalIp, null);
703 Advertise to the BGP about the new route to the external IP having the
704 new TEP IP as the next hop.
705 Populate a new FIB entry with the next hop IP as the new TEP IP using the
708 String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
709 if (extNwProvType == null) {
712 String gwMacAddress = null;
714 if (extNwProvType == ProviderTypes.VXLAN) {
715 // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
716 gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
717 if (gwMacAddress != null) {
718 LOG.debug("hndlTepAddOnNaptSwitch : External Gateway MAC address {} found for External Router ID {}",
719 gwMacAddress, routerId);
721 LOG.error("hndlTepAddOnNaptSwitch : No External Gateway MAC address found for External Router ID {}",
725 //get l3Vni value for external VPN
726 l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
727 if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
728 LOG.debug("hndlTepAddOnNaptSwitch : L3VNI value is not configured in Internet VPN {} and RD {} "
729 + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
730 + "NAT flows", vpnName, rd);
731 l3Vni = natOverVxlanUtil.getInternetVpnVni(externalVpnName, routerId).longValue();
735 for (final String externalIp : externalIps) {
737 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
738 if (extNwProvType == ProviderTypes.VXLAN) {
739 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Advertise the route to the externalIp {} "
740 + "having nextHopIp {}", externalIp, nextHopIp);
741 NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, externalVpnName, rd,
742 externalIp, nextHopIp, l3Vni, tunnelName, gwMacAddress, confTx, RouteOrigin.STATIC,
743 srcDpnId, networkId);
747 Long label = externalRouterListner.checkExternalIpLabel(routerId,
749 if (label == null || label == NatConstants.INVALID_ID) {
750 LOG.error("hndlTepAddOnNaptSwitch : SNAT->Unable to advertise to the DC GW "
751 + "since label is invalid");
754 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Advertise the route to the externalIp {} "
755 + "having nextHopIp {}", externalIp, nextHopIp);
757 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
758 l3vni = natOverVxlanUtil.getInternetVpnVni(externalVpnName, l3vni).longValue();
760 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, externalVpnName, rd,
761 fibExternalIp, nextHopIp, networkId.getValue(), null /* mac-address */, label, l3vni,
762 RouteOrigin.STATIC, srcDpnId);
766 LOG.debug("hndlTepAddOnNaptSwitch: SNAT -> Install custom FIB routes "
767 + "(Table 21 -> Push MPLS label to Tunnel port");
768 List<Instruction> customInstructions = new ArrayList<>();
769 int customInstructionIndex = 0;
770 long externalSubnetVpnId = NatUtil.getExternalSubnetVpnIdForRouterExternalIp(dataBroker, externalIp,
772 if (externalSubnetVpnId != NatConstants.INVALID_ID) {
773 LOG.debug("hndlTepAddOnNaptSwitch : Will install custom FIB router with external subnet VPN ID {}",
774 externalSubnetVpnId);
775 BigInteger subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(externalSubnetVpnId);
776 customInstructions.add(new InstructionWriteMetadata(subnetIdMetaData,
777 MetaDataUtil.METADATA_MASK_VRFID).buildInstruction(customInstructionIndex));
778 customInstructionIndex++;
780 customInstructions.add(new InstructionGotoTable(NwConstants.INBOUND_NAPT_TABLE)
781 .buildInstruction(customInstructionIndex));
782 CreateFibEntryInput input =
783 new CreateFibEntryInputBuilder().setVpnName(externalVpnName).setSourceDpid(srcDpnId)
784 .setInstruction(customInstructions).setIpAddress(fibExternalIp)
785 .setIpAddressSource(FibEntryInputs.IpAddressSource.ExternalFixedIP)
786 .setServiceId(serviceId).setInstruction(customInstructions).build();
787 ListenableFuture<RpcResult<CreateFibEntryOutput>> listenableFuture = fibRpcService.createFibEntry(input);
789 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
792 public void onFailure(@Nonnull Throwable error) {
793 LOG.error("hndlTepAddOnNaptSwitch : SNAT->Error in generate label or fib install process",
798 public void onSuccess(@Nonnull RpcResult<CreateFibEntryOutput> result) {
799 if (result.isSuccessful()) {
800 LOG.info("hndlTepAddOnNaptSwitch : SNAT -> Successfully installed custom FIB routes "
801 + "for prefix {}", externalIp);
803 LOG.error("hndlTepAddOnNaptSwitch : SNAT -> Error in rpc call to create custom Fib entries "
804 + "for prefix {} in DPN {}, {}", externalIp, srcDpnId, result.getErrors());
807 }, MoreExecutors.directExecutor());
813 private void hndlTepAddForDnatInEachRtr(RoutersList router, long routerId, String nextHopIp,
814 BigInteger tepAddedDpnId, ProviderTypes extNwProvType, TypedWriteTransaction<Configuration> confTx) {
815 //DNAT : Advertise the new route to the floating IP having the new TEP IP as the next hop IP
816 final String routerName = router.getRouter();
818 InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
819 Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType
820 .CONFIGURATION, routerPortsId);
821 if (!optRouterPorts.isPresent()) {
822 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Could not read Router Ports data object with id: {} "
823 + "from DNAT FloatinIpInfo", routerName);
826 RouterPorts routerPorts = optRouterPorts.get();
827 Uuid extNwId = routerPorts.getExternalNetworkId();
828 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId);
829 if (vpnName == null) {
830 LOG.info("hndlTepAddForDnatInEachRtr : DNAT -> No External VPN associated with ext nw {} for router {}",
831 extNwId, routerName);
835 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
836 if (extNwProvType == null) {
839 String gwMacAddress = null;
841 if (extNwProvType == ProviderTypes.VXLAN) {
842 // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
843 gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
844 if (gwMacAddress != null) {
845 LOG.debug("hndlTepAddForDnatInEachRtr : External GwMAC address {} found for External Router ID {}",
846 gwMacAddress, routerId);
848 LOG.error("hndlTepAddForDnatInEachRtr : No External GwMAC address found for External Router ID {}",
852 //get l3Vni value for external VPN
853 l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
854 if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
855 LOG.debug("hndlTepAddForDnatInEachRtr : L3VNI value is not configured in Internet VPN {} and RD {} "
856 + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
857 + "NAT flows", vpnName, rd);
858 l3Vni = natOverVxlanUtil.getInternetVpnVni(vpnName, routerId).longValue();
861 for (Ports port : requireNonNullElse(routerPorts.getPorts(), Collections.<Ports>emptyList())) {
862 //Get the DPN on which this interface resides
863 final String interfaceName = port.getPortName();
864 final BigInteger fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
865 if (fipCfgdDpnId.equals(BigInteger.ZERO)) {
866 LOG.info("hndlTepAddForDnatInEachRtr : DNAT->Skip processing Floating ip configuration for the port {},"
867 + "since no DPN present for it", interfaceName);
870 if (!fipCfgdDpnId.equals(tepAddedDpnId)) {
871 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> TEP added DPN {} is not the DPN {} which has the "
872 + "floating IP configured for the port: {}",
873 tepAddedDpnId, fipCfgdDpnId, interfaceName);
876 for (InternalToExternalPortMap intExtPortMap : requireNonNullElse(port.getInternalToExternalPortMap(),
877 Collections.<InternalToExternalPortMap>emptyList())) {
878 final String internalIp = intExtPortMap.getInternalIp();
879 final String externalIp = intExtPortMap.getExternalIp();
880 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertising the FIB route to the floating IP {} "
881 + "configured for the port: {}", externalIp, interfaceName);
883 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
885 if (extNwProvType == ProviderTypes.VXLAN) {
886 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertise the route to the externalIp {} "
887 + "having nextHopIp {}", externalIp, nextHopIp);
888 NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, vpnName, rd,
889 externalIp, nextHopIp, l3Vni, interfaceName, gwMacAddress, confTx, RouteOrigin.STATIC,
890 fipCfgdDpnId, extNwId);
893 long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
894 if (label == NatConstants.INVALID_ID) {
895 LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Unable to advertise to the DC GW since label "
899 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertise the route to the externalIp {} "
900 + "having nextHopIp {}", externalIp, nextHopIp);
902 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
903 l3vni = natOverVxlanUtil.getInternetVpnVni(vpnName, l3vni).longValue();
905 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd,
906 fibExternalIp, nextHopIp, null, null, label, l3vni, RouteOrigin.STATIC,
911 //Install custom FIB routes (Table 21 -> Push MPLS label to Tunnel port
912 List<Instruction> customInstructions = new ArrayList<>();
913 customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(0));
914 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
915 .setSourceDpid(fipCfgdDpnId).setInstruction(customInstructions)
916 .setIpAddressSource(FibEntryInputs.IpAddressSource.FloatingIP)
917 .setIpAddress(fibExternalIp).setServiceId(serviceId).setInstruction(customInstructions)
919 ListenableFuture<RpcResult<CreateFibEntryOutput>> listenableFuture =
920 fibRpcService.createFibEntry(input);
922 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
925 public void onFailure(@Nonnull Throwable error) {
926 LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Error in generate label or fib install process",
931 public void onSuccess(@Nonnull RpcResult<CreateFibEntryOutput> result) {
932 if (result.isSuccessful()) {
933 LOG.info("hndlTepAddForDnatInEachRtr : DNAT -> Successfully installed custom FIB routes "
934 + "for prefix {}", externalIp);
936 LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Error in rpc call to create custom Fib "
937 + "entries for prefix {} in DPN {}, {}", externalIp, fipCfgdDpnId, result.getErrors());
940 }, MoreExecutors.directExecutor());
945 private void hndlTepDelForSnatInEachRtr(RoutersList router, long routerId, BigInteger dpnId, String tunnelType,
946 String srcTepIp, String destTepIp, String tunnelName, ProviderTypes extNwProvType,
947 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
949 1) Elect a new switch as the primary NAPT
950 2) Advertise the new routes to BGP for the newly elected TEP IP as the DPN IP
951 3) This will make sure old routes are withdrawn and new routes are advertised.
954 String routerName = router.getRouter();
955 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Trying to clear routes to the External fixed IP associated "
956 + "to the router {}", routerName);
958 // Check if this is externalRouter else ignore
959 InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
960 Optional<Routers> routerData;
962 routerData = confTx.read(extRoutersId).get();
963 } catch (InterruptedException | ExecutionException e) {
964 LOG.error("Error retrieving routers {}", extRoutersId, e);
965 routerData = Optional.absent();
967 if (!routerData.isPresent()) {
968 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Ignoring TEP del for router {} since its not External Router",
973 //Check if the DPN having the router is the NAPT switch
974 BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
975 if (naptId == null || naptId.equals(BigInteger.ZERO) || !naptId.equals(dpnId)) {
976 LOG.warn("hndlTepDelForSnatInEachRtr : SNAT -> Ignoring TEP delete for the DPN {} since"
977 + " its NOT a NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
978 + "TUNNEL NAME {} ", dpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
981 if (natMode == NatMode.Conntrack) {
982 Routers extRouter = routerData.get();
983 natServiceManager.notify(confTx, extRouter, null, naptId, dpnId,
984 SnatServiceManager.Action.CNT_ROUTER_DISBL);
985 if (extRouter.isEnableSnat()) {
986 natServiceManager.notify(confTx,extRouter, null, naptId, dpnId,
987 SnatServiceManager.Action.SNAT_ROUTER_DISBL);
992 Uuid networkId = routerData.get().getNetworkId();
993 if (networkId == null) {
994 LOG.error("hndlTepDelForSnatInEachRtr : SNAT->Ignoring TEP delete for the DPN {} having the router {} "
995 + "since the Router instance {} not found in ExtRouters model b/w SRC IP {} and DST "
996 + "IP {} and TUNNEL NAME {} ", dpnId, routerData.get().getRouterName(), tunnelType,
997 srcTepIp, destTepIp, tunnelName);
1001 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Router {} is associated with ext nw {}", routerId, networkId);
1002 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
1004 if (bgpVpnUuid == null) {
1005 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Internal VPN-ID {} associated to router {}",
1006 routerId, routerName);
1007 bgpVpnId = routerId;
1009 //Install default entry in FIB to SNAT table
1010 LOG.debug("hndlTepDelForSnatInEachRtr : Installing default route in FIB on DPN {} for router {} with"
1011 + " vpn {}...", dpnId, routerName, bgpVpnId);
1012 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, confTx);
1014 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
1015 if (bgpVpnId == NatConstants.INVALID_ID) {
1016 LOG.error("hndlTepDelForSnatInEachRtr :SNAT->Invalid Private BGP VPN ID returned for routerName {}",
1020 LOG.debug("hndlTepDelForSnatInEachRtr :SNAT->External BGP VPN (Private BGP) {} associated to router {}",
1021 bgpVpnId, routerName);
1022 //Install default entry in FIB to SNAT table
1023 LOG.debug("hndlTepDelForSnatInEachRtr : Installing default route in FIB on dpn {} for routerId {} "
1024 + "with vpnId {}...", dpnId, routerId, bgpVpnId);
1025 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, routerId, confTx);
1028 if (routerData.get().isEnableSnat()) {
1029 LOG.info("hndlTepDelForSnatInEachRtr : SNAT enabled for router {}", routerId);
1031 long routerVpnId = routerId;
1032 if (bgpVpnId != NatConstants.INVALID_ID) {
1033 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Private BGP VPN ID (Internal BGP VPN ID) {} "
1034 + "associated to the router {}", bgpVpnId, routerName);
1035 routerVpnId = bgpVpnId;
1037 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Internal L3 VPN ID (Router ID) {} "
1038 + "associated to the router {}", routerVpnId, routerName);
1040 //Re-elect the other available switch as the NAPT switch and program the NAT flows.
1041 removeSNATFromDPN(dpnId, routerName, routerId, routerVpnId, networkId, extNwProvType, confTx);
1043 LOG.info("hndlTepDelForSnatInEachRtr : SNAT is not enabled for router {} to handle addDPN event {}",
1049 private void hndlTepDelForDnatInEachRtr(RoutersList router, long routerId, BigInteger tepDeletedDpnId,
1050 ProviderTypes extNwProvType) {
1051 //DNAT : Withdraw the routes from the BGP
1052 String routerName = router.getRouter();
1054 LOG.debug("hndlTepDelForDnatInEachRtr : DNAT -> Trying to clear routes to the Floating IP "
1055 + "associated to the router {}", routerName);
1057 InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
1058 Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType
1059 .CONFIGURATION, routerPortsId);
1060 if (!optRouterPorts.isPresent()) {
1061 LOG.debug("hndlTepDelForDnatInEachRtr : DNAT -> Could not read Router Ports data object with id: {} "
1062 + "from DNAT FloatingIpInfo", routerName);
1065 RouterPorts routerPorts = optRouterPorts.get();
1066 Uuid extNwId = routerPorts.getExternalNetworkId();
1067 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId);
1068 if (vpnName == null) {
1069 LOG.error("hndlTepDelForDnatInEachRtr : DNAT -> No External VPN associated with Ext N/W {} for Router {}",
1070 extNwId, routerName);
1073 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
1074 if (extNwProvType == null) {
1078 if (extNwProvType == ProviderTypes.VXLAN) {
1079 //get l3Vni value for external VPN
1080 l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
1081 if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
1082 LOG.debug("hndlTepDelForDnatInEachRtr : L3VNI value is not configured in Internet VPN {} and RD {} "
1083 + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
1084 + "NAT flows", vpnName, rd);
1085 l3Vni = natOverVxlanUtil.getInternetVpnVni(vpnName, routerId).longValue();
1088 for (Ports port : requireNonNullElse(routerPorts.getPorts(), Collections.<Ports>emptyList())) {
1089 //Get the DPN on which this interface resides
1090 String interfaceName = port.getPortName();
1091 BigInteger fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
1092 if (fipCfgdDpnId.equals(BigInteger.ZERO)) {
1093 LOG.info("hndlTepDelForDnatInEachRtr : DNAT -> Abort processing Floating ip configuration. "
1094 + "No DPN for port : {}", interfaceName);
1097 if (!fipCfgdDpnId.equals(tepDeletedDpnId)) {
1098 LOG.info("hndlTepDelForDnatInEachRtr : DNAT -> TEP deleted DPN {} is not the DPN {} which has the "
1099 + "floating IP configured for the port: {}",
1100 tepDeletedDpnId, fipCfgdDpnId, interfaceName);
1103 for (InternalToExternalPortMap intExtPortMap : requireNonNullElse(port.getInternalToExternalPortMap(),
1104 Collections.<InternalToExternalPortMap>emptyList())) {
1105 String internalIp = intExtPortMap.getInternalIp();
1106 String externalIp = intExtPortMap.getExternalIp();
1107 externalIp = NatUtil.validateAndAddNetworkMask(externalIp);
1108 LOG.debug("hndlTepDelForDnatInEachRtr : DNAT -> Withdrawing the FIB route to the floating IP {} "
1109 + "configured for the port: {}",
1110 externalIp, interfaceName);
1111 NatUtil.removePrefixFromBGP(bgpManager, fibManager, rd, externalIp, vpnName, LOG);
1113 if (extNwProvType == ProviderTypes.VXLAN) {
1116 long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
1117 if (label == NatConstants.INVALID_ID) {
1118 LOG.error("hndlTepDelForDnatInEachRtr : DNAT -> Unable to remove the table 21 entry pushing the"
1119 + " MPLS label to the tunnel since label is invalid");
1125 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
1126 .setSourceDpid(fipCfgdDpnId).setIpAddress(externalIp).setServiceId(serviceId)
1127 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.FloatingIP).build();
1128 ListenableFuture<RpcResult<RemoveFibEntryOutput>> listenableFuture =
1129 fibRpcService.removeFibEntry(input);
1131 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<RemoveFibEntryOutput>>() {
1134 public void onFailure(@Nonnull Throwable error) {
1135 LOG.error("hndlTepDelForDnatInEachRtr : DNAT -> Error in removing the table 21 entry pushing "
1136 + "the MPLS label to the tunnel since label is invalid ", error);
1140 public void onSuccess(@Nonnull RpcResult<RemoveFibEntryOutput> result) {
1141 if (result.isSuccessful()) {
1142 LOG.info("hndlTepDelForDnatInEachRtr : DNAT -> Successfully removed the entry pushing the "
1143 + "MPLS label to the tunnel");
1145 LOG.error("hndlTepDelForDnatInEachRtr : DNAT -> Error in fib rpc call to remove the table "
1146 + "21 entry pushing the MPLS label to the tunnnel due to {}", result.getErrors());
1149 }, MoreExecutors.directExecutor());
1154 protected boolean isTunnelInLogicalGroup(StateTunnelList stateTunnelList) {
1155 String ifaceName = stateTunnelList.getTunnelInterfaceName();
1156 if (getTunnelType(stateTunnelList) == NatConstants.ITMTunnelLocType.Internal.getValue()) {
1157 Interface configIface = interfaceManager.getInterfaceInfoFromConfigDataStore(ifaceName);
1158 IfTunnel ifTunnel = configIface != null ? configIface.augmentation(IfTunnel.class) : null;
1159 if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) {
1160 ParentRefs refs = configIface.augmentation(ParentRefs.class);
1161 if (refs != null && !Strings.isNullOrEmpty(refs.getParentInterface())) {
1162 return true; //multiple VxLAN tunnels enabled, i.e. only logical tunnel should be treated
1166 LOG.trace("isTunnelInLogicalGroup: ignoring the tunnel event for {}", ifaceName);