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;
13 import com.google.common.base.Optional;
14 import com.google.common.base.Strings;
15 import com.google.common.util.concurrent.FutureCallback;
16 import com.google.common.util.concurrent.Futures;
17 import com.google.common.util.concurrent.ListenableFuture;
18 import com.google.common.util.concurrent.MoreExecutors;
19 import java.math.BigInteger;
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.List;
24 import java.util.concurrent.ExecutionException;
25 import javax.annotation.Nonnull;
26 import javax.annotation.PostConstruct;
27 import javax.inject.Inject;
28 import javax.inject.Singleton;
29 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
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.Datastore.Configuration;
34 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
35 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
36 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
37 import org.opendaylight.genius.infra.TypedWriteTransaction;
38 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
39 import org.opendaylight.genius.mdsalutil.BucketInfo;
40 import org.opendaylight.genius.mdsalutil.FlowEntity;
41 import org.opendaylight.genius.mdsalutil.MDSALUtil;
42 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
43 import org.opendaylight.genius.mdsalutil.NwConstants;
44 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
45 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
46 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
47 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
48 import org.opendaylight.netvirt.elanmanager.api.IElanService;
49 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
50 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
51 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryOutput;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibEntryInputs;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryOutput;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersList;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.dpn.routers.list.RoutersList;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
82 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
83 import org.opendaylight.yangtools.yang.common.RpcResult;
84 import org.slf4j.Logger;
85 import org.slf4j.LoggerFactory;
88 public class NatTunnelInterfaceStateListener
89 extends AsyncDataTreeChangeListenerBase<StateTunnelList, NatTunnelInterfaceStateListener> {
91 private static final Logger LOG = LoggerFactory.getLogger(NatTunnelInterfaceStateListener.class);
92 private final DataBroker dataBroker;
93 private final ManagedNewTransactionRunner txRunner;
94 private final IFibManager fibManager;
95 private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
96 private final NaptSwitchHA naptSwitchHA;
97 private final IMdsalApiManager mdsalManager;
98 private final IdManagerService idManager;
99 private final IBgpManager bgpManager;
100 private final ExternalRoutersListener externalRouterListner;
101 private final SnatServiceManager natServiceManager;
102 private final OdlInterfaceRpcService interfaceService;
103 private final FloatingIPListener floatingIPListener;
104 private final FibRpcService fibRpcService;
105 private final IElanService elanManager;
106 private final IInterfaceManager interfaceManager;
107 private final NatMode natMode;
109 protected enum TunnelAction {
116 * Responsible for listening to tunnel interface state change.
118 * @param dataBroker - dataBroker service reference
119 * @param bgpManager Used to advertise routes to the BGP Router
120 * @param fibManager - FIB Manager
121 * @param defaultRouteProgrammer - Default Route Programmer
122 * @param naptSwitchHA - NAPT Switch HA
123 * @param mdsalManager - MDSAL Manager
124 * @param idManager - ID manager
125 * @param externalRouterListner - External Router Listener
126 * @param natServiceManager - Nat Service Manager
127 * @param interfaceService - Interface Service
128 * @param floatingIPListener - Floating IP Listener
129 * @param fibRpcService - FIB RPC Service
130 * @param config - Nat Service Config
131 * @param elanManager - Elan Manager
132 * @param interfaceManager - Interface Manager
135 public NatTunnelInterfaceStateListener(final DataBroker dataBroker,
136 final IBgpManager bgpManager,
137 final IFibManager fibManager,
138 final SNATDefaultRouteProgrammer defaultRouteProgrammer,
139 final NaptSwitchHA naptSwitchHA,
140 final IMdsalApiManager mdsalManager,
141 final IdManagerService idManager,
142 final ExternalRoutersListener externalRouterListner,
143 final SnatServiceManager natServiceManager,
144 final OdlInterfaceRpcService interfaceService,
145 final FloatingIPListener floatingIPListener,
146 final FibRpcService fibRpcService,
147 final NatserviceConfig config,
148 final IElanService elanManager,
149 final IInterfaceManager interfaceManager) {
150 super(StateTunnelList.class, NatTunnelInterfaceStateListener.class);
151 this.dataBroker = dataBroker;
152 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
153 this.bgpManager = bgpManager;
154 this.fibManager = fibManager;
155 this.defaultRouteProgrammer = defaultRouteProgrammer;
156 this.naptSwitchHA = naptSwitchHA;
157 this.mdsalManager = mdsalManager;
158 this.idManager = idManager;
159 this.externalRouterListner = externalRouterListner;
160 this.natServiceManager = natServiceManager;
161 this.interfaceService = interfaceService;
162 this.floatingIPListener = floatingIPListener;
163 this.fibRpcService = fibRpcService;
164 this.elanManager = elanManager;
165 this.interfaceManager = interfaceManager;
166 if (config != null) {
167 this.natMode = config.getNatMode();
169 this.natMode = NatMode.Controller;
176 LOG.info("{} init", getClass().getSimpleName());
177 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
181 protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
182 return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
186 protected NatTunnelInterfaceStateListener getDataTreeChangeListener() {
187 return NatTunnelInterfaceStateListener.this;
191 protected void add(InstanceIdentifier<StateTunnelList> instanceIdentifier, StateTunnelList add) {
192 LOG.trace("add : TEP addtion---- {}", add);
193 hndlTepEvntsForDpn(add, TunnelAction.TUNNEL_EP_ADD);
197 protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
198 LOG.trace("remove : TEP deletion---- {}", del);
199 hndlTepEvntsForDpn(del, TunnelAction.TUNNEL_EP_DELETE);
203 protected void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original,
204 StateTunnelList update) {
205 LOG.trace("update : Tunnel updation---- {}", update);
206 //UPDATE IS A SEQUENCE OF DELETE AND ADD EVENTS . DELETE MIGHT HAVE CHANGED THE PRIMARY AND ADVERTISED. SO
210 private int getTunnelType(StateTunnelList stateTunnelList) {
212 if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
213 tunTypeVal = NatConstants.ITMTunnelLocType.Internal.getValue();
214 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
215 tunTypeVal = NatConstants.ITMTunnelLocType.External.getValue();
216 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
217 tunTypeVal = NatConstants.ITMTunnelLocType.Hwvtep.getValue();
219 tunTypeVal = NatConstants.ITMTunnelLocType.Invalid.getValue();
224 // TODO Clean up the exception handling
225 @SuppressWarnings("checkstyle:IllegalCatch")
226 void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerId, long routerVpnId,
227 Uuid networkId, ProviderTypes extNwProvType, TypedReadWriteTransaction<Configuration> confTx) {
228 //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
229 //remove miss entry to NAPT switch
230 //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
232 if (routerId == NatConstants.INVALID_ID) {
233 LOG.error("removeSNATFromDPN : SNAT -> Invalid routerId returned for routerName {}", routerName);
236 Collection<String> externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
237 if (extNwProvType == null) {
240 Map<String, Long> externalIpLabel;
241 if (extNwProvType == ProviderTypes.VXLAN) {
242 externalIpLabel = null;
244 externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
247 final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
248 if (externalVpnName == null) {
249 LOG.error("removeSNATFromDPN : SNAT -> No VPN associated with ext nw {} in router {}",
250 networkId, routerId);
254 BigInteger naptSwitch = dpnId;
256 naptSwitchHA.isNaptSwitchDown(routerName, routerId, dpnId, naptSwitch,
257 routerVpnId, externalIpCache, false, confTx);
259 LOG.debug("removeSNATFromDPN:SNAT->NaptSwitchDown:Switch with DpnId {} is not naptSwitch for router {}",
261 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
262 FlowEntity flowEntity = null;
264 flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId,
265 routerVpnId, NatConstants.DEL_FLOW);
266 if (flowEntity == null) {
267 LOG.error("removeSNATFromDPN : SNAT -> Failed to populate flowentity for "
268 + "router {} with dpnId {} groupIs {}", routerName, dpnId, groupId);
271 LOG.debug("removeSNATFromDPN : SNAT->Removing default SNAT miss entry flow entity {}", flowEntity);
272 mdsalManager.removeFlow(confTx, flowEntity);
274 } catch (Exception ex) {
275 LOG.error("removeSNATFromDPN : SNAT->Failed to remove default SNAT miss entry flow entity {}",
279 LOG.debug("removeSNATFromDPN:SNAT->Removed default SNAT miss entry flow for dpnID {}, routername {}",
284 LOG.info("removeSNATFromDPN : SNAT->Removing NAPT Group :{} on Dpn {}", groupId, dpnId);
285 mdsalManager.removeGroup(confTx, dpnId, groupId);
286 } catch (Exception ex) {
287 LOG.error("removeSNATFromDPN : SNAT->Failed to remove group {}", groupId, ex);
290 LOG.debug("removeSNATFromDPN : SNAT->Removed default SNAT miss entry flow for dpnID {}, routerName {}",
293 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, routerId, dpnId, externalIpLabel, confTx);
294 //remove table 26 flow ppointing to table46
295 FlowEntity flowEntity = null;
297 flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId,
298 NatConstants.DEL_FLOW);
299 if (flowEntity == null) {
300 LOG.error("removeSNATFromDPN : SNAT->Failed to populate flowentity for router {} with dpnId {}",
304 LOG.debug("removeSNATFromDPN : SNAT->Removing default SNAT miss entry flow entity for "
305 + "router {} with dpnId {} in napt switch {}", routerName, dpnId, naptSwitch);
306 mdsalManager.removeFlow(confTx, flowEntity);
308 } catch (Exception ex) {
309 LOG.error("removeSNATFromDPN : SNAT->Failed to remove default SNAT miss entry flow entity {}",
313 LOG.debug("removeSNATFromDPN : SNAT->Removed default SNAT miss entry flow for dpnID {} "
314 + "with routername {}", dpnId, routerName);
316 //best effort to check IntExt model
317 naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel, confTx);
319 } catch (Exception ex) {
320 LOG.error("removeSNATFromDPN : SNAT->Exception while handling naptSwitch down for router {}",
325 private void hndlTepEvntsForDpn(StateTunnelList stateTunnelList, TunnelAction tunnelAction) {
326 final BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
327 final String srcTepIp = String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue());
328 final String destTepIp = String.valueOf(stateTunnelList.getDstInfo().getTepIp().getValue());
329 LOG.trace("hndlTepEvntsForDpn : Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ",
330 srcDpnId, srcTepIp, destTepIp);
331 int tunTypeVal = getTunnelType(stateTunnelList);
332 LOG.trace("hndlTepEvntsForDpn : tunTypeVal is {}", tunTypeVal);
333 String srcTepId = stateTunnelList.getSrcInfo().getTepDeviceId();
334 String tunnelType = stateTunnelList.getTransportType().toString();
335 String tunnelName = stateTunnelList.getTunnelInterfaceName();
337 if (tunTypeVal == NatConstants.ITMTunnelLocType.Invalid.getValue()) {
338 LOG.warn("hndlTepEvntsForDpn : Ignoring TEP event {} for the DPN {} "
339 + "since its a INVALID TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and " + "TUNNEL NAME {} ",
340 tunnelAction, srcTepId, tunnelType, srcTepIp, destTepIp, tunnelName);
344 switch (tunnelAction) {
347 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
348 if (isTunnelInLogicalGroup(stateTunnelList)
349 || !hndlTepAddForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp,
351 LOG.debug("hndlTepEvntsForDpn : Unable to process TEP ADD");
354 } catch (InterruptedException | ExecutionException e) {
355 LOG.error("Error processing tunnel endpoint addition", e);
358 case TUNNEL_EP_DELETE:
360 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
361 if (!handleTepDelForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp, tx)) {
362 LOG.debug("hndlTepEvntsForDpn : Unable to process TEP DEL");
365 } catch (InterruptedException | ExecutionException e) {
366 LOG.error("Error processing tunnel endpoint removal", e);
369 case TUNNEL_EP_UPDATE:
372 LOG.warn("hndlTepEvntsForDpn: unknown tunnelAction: {}", tunnelAction);
377 private boolean hndlTepAddForAllRtrs(BigInteger srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
378 String destTepIp, TypedReadWriteTransaction<Configuration> writeFlowInvTx) {
379 LOG.trace("hndlTepAddForAllRtrs: TEP ADD ----- for EXTERNAL/HWVTEP ITM Tunnel, TYPE {} ,State is UP b/w SRC IP"
380 + " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
382 InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
383 Optional<DpnRoutersList> optionalRouterDpnList =
384 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
385 LogicalDatastoreType.OPERATIONAL, dpnRoutersListId);
386 if (!optionalRouterDpnList.isPresent()) {
387 LOG.info("hndlTepAddForAllRtrs : RouterDpnList model is empty for DPN {}. Hence ignoring TEP add event "
388 + "for the ITM TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ",
389 srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
393 List<RoutersList> routersList = optionalRouterDpnList.get().getRoutersList();
394 if (routersList == null) {
395 LOG.debug("hndlTepAddForAllRtrs : Ignoring TEP add for the DPN {} since no routers are associated"
396 + " for the DPN having the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
397 + "TUNNEL NAME {} ", srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
401 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
402 for (RoutersList router : routersList) {
403 String routerName = router.getRouter();
404 long routerId = NatUtil.getVpnId(dataBroker, routerName);
405 if (routerId == NatConstants.INVALID_ID) {
406 LOG.error("hndlTepAddForAllRtrs :Invalid ROUTER-ID {} returned for routerName {}",
407 routerId, routerName);
410 LOG.debug("hndlTepAddForAllRtrs : TEP ADD : DNAT -> Advertising routes for router {} ", routerName);
411 Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
412 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
413 routerName, externalNetworkId);
414 if (extNwProvType == null) {
417 hndlTepAddForDnatInEachRtr(router, routerId, nextHopIp, srcDpnId, extNwProvType, writeFlowInvTx);
419 LOG.debug("hndlTepAddForAllRtrs : TEP ADD : SNAT -> Advertising routes for router {} ", routerName);
420 hndlTepAddForSnatInEachRtr(router, routerId, srcDpnId, tunnelType, srcTepIp, destTepIp,
421 tunnelName, nextHopIp, extNwProvType, writeFlowInvTx);
426 // TODO Clean up the exception handling
427 @SuppressWarnings("checkstyle:IllegalCatch")
428 private boolean handleTepDelForAllRtrs(BigInteger srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
429 String destTepIp, TypedReadWriteTransaction<Configuration> writeFlowInvTx) {
431 LOG.trace("handleTepDelForAllRtrs : TEP DEL ----- for EXTERNAL/HWVTEP ITM Tunnel,TYPE {},State is UP b/w SRC IP"
432 + " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
434 // When tunnel EP is deleted on a DPN , VPN gets two deletion event.
435 // One for a DPN on which tunnel EP was deleted and another for other-end DPN.
436 // Handle only the DPN on which it was deleted , ignore other event.
437 // DPN on which TEP is deleted , endpoint IP will be null.
438 String endpointIpForDPN = null;
440 endpointIpForDPN = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
441 } catch (Exception e) {
442 /* this dpn does not have the VTEP */
443 LOG.error("handleTepDelForAllRtrs : DPN {} does not have the VTEP", srcDpnId);
444 endpointIpForDPN = null;
447 if (endpointIpForDPN != null) {
448 LOG.trace("handleTepDelForAllRtrs : Ignore TEP DELETE event received for DPN {} VTEP IP {} since its "
449 + "the other end DPN w.r.t the delted TEP", srcDpnId, srcTepIp);
453 List<RoutersList> routersList = null;
454 InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
455 Optional<DpnRoutersList> optionalRouterDpnList =
456 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
457 LogicalDatastoreType.OPERATIONAL, dpnRoutersListId);
458 if (optionalRouterDpnList.isPresent()) {
459 routersList = optionalRouterDpnList.get().getRoutersList();
461 LOG.warn("handleTepDelForAllRtrs : RouterDpnList is empty for DPN {}.Hence ignoring TEP DEL event "
462 + "for the ITM TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ",
463 srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
467 if (routersList == null) {
468 LOG.error("handleTepDelForAllRtrs : DPN {} does not have the Routers presence", srcDpnId);
472 for (RoutersList router : routersList) {
473 String routerName = router.getRouter();
474 LOG.debug("handleTepDelForAllRtrs : TEP DEL : DNAT -> Withdrawing routes for router {} ", routerName);
475 long routerId = NatUtil.getVpnId(dataBroker, routerName);
476 if (routerId == NatConstants.INVALID_ID) {
477 LOG.error("handleTepDelForAllRtrs :Invalid ROUTER-ID {} returned for routerName {}",
478 routerId, routerName);
481 Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
482 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
483 routerName, externalNetworkId);
484 if (extNwProvType == null) {
487 hndlTepDelForDnatInEachRtr(router, routerId, srcDpnId, extNwProvType);
488 LOG.debug("handleTepDelForAllRtrs : TEP DEL : SNAT -> Withdrawing and Advertising routes for router {} ",
490 hndlTepDelForSnatInEachRtr(router, routerId, srcDpnId, tunnelType, srcTepIp, destTepIp,
491 tunnelName, extNwProvType, writeFlowInvTx);
496 private void hndlTepAddForSnatInEachRtr(RoutersList router, long routerId, final BigInteger srcDpnId,
497 String tunnelType, String srcTepIp, String destTepIp, String tunnelName, String nextHopIp,
498 ProviderTypes extNwProvType, TypedReadWriteTransaction<Configuration> writeFlowInvTx) {
500 /*SNAT : Remove the old routes to the external IP having the old TEP IP as the next hop IP
501 Advertise to the BGP about the new route to the external IP having the new TEP IP
502 added as the next hop IP
504 String routerName = router.getRouter();
506 // Check if this is externalRouter else ignore
507 InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
508 Optional<Routers> routerData;
510 routerData = writeFlowInvTx.read(extRoutersId).get();
511 } catch (InterruptedException | ExecutionException e) {
512 LOG.error("Error reading router data for {}", extRoutersId, e);
513 routerData = Optional.absent();
515 if (!routerData.isPresent()) {
516 LOG.warn("hndlTepAddForSnatInEachRtr : SNAT->Ignoring TEP add for router {} since its not External Router",
521 BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
522 if (naptId == null || naptId.equals(BigInteger.ZERO)) {
523 LOG.warn("hndlTepAddForSnatInEachRtr : SNAT -> Ignoring TEP add for the DPN {} having the router {} since"
524 + " the router is not part of the NAT service - the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
525 + "TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
528 if (natMode == NatMode.Conntrack) {
529 natServiceManager.notify(writeFlowInvTx, routerData.get(), naptId, srcDpnId,
530 SnatServiceManager.Action.SNAT_ROUTER_ENBL);
532 Uuid bgpVpnUuId = NatUtil.getVpnForRouter(dataBroker, routerName);
533 //Check if the DPN having the router is the NAPT switch
534 if (!naptId.equals(srcDpnId)) {
536 1) Install default NAT rule from table 21 to 26
537 2) Install the group which forward packet to the tunnel port for the NAPT switch.
538 3) Install the flow 26 which forwards the packet to the group.
540 if (!hndlTepAddOnNonNaptSwitch(srcDpnId, naptId, tunnelType, srcTepIp, destTepIp, tunnelName,
541 routerName, routerId, bgpVpnUuId, writeFlowInvTx)) {
542 LOG.error("hndlTepAddForSnatInEachRtr : Unable to process the TEP add event on NON-NAPT switch {}",
548 if (!hndlTepAddOnNaptSwitch(srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName, routerId,
549 routerData, nextHopIp, bgpVpnUuId, extNwProvType, writeFlowInvTx)) {
550 LOG.debug("hndlTepAddForSnatInEachRtr : Unable to process the TEP add event on NAPT switch {}",
558 private boolean hndlTepAddOnNonNaptSwitch(BigInteger srcDpnId, BigInteger primaryDpnId, String tunnelType,
559 String srcTepIp, String destTepIp, String tunnelName, String routerName, long routerId, Uuid vpnName,
560 TypedWriteTransaction<Configuration> confTx) {
563 1) Install default NAT rule from table 21 to 26
564 2) Install the group which forward packet to the tunnel port for the NAPT switch.
565 3) Install the flow 26 which forwards the packet to the group.
567 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Processing TEP add for the DPN {} having the router {} since "
568 + "its THE NON NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
569 + "and TUNNEL NAME {} ",
570 srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
571 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Install default NAT rule from table 21 to 26");
573 if (vpnName == null) {
574 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Internal VPN associated to router {}", routerId);
576 if (vpnId == NatConstants.INVALID_ID) {
577 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid Internal VPN ID returned for routerName {}",
581 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerName);
582 //Install default entry in FIB to SNAT table
583 LOG.debug("hndlTepAddOnNonNaptSwitch : Installing default route in FIB on DPN {} for router {} with"
584 + " vpn {}...", srcDpnId, routerName, vpnId);
585 defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, confTx);
587 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Install the group which forward packet to the tunnel port "
588 + "for the NAPT switch {} and the flow 26 which forwards to group", primaryDpnId);
589 externalRouterListner.handleSwitches(srcDpnId, routerName, routerId, primaryDpnId);
591 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> External BGP VPN (Private BGP) associated to router {}",
593 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
594 if (vpnId == NatConstants.INVALID_ID) {
595 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid Private BGP VPN ID returned for routerName {}",
599 if (routerId == NatConstants.INVALID_ID) {
600 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid routId returned for routerName {}", routerId);
603 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
604 //Install default entry in FIB to SNAT table
605 LOG.debug("hndlTepAddOnNonNaptSwitch : Installing default route in FIB on dpn {} for routerId {} "
606 + "with vpnId {}...", srcDpnId, routerId, vpnId);
607 defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, routerId, confTx);
609 LOG.debug("hndlTepAddOnNonNaptSwitch : Install group in non NAPT switch {} for router {}",
610 srcDpnId, routerName);
611 List<BucketInfo> bucketInfoForNonNaptSwitches =
612 externalRouterListner.getBucketInfoForNonNaptSwitches(srcDpnId, primaryDpnId, routerName, routerId);
613 long groupId = externalRouterListner.installGroup(srcDpnId, routerName, bucketInfoForNonNaptSwitches);
615 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> in the SNAT miss entry pointing to group {} "
616 + "in the non NAPT switch {}", groupId, srcDpnId);
617 FlowEntity flowEntity =
618 externalRouterListner.buildSnatFlowEntityWithUpdatedVpnId(srcDpnId, routerName, groupId, vpnId);
619 mdsalManager.addFlow(confTx, flowEntity);
624 private boolean hndlTepAddOnNaptSwitch(BigInteger srcDpnId, String tunnelType, String srcTepIp,
625 String destTepIp, String tunnelName, long routerId,
626 Optional<Routers> routerData, String nextHopIp, Uuid vpnName,
627 ProviderTypes extNwProvType, TypedWriteTransaction<Configuration> confTx) {
628 if (!routerData.isPresent()) {
629 LOG.warn("hndlTepAddOnNaptSwitch: routerData is not present");
632 Routers router = routerData.get();
633 String routerName = router.getRouterName();
634 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Processing TEP add for the DPN {} having the router {} since "
635 + "its THE NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
636 + "and TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
638 Uuid networkId = router.getNetworkId();
639 if (networkId == null) {
640 LOG.warn("hndlTepAddOnNaptSwitch : SNAT -> Ignoring TEP add since the router {} is not associated to the "
641 + "external network", routerName);
645 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Router {} is associated with Ext nw {}", routerId, networkId);
647 if (vpnName == null) {
648 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Internal VPN associated to router {}", routerId);
649 vpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
650 if (vpnId == NatConstants.INVALID_ID) {
651 LOG.error("hndlTepAddOnNaptSwitch : Invalid External VPN-ID returned for routerName {}", routerName);
654 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Retrieved External VPN-ID {} for router {}", vpnId, routerId);
656 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Private BGP VPN associated to router {}", routerId);
657 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
658 if (vpnId == null || vpnId == NatConstants.INVALID_ID) {
659 LOG.error("hndlTepAddOnNaptSwitch : Invalid vpnId returned for routerName {}", routerName);
662 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
665 /*1) Withdraw the old route to the external IP from the BGP which was having the
666 next hop as the old TEP IP.
667 2) Advertise to the BGP about the new route to the external IP having the
668 new TEP IP as the next hop.
669 3) Populate a new FIB entry with the next hop IP as the new TEP IP using the
673 //Withdraw the old route to the external IP from the BGP which was having the
674 //next hop as the old TEP IP.
675 final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
676 if (externalVpnName == null) {
677 LOG.error("hndlTepAddOnNaptSwitch : SNAT -> No VPN associated with ext nw {} in router {}",
678 networkId, routerId);
681 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
682 LOG.debug("hndlTepAddOnNaptSwitch : Clearing the FIB entries but not the BGP routes");
683 for (String externalIp : externalIps) {
684 String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
685 LOG.debug("hndlTepAddOnNaptSwitch : Removing Fib entry rd {} prefix {}", rd, externalIp);
686 fibManager.removeFibEntry(rd, externalIp, null);
690 Advertise to the BGP about the new route to the external IP having the
691 new TEP IP as the next hop.
692 Populate a new FIB entry with the next hop IP as the new TEP IP using the
695 String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
696 if (extNwProvType == null) {
699 String gwMacAddress = null;
701 if (extNwProvType == ProviderTypes.VXLAN) {
702 // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
703 gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
704 if (gwMacAddress != null) {
705 LOG.debug("hndlTepAddOnNaptSwitch : External Gateway MAC address {} found for External Router ID {}",
706 gwMacAddress, routerId);
708 LOG.error("hndlTepAddOnNaptSwitch : No External Gateway MAC address found for External Router ID {}",
712 //get l3Vni value for external VPN
713 l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
714 if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
715 LOG.debug("hndlTepAddOnNaptSwitch : L3VNI value is not configured in Internet VPN {} and RD {} "
716 + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
717 + "NAT flows", vpnName, rd);
718 l3Vni = NatOverVxlanUtil.getInternetVpnVni(idManager, externalVpnName, routerId).longValue();
722 for (final String externalIp : externalIps) {
724 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
725 if (extNwProvType == ProviderTypes.VXLAN) {
726 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Advertise the route to the externalIp {} "
727 + "having nextHopIp {}", externalIp, nextHopIp);
728 NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, externalVpnName, rd,
729 externalIp, nextHopIp, l3Vni, tunnelName, gwMacAddress, confTx, RouteOrigin.STATIC,
730 srcDpnId, networkId);
734 Long label = externalRouterListner.checkExternalIpLabel(routerId,
736 if (label == null || label == NatConstants.INVALID_ID) {
737 LOG.error("hndlTepAddOnNaptSwitch : SNAT->Unable to advertise to the DC GW "
738 + "since label is invalid");
741 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Advertise the route to the externalIp {} "
742 + "having nextHopIp {}", externalIp, nextHopIp);
744 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
745 l3vni = NatOverVxlanUtil.getInternetVpnVni(idManager, externalVpnName, l3vni).longValue();
747 Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(externalIp, router);
748 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, externalVpnName, rd, externalSubnetId,
749 fibExternalIp, nextHopIp, networkId.getValue(), null /* mac-address */, label, l3vni,
750 RouteOrigin.STATIC, srcDpnId);
754 LOG.debug("hndlTepAddOnNaptSwitch: SNAT -> Install custom FIB routes "
755 + "(Table 21 -> Push MPLS label to Tunnel port");
756 List<Instruction> customInstructions = new ArrayList<>();
757 int customInstructionIndex = 0;
758 long externalSubnetVpnId = NatUtil.getExternalSubnetVpnIdForRouterExternalIp(dataBroker, externalIp,
760 if (externalSubnetVpnId != NatConstants.INVALID_ID) {
761 LOG.debug("hndlTepAddOnNaptSwitch : Will install custom FIB router with external subnet VPN ID {}",
762 externalSubnetVpnId);
763 BigInteger subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(externalSubnetVpnId);
764 customInstructions.add(new InstructionWriteMetadata(subnetIdMetaData,
765 MetaDataUtil.METADATA_MASK_VRFID).buildInstruction(customInstructionIndex));
766 customInstructionIndex++;
768 customInstructions.add(new InstructionGotoTable(NwConstants.INBOUND_NAPT_TABLE)
769 .buildInstruction(customInstructionIndex));
770 CreateFibEntryInput input =
771 new CreateFibEntryInputBuilder().setVpnName(externalVpnName).setSourceDpid(srcDpnId)
772 .setInstruction(customInstructions).setIpAddress(fibExternalIp)
773 .setIpAddressSource(FibEntryInputs.IpAddressSource.ExternalFixedIP)
774 .setServiceId(serviceId).setInstruction(customInstructions).build();
775 ListenableFuture<RpcResult<CreateFibEntryOutput>> listenableFuture = fibRpcService.createFibEntry(input);
777 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
780 public void onFailure(@Nonnull Throwable error) {
781 LOG.error("hndlTepAddOnNaptSwitch : SNAT->Error in generate label or fib install process",
786 public void onSuccess(@Nonnull RpcResult<CreateFibEntryOutput> result) {
787 if (result.isSuccessful()) {
788 LOG.info("hndlTepAddOnNaptSwitch : SNAT -> Successfully installed custom FIB routes "
789 + "for prefix {}", externalIp);
791 LOG.error("hndlTepAddOnNaptSwitch : SNAT -> Error in rpc call to create custom Fib entries "
792 + "for prefix {} in DPN {}, {}", externalIp, srcDpnId, result.getErrors());
795 }, MoreExecutors.directExecutor());
801 private void hndlTepAddForDnatInEachRtr(RoutersList router, long routerId, String nextHopIp,
802 BigInteger tepAddedDpnId, ProviderTypes extNwProvType, TypedWriteTransaction<Configuration> confTx) {
803 //DNAT : Advertise the new route to the floating IP having the new TEP IP as the next hop IP
804 final String routerName = router.getRouter();
806 InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
807 Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType
808 .CONFIGURATION, routerPortsId);
809 if (!optRouterPorts.isPresent()) {
810 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Could not read Router Ports data object with id: {} "
811 + "from DNAT FloatinIpInfo", routerName);
814 RouterPorts routerPorts = optRouterPorts.get();
815 Uuid extNwId = routerPorts.getExternalNetworkId();
816 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId);
817 if (vpnName == null) {
818 LOG.info("hndlTepAddForDnatInEachRtr : DNAT -> No External VPN associated with ext nw {} for router {}",
819 extNwId, routerName);
823 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
824 if (extNwProvType == null) {
827 String gwMacAddress = null;
829 if (extNwProvType == ProviderTypes.VXLAN) {
830 // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
831 gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
832 if (gwMacAddress != null) {
833 LOG.debug("hndlTepAddForDnatInEachRtr : External GwMAC address {} found for External Router ID {}",
834 gwMacAddress, routerId);
836 LOG.error("hndlTepAddForDnatInEachRtr : No External GwMAC address found for External Router ID {}",
840 //get l3Vni value for external VPN
841 l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
842 if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
843 LOG.debug("hndlTepAddForDnatInEachRtr : L3VNI value is not configured in Internet VPN {} and RD {} "
844 + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
845 + "NAT flows", vpnName, rd);
846 l3Vni = NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, routerId).longValue();
849 List<Ports> interfaces = routerPorts.getPorts();
850 for (Ports port : interfaces) {
851 //Get the DPN on which this interface resides
852 final String interfaceName = port.getPortName();
853 final BigInteger fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
854 if (fipCfgdDpnId.equals(BigInteger.ZERO)) {
855 LOG.info("hndlTepAddForDnatInEachRtr : DNAT->Skip processing Floating ip configuration for the port {},"
856 + "since no DPN present for it", interfaceName);
859 if (!fipCfgdDpnId.equals(tepAddedDpnId)) {
860 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> TEP added DPN {} is not the DPN {} which has the "
861 + "floating IP configured for the port: {}",
862 tepAddedDpnId, fipCfgdDpnId, interfaceName);
865 List<InternalToExternalPortMap> intExtPortMapList = port.getInternalToExternalPortMap();
866 for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) {
867 final String internalIp = intExtPortMap.getInternalIp();
868 final String externalIp = intExtPortMap.getExternalIp();
869 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertising the FIB route to the floating IP {} "
870 + "configured for the port: {}", externalIp, interfaceName);
872 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
874 if (extNwProvType == ProviderTypes.VXLAN) {
875 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertise the route to the externalIp {} "
876 + "having nextHopIp {}", externalIp, nextHopIp);
877 NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, vpnName, rd,
878 externalIp, nextHopIp, l3Vni, interfaceName, gwMacAddress, confTx, RouteOrigin.STATIC,
879 fipCfgdDpnId, extNwId);
882 long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
883 if (label == NatConstants.INVALID_ID) {
884 LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Unable to advertise to the DC GW since label "
888 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertise the route to the externalIp {} "
889 + "having nextHopIp {}", externalIp, nextHopIp);
891 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
892 l3vni = NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, l3vni).longValue();
894 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd, null,
895 fibExternalIp, nextHopIp, null, null, label, l3vni, RouteOrigin.STATIC,
900 //Install custom FIB routes (Table 21 -> Push MPLS label to Tunnel port
901 List<Instruction> customInstructions = new ArrayList<>();
902 customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(0));
903 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
904 .setSourceDpid(fipCfgdDpnId).setInstruction(customInstructions)
905 .setIpAddressSource(FibEntryInputs.IpAddressSource.FloatingIP)
906 .setIpAddress(fibExternalIp).setServiceId(serviceId).setInstruction(customInstructions)
908 ListenableFuture<RpcResult<CreateFibEntryOutput>> listenableFuture =
909 fibRpcService.createFibEntry(input);
911 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
914 public void onFailure(@Nonnull Throwable error) {
915 LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Error in generate label or fib install process",
920 public void onSuccess(@Nonnull RpcResult<CreateFibEntryOutput> result) {
921 if (result.isSuccessful()) {
922 LOG.info("hndlTepAddForDnatInEachRtr : DNAT -> Successfully installed custom FIB routes "
923 + "for prefix {}", externalIp);
925 LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Error in rpc call to create custom Fib "
926 + "entries for prefix {} in DPN {}, {}", externalIp, fipCfgdDpnId, result.getErrors());
929 }, MoreExecutors.directExecutor());
934 private void hndlTepDelForSnatInEachRtr(RoutersList router, long routerId, BigInteger dpnId, String tunnelType,
935 String srcTepIp, String destTepIp, String tunnelName, ProviderTypes extNwProvType,
936 TypedReadWriteTransaction<Configuration> confTx) {
938 1) Elect a new switch as the primary NAPT
939 2) Advertise the new routes to BGP for the newly elected TEP IP as the DPN IP
940 3) This will make sure old routes are withdrawn and new routes are advertised.
943 String routerName = router.getRouter();
944 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Trying to clear routes to the External fixed IP associated "
945 + "to the router {}", routerName);
947 // Check if this is externalRouter else ignore
948 InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
949 Optional<Routers> routerData;
951 routerData = confTx.read(extRoutersId).get();
952 } catch (InterruptedException | ExecutionException e) {
953 LOG.error("Error retrieving routers {}", extRoutersId, e);
954 routerData = Optional.absent();
956 if (!routerData.isPresent()) {
957 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Ignoring TEP del for router {} since its not External Router",
962 //Check if the DPN having the router is the NAPT switch
963 BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
964 if (naptId == null || naptId.equals(BigInteger.ZERO) || !naptId.equals(dpnId)) {
965 LOG.warn("hndlTepDelForSnatInEachRtr : SNAT -> Ignoring TEP delete for the DPN {} since"
966 + " its NOT a NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
967 + "TUNNEL NAME {} ", dpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
970 if (natMode == NatMode.Conntrack) {
971 natServiceManager.notify(confTx, routerData.get(), naptId, dpnId,
972 SnatServiceManager.Action.SNAT_ROUTER_DISBL);
976 Uuid networkId = routerData.get().getNetworkId();
977 if (networkId == null) {
978 LOG.error("hndlTepDelForSnatInEachRtr : SNAT->Ignoring TEP delete for the DPN {} having the router {} "
979 + "since the Router instance {} not found in ExtRouters model b/w SRC IP {} and DST "
980 + "IP {} and TUNNEL NAME {} ", dpnId, routerData.get().getRouterName(), tunnelType,
981 srcTepIp, destTepIp, tunnelName);
985 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Router {} is associated with ext nw {}", routerId, networkId);
986 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
988 if (bgpVpnUuid == null) {
989 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Internal VPN-ID {} associated to router {}",
990 routerId, routerName);
993 //Install default entry in FIB to SNAT table
994 LOG.debug("hndlTepDelForSnatInEachRtr : Installing default route in FIB on DPN {} for router {} with"
995 + " vpn {}...", dpnId, routerName, bgpVpnId);
996 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, confTx);
998 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
999 if (bgpVpnId == NatConstants.INVALID_ID) {
1000 LOG.error("hndlTepDelForSnatInEachRtr :SNAT->Invalid Private BGP VPN ID returned for routerName {}",
1004 LOG.debug("hndlTepDelForSnatInEachRtr :SNAT->External BGP VPN (Private BGP) {} associated to router {}",
1005 bgpVpnId, routerName);
1006 //Install default entry in FIB to SNAT table
1007 LOG.debug("hndlTepDelForSnatInEachRtr : Installing default route in FIB on dpn {} for routerId {} "
1008 + "with vpnId {}...", dpnId, routerId, bgpVpnId);
1009 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, routerId, confTx);
1012 if (routerData.get().isEnableSnat()) {
1013 LOG.info("hndlTepDelForSnatInEachRtr : SNAT enabled for router {}", routerId);
1015 long routerVpnId = routerId;
1016 if (bgpVpnId != NatConstants.INVALID_ID) {
1017 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Private BGP VPN ID (Internal BGP VPN ID) {} "
1018 + "associated to the router {}", bgpVpnId, routerName);
1019 routerVpnId = bgpVpnId;
1021 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Internal L3 VPN ID (Router ID) {} "
1022 + "associated to the router {}", routerVpnId, routerName);
1024 //Re-elect the other available switch as the NAPT switch and program the NAT flows.
1025 removeSNATFromDPN(dpnId, routerName, routerId, routerVpnId, networkId, extNwProvType, confTx);
1027 LOG.info("hndlTepDelForSnatInEachRtr : SNAT is not enabled for router {} to handle addDPN event {}",
1033 private void hndlTepDelForDnatInEachRtr(RoutersList router, long routerId, BigInteger tepDeletedDpnId,
1034 ProviderTypes extNwProvType) {
1035 //DNAT : Withdraw the routes from the BGP
1036 String routerName = router.getRouter();
1038 LOG.debug("hndlTepDelForDnatInEachRtr : DNAT -> Trying to clear routes to the Floating IP "
1039 + "associated to the router {}", routerName);
1041 InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
1042 Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType
1043 .CONFIGURATION, routerPortsId);
1044 if (!optRouterPorts.isPresent()) {
1045 LOG.debug("hndlTepDelForDnatInEachRtr : DNAT -> Could not read Router Ports data object with id: {} "
1046 + "from DNAT FloatingIpInfo", routerName);
1049 RouterPorts routerPorts = optRouterPorts.get();
1050 Uuid extNwId = routerPorts.getExternalNetworkId();
1051 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId);
1052 if (vpnName == null) {
1053 LOG.error("hndlTepDelForDnatInEachRtr : DNAT -> No External VPN associated with Ext N/W {} for Router {}",
1054 extNwId, routerName);
1057 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
1058 if (extNwProvType == null) {
1062 if (extNwProvType == ProviderTypes.VXLAN) {
1063 //get l3Vni value for external VPN
1064 l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
1065 if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
1066 LOG.debug("hndlTepDelForDnatInEachRtr : L3VNI value is not configured in Internet VPN {} and RD {} "
1067 + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
1068 + "NAT flows", vpnName, rd);
1069 l3Vni = NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, routerId).longValue();
1072 List<Ports> interfaces = routerPorts.getPorts();
1073 for (Ports port : interfaces) {
1074 //Get the DPN on which this interface resides
1075 String interfaceName = port.getPortName();
1076 BigInteger fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
1077 if (fipCfgdDpnId.equals(BigInteger.ZERO)) {
1078 LOG.info("hndlTepDelForDnatInEachRtr : DNAT -> Abort processing Floating ip configuration. "
1079 + "No DPN for port : {}", interfaceName);
1082 if (!fipCfgdDpnId.equals(tepDeletedDpnId)) {
1083 LOG.info("hndlTepDelForDnatInEachRtr : DNAT -> TEP deleted DPN {} is not the DPN {} which has the "
1084 + "floating IP configured for the port: {}",
1085 tepDeletedDpnId, fipCfgdDpnId, interfaceName);
1088 List<InternalToExternalPortMap> intExtPortMapList = port.getInternalToExternalPortMap();
1089 for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) {
1090 String internalIp = intExtPortMap.getInternalIp();
1091 String externalIp = intExtPortMap.getExternalIp();
1092 externalIp = NatUtil.validateAndAddNetworkMask(externalIp);
1093 LOG.debug("hndlTepDelForDnatInEachRtr : DNAT -> Withdrawing the FIB route to the floating IP {} "
1094 + "configured for the port: {}",
1095 externalIp, interfaceName);
1096 NatUtil.removePrefixFromBGP(bgpManager, fibManager, rd, externalIp, vpnName, LOG);
1098 if (extNwProvType == ProviderTypes.VXLAN) {
1101 long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
1102 if (label == NatConstants.INVALID_ID) {
1103 LOG.error("hndlTepDelForDnatInEachRtr : DNAT -> Unable to remove the table 21 entry pushing the"
1104 + " MPLS label to the tunnel since label is invalid");
1110 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
1111 .setSourceDpid(fipCfgdDpnId).setIpAddress(externalIp).setServiceId(serviceId)
1112 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.FloatingIP).build();
1113 ListenableFuture<RpcResult<RemoveFibEntryOutput>> listenableFuture =
1114 fibRpcService.removeFibEntry(input);
1116 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<RemoveFibEntryOutput>>() {
1119 public void onFailure(@Nonnull Throwable error) {
1120 LOG.error("hndlTepDelForDnatInEachRtr : DNAT -> Error in removing the table 21 entry pushing "
1121 + "the MPLS label to the tunnel since label is invalid ", error);
1125 public void onSuccess(@Nonnull RpcResult<RemoveFibEntryOutput> result) {
1126 if (result.isSuccessful()) {
1127 LOG.info("hndlTepDelForDnatInEachRtr : DNAT -> Successfully removed the entry pushing the "
1128 + "MPLS label to the tunnel");
1130 LOG.error("hndlTepDelForDnatInEachRtr : DNAT -> Error in fib rpc call to remove the table "
1131 + "21 entry pushing the MPLS label to the tunnnel due to {}", result.getErrors());
1134 }, MoreExecutors.directExecutor());
1139 protected boolean isTunnelInLogicalGroup(StateTunnelList stateTunnelList) {
1140 String ifaceName = stateTunnelList.getTunnelInterfaceName();
1141 if (getTunnelType(stateTunnelList) == NatConstants.ITMTunnelLocType.Internal.getValue()) {
1142 Interface configIface = interfaceManager.getInterfaceInfoFromConfigDataStore(ifaceName);
1143 IfTunnel ifTunnel = configIface != null ? configIface.augmentation(IfTunnel.class) : null;
1144 if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) {
1145 ParentRefs refs = configIface.augmentation(ParentRefs.class);
1146 if (refs != null && !Strings.isNullOrEmpty(refs.getParentInterface())) {
1147 return true; //multiple VxLAN tunnels enabled, i.e. only logical tunnel should be treated
1151 LOG.trace("isTunnelInLogicalGroup: ignoring the tunnel event for {}", ifaceName);