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.mdsal.binding.util.Datastore.CONFIGURATION;
13 import com.google.common.base.Strings;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import com.google.common.util.concurrent.MoreExecutors;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.List;
22 import java.util.Optional;
23 import java.util.concurrent.ExecutionException;
24 import javax.annotation.PreDestroy;
25 import javax.inject.Inject;
26 import javax.inject.Singleton;
27 import org.eclipse.jdt.annotation.NonNull;
28 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
29 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
30 import org.opendaylight.genius.mdsalutil.BucketInfo;
31 import org.opendaylight.genius.mdsalutil.FlowEntity;
32 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
33 import org.opendaylight.genius.mdsalutil.NwConstants;
34 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
35 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
36 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
37 import org.opendaylight.infrautils.utils.concurrent.Executors;
38 import org.opendaylight.mdsal.binding.api.DataBroker;
39 import org.opendaylight.mdsal.binding.util.Datastore.Configuration;
40 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
41 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
42 import org.opendaylight.mdsal.binding.util.TypedReadWriteTransaction;
43 import org.opendaylight.mdsal.binding.util.TypedWriteTransaction;
44 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
45 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
46 import org.opendaylight.netvirt.elanmanager.api.IElanService;
47 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
48 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
49 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
50 import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryOutput;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibEntryInputs;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersList;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.dpn.routers.list.RoutersList;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.dpn.routers.list.RoutersListKey;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
79 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
80 import org.opendaylight.yangtools.yang.common.RpcResult;
81 import org.opendaylight.yangtools.yang.common.Uint32;
82 import org.opendaylight.yangtools.yang.common.Uint64;
83 import org.slf4j.Logger;
84 import org.slf4j.LoggerFactory;
87 public class NatTunnelInterfaceStateListener extends AbstractAsyncDataTreeChangeListener<StateTunnelList> {
89 private static final Logger LOG = LoggerFactory.getLogger(NatTunnelInterfaceStateListener.class);
90 private final DataBroker dataBroker;
91 private final ManagedNewTransactionRunner txRunner;
92 private final IFibManager fibManager;
93 private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
94 private final NaptSwitchHA naptSwitchHA;
95 private final IMdsalApiManager mdsalManager;
96 private final IdManagerService idManager;
97 private final IBgpManager bgpManager;
98 private final ExternalRoutersListener externalRouterListner;
99 private final SnatServiceManager natServiceManager;
100 private final OdlInterfaceRpcService interfaceService;
101 private final FloatingIPListener floatingIPListener;
102 private final FibRpcService fibRpcService;
103 private final IElanService elanManager;
104 private final IInterfaceManager interfaceManager;
105 private final NatOverVxlanUtil natOverVxlanUtil;
106 private final NatMode natMode;
108 protected enum TunnelAction {
115 * Responsible for listening to tunnel interface state change.
117 * @param dataBroker - dataBroker service reference
118 * @param bgpManager Used to advertise routes to the BGP Router
119 * @param fibManager - FIB Manager
120 * @param defaultRouteProgrammer - Default Route Programmer
121 * @param naptSwitchHA - NAPT Switch HA
122 * @param mdsalManager - MDSAL Manager
123 * @param idManager - ID manager
124 * @param externalRouterListner - External Router Listener
125 * @param natServiceManager - Nat Service Manager
126 * @param interfaceService - Interface Service
127 * @param floatingIPListener - Floating IP Listener
128 * @param fibRpcService - FIB RPC Service
129 * @param config - Nat Service Config
130 * @param elanManager - Elan Manager
131 * @param interfaceManager - Interface Manager
132 * @param natOverVxlanUtils - Nat Over Vxlan Utility
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 final NatOverVxlanUtil natOverVxlanUtils) {
151 super(dataBroker, LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(TunnelsState.class)
152 .child(StateTunnelList.class),
153 Executors.newListeningSingleThreadExecutor("NatTunnelInterfaceStateListener", LOG));
154 this.dataBroker = dataBroker;
155 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
156 this.bgpManager = bgpManager;
157 this.fibManager = fibManager;
158 this.defaultRouteProgrammer = defaultRouteProgrammer;
159 this.naptSwitchHA = naptSwitchHA;
160 this.mdsalManager = mdsalManager;
161 this.idManager = idManager;
162 this.externalRouterListner = externalRouterListner;
163 this.natServiceManager = natServiceManager;
164 this.interfaceService = interfaceService;
165 this.floatingIPListener = floatingIPListener;
166 this.fibRpcService = fibRpcService;
167 this.elanManager = elanManager;
168 this.interfaceManager = interfaceManager;
169 this.natOverVxlanUtil = natOverVxlanUtils;
170 if (config != null) {
171 this.natMode = config.getNatMode();
173 this.natMode = NatMode.Controller;
178 LOG.info("{} init", getClass().getSimpleName());
183 public void close() {
185 Executors.shutdownAndAwaitTermination(getExecutorService());
189 public void add(InstanceIdentifier<StateTunnelList> instanceIdentifier, StateTunnelList add) {
190 LOG.trace("add : TEP addtion---- {}", add);
191 hndlTepEvntsForDpn(add, TunnelAction.TUNNEL_EP_ADD);
195 public void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
196 LOG.trace("remove : TEP deletion---- {}", del);
197 // Moved the remove implementation logic to NatTepChangeLister.remove()
201 public void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original,
202 StateTunnelList update) {
203 LOG.trace("update : Tunnel updation---- {}", update);
204 //UPDATE IS A SEQUENCE OF DELETE AND ADD EVENTS . DELETE MIGHT HAVE CHANGED THE PRIMARY AND ADVERTISED. SO
208 private int getTunnelType(StateTunnelList stateTunnelList) {
210 if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
211 tunTypeVal = NatConstants.ITMTunnelLocType.Internal.getValue();
212 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
213 tunTypeVal = NatConstants.ITMTunnelLocType.External.getValue();
214 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
215 tunTypeVal = NatConstants.ITMTunnelLocType.Hwvtep.getValue();
217 tunTypeVal = NatConstants.ITMTunnelLocType.Invalid.getValue();
222 private void hndlTepEvntsForDpn(StateTunnelList stateTunnelList, TunnelAction tunnelAction) {
223 LOG.trace("hndlTepEvntsForDpn : stateTunnelList {}", stateTunnelList);
224 final Uint64 srcDpnId = stateTunnelList.getSrcInfo() != null
225 ? Uint64.valueOf(stateTunnelList.getSrcInfo().getTepDeviceId()) : Uint64.ZERO;
226 final String srcTepIp = stateTunnelList.getSrcInfo() != null
227 ? stateTunnelList.getSrcInfo().getTepIp().stringValue() : null;
228 final String destTepIp = stateTunnelList.getDstInfo() != null
229 ? stateTunnelList.getDstInfo().getTepIp().stringValue() : null;
230 LOG.trace("hndlTepEvntsForDpn : Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ",
231 srcDpnId, srcTepIp, destTepIp);
232 if (srcDpnId == Uint64.ZERO || srcTepIp == null || destTepIp == null) {
233 LOG.error("hndlTepEvntsForDpn invalid srcDpnId {}, srcTepIp {}, destTepIp {}",
234 srcDpnId, srcTepIp, destTepIp);
237 int tunTypeVal = getTunnelType(stateTunnelList);
238 LOG.trace("hndlTepEvntsForDpn : tunTypeVal is {}", tunTypeVal);
239 String srcTepId = stateTunnelList.getSrcInfo().getTepDeviceId() != null
240 ? stateTunnelList.getSrcInfo().getTepDeviceId() : "0";
241 String tunnelType = stateTunnelList.getTransportType() != null
242 ? stateTunnelList.getTransportType().toString() : null;
243 String tunnelName = stateTunnelList.getTunnelInterfaceName();
245 if (tunTypeVal == NatConstants.ITMTunnelLocType.Invalid.getValue() || srcDpnId.equals(Uint64.ZERO)
246 || srcTepIp == null || destTepIp == null) {
247 LOG.warn("hndlTepEvntsForDpn : Ignoring TEP event {} for the DPN {} "
248 + "since its a INVALID TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and " + "TUNNEL NAME {} ",
249 tunnelAction, srcTepId, tunnelType, srcTepIp, destTepIp, tunnelName);
253 switch (tunnelAction) {
256 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
257 if (isTunnelInLogicalGroup(stateTunnelList)
258 || !hndlTepAddForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp,
260 LOG.debug("hndlTepEvntsForDpn : Unable to process TEP ADD");
263 } catch (InterruptedException | ExecutionException e) {
264 LOG.error("Error processing tunnel endpoint addition", e);
267 case TUNNEL_EP_DELETE:
268 // Moved the current implementation logic to NatTepChangeListener.remove()
270 case TUNNEL_EP_UPDATE:
273 LOG.warn("hndlTepEvntsForDpn: unknown tunnelAction: {}", tunnelAction);
278 private boolean hndlTepAddForAllRtrs(Uint64 srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
279 String destTepIp, TypedReadWriteTransaction<Configuration> writeFlowInvTx)
280 throws ExecutionException, InterruptedException {
281 LOG.trace("hndlTepAddForAllRtrs: TEP ADD ----- for EXTERNAL/HWVTEP ITM Tunnel, TYPE {} ,State is UP b/w SRC IP"
282 + " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
284 InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
285 Optional<DpnRoutersList> optionalRouterDpnList =
286 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
287 LogicalDatastoreType.OPERATIONAL, dpnRoutersListId);
288 if (!optionalRouterDpnList.isPresent()) {
289 LOG.info("hndlTepAddForAllRtrs : RouterDpnList model is empty for DPN {}. Hence ignoring TEP add event "
290 + "for the ITM TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ",
291 srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
295 Map<RoutersListKey, RoutersList> keyRoutersListMap = optionalRouterDpnList.get().getRoutersList();
296 if (keyRoutersListMap == null) {
297 LOG.debug("hndlTepAddForAllRtrs : Ignoring TEP add for the DPN {} since no routers are associated"
298 + " for the DPN having the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
299 + "TUNNEL NAME {} ", srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
303 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
304 for (RoutersList router : keyRoutersListMap.values()) {
305 String routerName = router.getRouter();
306 Uint32 routerId = NatUtil.getVpnId(dataBroker, routerName);
307 if (routerId == NatConstants.INVALID_ID) {
308 LOG.error("hndlTepAddForAllRtrs :Invalid ROUTER-ID {} returned for routerName {}",
309 routerId, routerName);
312 LOG.debug("hndlTepAddForAllRtrs : TEP ADD : DNAT -> Advertising routes for router {} ", routerName);
313 Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
314 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
315 routerName, externalNetworkId);
316 if (extNwProvType == null) {
319 hndlTepAddForDnatInEachRtr(router, routerId, nextHopIp, srcDpnId, extNwProvType, writeFlowInvTx);
321 LOG.debug("hndlTepAddForAllRtrs : TEP ADD : SNAT -> Advertising routes for router {} ", routerName);
322 hndlTepAddForSnatInEachRtr(router, routerId, srcDpnId, tunnelType, srcTepIp, destTepIp,
323 tunnelName, nextHopIp, extNwProvType, writeFlowInvTx);
328 private void hndlTepAddForSnatInEachRtr(RoutersList router, Uint32 routerId, final Uint64 srcDpnId,
329 String tunnelType, String srcTepIp, String destTepIp, String tunnelName, String nextHopIp,
330 ProviderTypes extNwProvType, TypedReadWriteTransaction<Configuration> writeFlowInvTx)
331 throws ExecutionException, InterruptedException {
333 /*SNAT : Remove the old routes to the external IP having the old TEP IP as the next hop IP
334 Advertise to the BGP about the new route to the external IP having the new TEP IP
335 added as the next hop IP
337 String routerName = router.getRouter();
339 // Check if this is externalRouter else ignore
340 InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
341 Optional<Routers> routerData;
343 routerData = writeFlowInvTx.read(extRoutersId).get();
344 } catch (InterruptedException | ExecutionException e) {
345 LOG.error("Error reading router data for {}", extRoutersId, e);
346 routerData = Optional.empty();
348 if (!routerData.isPresent()) {
349 LOG.warn("hndlTepAddForSnatInEachRtr : SNAT->Ignoring TEP add for router {} since its not External Router",
354 Uint64 naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
355 if (naptId == null || naptId.equals(Uint64.ZERO)) {
356 LOG.warn("hndlTepAddForSnatInEachRtr : SNAT -> Ignoring TEP add for the DPN {} having the router {} since"
357 + " the router is not part of the NAT service - the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
358 + "TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
361 if (natMode == NatMode.Conntrack) {
362 Routers extRouter = routerData.get();
363 natServiceManager.notify(writeFlowInvTx, extRouter, null, naptId, srcDpnId,
364 SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_ENBL);
365 if (extRouter.isEnableSnat()) {
366 natServiceManager.notify(writeFlowInvTx, extRouter, null, naptId, srcDpnId,
367 SnatServiceManager.Action.SNAT_ROUTER_ENBL);
370 Uuid bgpVpnUuId = NatUtil.getVpnForRouter(dataBroker, routerName);
371 //Check if the DPN having the router is the NAPT switch
372 if (!naptId.equals(srcDpnId)) {
374 1) Install default NAT rule from table 21 to 26
375 2) Install the group which forward packet to the tunnel port for the NAPT switch.
376 3) Install the flow 26 which forwards the packet to the group.
378 if (!hndlTepAddOnNonNaptSwitch(srcDpnId, naptId, tunnelType, srcTepIp, destTepIp, tunnelName,
379 routerName, routerId, bgpVpnUuId, writeFlowInvTx)) {
380 LOG.error("hndlTepAddForSnatInEachRtr : Unable to process the TEP add event on NON-NAPT switch {}",
386 if (!hndlTepAddOnNaptSwitch(srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName, routerId,
387 routerData, nextHopIp, bgpVpnUuId, extNwProvType, writeFlowInvTx)) {
388 LOG.debug("hndlTepAddForSnatInEachRtr : Unable to process the TEP add event on NAPT switch {}",
396 private boolean hndlTepAddOnNonNaptSwitch(Uint64 srcDpnId, Uint64 primaryDpnId, String tunnelType,
397 String srcTepIp, String destTepIp, String tunnelName, String routerName, Uint32 routerId, Uuid vpnName,
398 TypedWriteTransaction<Configuration> confTx) {
401 1) Install default NAT rule from table 21 to 26
402 2) Install the group which forward packet to the tunnel port for the NAPT switch.
403 3) Install the flow 26 which forwards the packet to the group.
405 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Processing TEP add for the DPN {} having the router {} since "
406 + "its THE NON NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
407 + "and TUNNEL NAME {} ",
408 srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
409 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Install default NAT rule from table 21 to 26");
411 if (vpnName == null) {
412 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Internal VPN associated to router {}", routerId);
414 if (vpnId == NatConstants.INVALID_ID) {
415 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid Internal VPN ID returned for routerName {}",
419 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerName);
420 //Install default entry in FIB to SNAT table
421 LOG.debug("hndlTepAddOnNonNaptSwitch : Installing default route in FIB on DPN {} for router {} with"
422 + " vpn {}...", srcDpnId, routerName, vpnId);
423 defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, confTx);
425 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Install the group which forward packet to the tunnel port "
426 + "for the NAPT switch {} and the flow 26 which forwards to group", primaryDpnId);
427 externalRouterListner.handleSwitches(srcDpnId, routerName, routerId, primaryDpnId);
429 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> External BGP VPN (Private BGP) associated to router {}",
431 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
432 if (vpnId == NatConstants.INVALID_ID) {
433 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid Private BGP VPN ID returned for routerName {}",
437 if (routerId == NatConstants.INVALID_ID) {
438 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid routId returned for routerName {}", routerId);
441 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
442 //Install default entry in FIB to SNAT table
443 LOG.debug("hndlTepAddOnNonNaptSwitch : Installing default route in FIB on dpn {} for routerId {} "
444 + "with vpnId {}...", srcDpnId, routerId, vpnId);
445 defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, routerId, confTx);
447 LOG.debug("hndlTepAddOnNonNaptSwitch : Install group in non NAPT switch {} for router {}",
448 srcDpnId, routerName);
449 List<BucketInfo> bucketInfoForNonNaptSwitches =
450 externalRouterListner.getBucketInfoForNonNaptSwitches(srcDpnId, primaryDpnId, routerName, routerId);
451 Uint32 groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME,
452 NatUtil.getGroupIdKey(routerName));
453 if (groupId != NatConstants.INVALID_ID) {
454 externalRouterListner.installGroup(srcDpnId, routerName, groupId, bucketInfoForNonNaptSwitches);
455 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> in the SNAT miss entry pointing to group {} "
456 + "in the non NAPT switch {}", groupId, srcDpnId);
457 FlowEntity flowEntity =
458 externalRouterListner.buildSnatFlowEntityWithUpdatedVpnId(srcDpnId, routerName, groupId, vpnId);
459 mdsalManager.addFlow(confTx, flowEntity);
461 LOG.error("hndlTepAddOnNonNaptSwitch: Unable to obtain group ID for Key: {}", routerName);
467 private boolean hndlTepAddOnNaptSwitch(Uint64 srcDpnId, String tunnelType, String srcTepIp,
468 String destTepIp, String tunnelName, Uint32 routerId,
469 Optional<Routers> routerData, String nextHopIp, Uuid vpnName,
470 ProviderTypes extNwProvType, TypedWriteTransaction<Configuration> confTx) {
471 if (!routerData.isPresent()) {
472 LOG.warn("hndlTepAddOnNaptSwitch: routerData is not present");
475 Routers router = routerData.get();
476 String routerName = router.getRouterName();
477 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Processing TEP add for the DPN {} having the router {} since "
478 + "its THE NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
479 + "and TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
481 Uuid networkId = router.getNetworkId();
482 if (networkId == null) {
483 LOG.warn("hndlTepAddOnNaptSwitch : SNAT -> Ignoring TEP add since the router {} is not associated to the "
484 + "external network", routerName);
488 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Router {} is associated with Ext nw {}", routerId, networkId);
490 if (vpnName == null) {
491 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Internal VPN associated to router {}", routerId);
492 vpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
493 if (vpnId == NatConstants.INVALID_ID) {
494 LOG.error("hndlTepAddOnNaptSwitch : Invalid External VPN-ID returned for routerName {}", routerName);
497 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Retrieved External VPN-ID {} for router {}", vpnId, routerId);
499 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Private BGP VPN associated to router {}", routerId);
500 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
501 if (vpnId == NatConstants.INVALID_ID) {
502 LOG.error("hndlTepAddOnNaptSwitch : Invalid vpnId returned for routerName {}", routerName);
505 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
508 /*1) Withdraw the old route to the external IP from the BGP which was having the
509 next hop as the old TEP IP.
510 2) Advertise to the BGP about the new route to the external IP having the
511 new TEP IP as the next hop.
512 3) Populate a new FIB entry with the next hop IP as the new TEP IP using the
516 //Withdraw the old route to the external IP from the BGP which was having the
517 //next hop as the old TEP IP.
518 final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
519 if (externalVpnName == null) {
520 LOG.error("hndlTepAddOnNaptSwitch : SNAT -> No VPN associated with ext nw {} in router {}",
521 networkId, routerId);
524 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
525 LOG.debug("hndlTepAddOnNaptSwitch : Clearing the FIB entries but not the BGP routes");
526 for (String externalIp : externalIps) {
527 String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
528 LOG.debug("hndlTepAddOnNaptSwitch : Removing Fib entry rd {} prefix {}", rd, externalIp);
529 fibManager.removeFibEntry(rd, externalIp, null, null);
533 Advertise to the BGP about the new route to the external IP having the
534 new TEP IP as the next hop.
535 Populate a new FIB entry with the next hop IP as the new TEP IP using the
538 String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
539 if (extNwProvType == null) {
542 String gwMacAddress = null;
543 Uint32 l3Vni = Uint32.ZERO;
544 if (extNwProvType == ProviderTypes.VXLAN) {
545 // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
546 gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
547 if (gwMacAddress != null) {
548 LOG.debug("hndlTepAddOnNaptSwitch : External Gateway MAC address {} found for External Router ID {}",
549 gwMacAddress, routerId);
551 LOG.error("hndlTepAddOnNaptSwitch : No External Gateway MAC address found for External Router ID {}",
555 //get l3Vni value for external VPN
556 l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
557 if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
558 LOG.debug("hndlTepAddOnNaptSwitch : L3VNI value is not configured in Internet VPN {} and RD {} "
559 + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
560 + "NAT flows", vpnName, rd);
561 l3Vni = natOverVxlanUtil.getInternetVpnVni(externalVpnName, routerId);
565 for (final String externalIp : externalIps) {
566 Uint32 serviceId = null;
567 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
568 if (extNwProvType == ProviderTypes.VXLAN) {
569 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Advertise the route to the externalIp {} "
570 + "having nextHopIp {}", externalIp, nextHopIp);
571 NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, externalVpnName, rd,
572 externalIp, nextHopIp, l3Vni, tunnelName, gwMacAddress, confTx, RouteOrigin.STATIC,
573 srcDpnId, networkId);
577 serviceId = externalRouterListner.checkExternalIpLabel(routerId,
579 if (serviceId == null || serviceId == NatConstants.INVALID_ID) {
580 LOG.error("hndlTepAddOnNaptSwitch : SNAT->Unable to advertise to the DC GW "
581 + "since label is invalid");
584 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Advertise the route to the externalIp {} "
585 + "having nextHopIp {}", externalIp, nextHopIp);
586 Uint32 l3vni = Uint32.ZERO;
587 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
588 l3vni = natOverVxlanUtil.getInternetVpnVni(externalVpnName, l3vni);
590 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, externalVpnName, rd,
591 fibExternalIp, nextHopIp, networkId.getValue(), null /* mac-address */, serviceId, l3vni,
592 RouteOrigin.STATIC, srcDpnId);
595 LOG.debug("hndlTepAddOnNaptSwitch: SNAT -> Install custom FIB routes "
596 + "(Table 21 -> Push MPLS label to Tunnel port");
597 List<Instruction> customInstructions = new ArrayList<>();
598 int customInstructionIndex = 0;
599 Uint32 externalSubnetVpnId = NatUtil.getExternalSubnetVpnIdForRouterExternalIp(dataBroker, externalIp,
601 if (externalSubnetVpnId != NatConstants.INVALID_ID) {
602 LOG.debug("hndlTepAddOnNaptSwitch : Will install custom FIB router with external subnet VPN ID {}",
603 externalSubnetVpnId);
604 Uint64 subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(externalSubnetVpnId.longValue());
605 customInstructions.add(new InstructionWriteMetadata(subnetIdMetaData,
606 MetaDataUtil.METADATA_MASK_VRFID).buildInstruction(customInstructionIndex));
607 customInstructionIndex++;
609 customInstructions.add(new InstructionGotoTable(NwConstants.INBOUND_NAPT_TABLE)
610 .buildInstruction(customInstructionIndex));
611 CreateFibEntryInput input =
612 new CreateFibEntryInputBuilder().setVpnName(externalVpnName).setSourceDpid(srcDpnId)
613 .setInstruction(customInstructions).setIpAddress(fibExternalIp)
614 .setIpAddressSource(FibEntryInputs.IpAddressSource.ExternalFixedIP)
615 .setServiceId(serviceId).setInstruction(customInstructions).build();
616 ListenableFuture<RpcResult<CreateFibEntryOutput>> listenableFuture = fibRpcService.createFibEntry(input);
618 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
621 public void onFailure(@NonNull Throwable error) {
622 LOG.error("hndlTepAddOnNaptSwitch : SNAT->Error in generate label or fib install process",
627 public void onSuccess(@NonNull RpcResult<CreateFibEntryOutput> result) {
628 if (result.isSuccessful()) {
629 LOG.info("hndlTepAddOnNaptSwitch : SNAT -> Successfully installed custom FIB routes "
630 + "for prefix {}", externalIp);
632 LOG.error("hndlTepAddOnNaptSwitch : SNAT -> Error in rpc call to create custom Fib entries "
633 + "for prefix {} in DPN {}, {}", externalIp, srcDpnId, result.getErrors());
636 }, MoreExecutors.directExecutor());
642 private void hndlTepAddForDnatInEachRtr(RoutersList router, Uint32 routerId, String nextHopIp,
643 Uint64 tepAddedDpnId, ProviderTypes extNwProvType, TypedWriteTransaction<Configuration> confTx) {
644 //DNAT : Advertise the new route to the floating IP having the new TEP IP as the next hop IP
645 final String routerName = router.getRouter();
647 InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
648 Optional<RouterPorts> optRouterPorts;
650 optRouterPorts = SingleTransactionDataBroker.syncReadOptional(dataBroker,
651 LogicalDatastoreType.CONFIGURATION, routerPortsId);
652 } catch (ExecutionException | InterruptedException e) {
653 LOG.error("hndlTepAddForDnatInEachRtr: Exception while reading RouterPorts DS for the router {}",
657 if (!optRouterPorts.isPresent()) {
658 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Could not read Router Ports data object with id: {} "
659 + "from DNAT FloatinIpInfo", routerName);
662 RouterPorts routerPorts = optRouterPorts.get();
663 Uuid extNwId = routerPorts.getExternalNetworkId();
664 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId);
665 if (vpnName == null) {
666 LOG.info("hndlTepAddForDnatInEachRtr : DNAT -> No External VPN associated with ext nw {} for router {}",
667 extNwId, routerName);
671 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
672 if (extNwProvType == null) {
675 String gwMacAddress = null;
676 Uint32 l3Vni = Uint32.ZERO;
677 if (extNwProvType == ProviderTypes.VXLAN) {
678 // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
679 gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
680 if (gwMacAddress != null) {
681 LOG.debug("hndlTepAddForDnatInEachRtr : External GwMAC address {} found for External Router ID {}",
682 gwMacAddress, routerId);
684 LOG.error("hndlTepAddForDnatInEachRtr : No External GwMAC address found for External Router ID {}",
688 //get l3Vni value for external VPN
689 l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
690 if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
691 LOG.debug("hndlTepAddForDnatInEachRtr : L3VNI value is not configured in Internet VPN {} and RD {} "
692 + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
693 + "NAT flows", vpnName, rd);
694 l3Vni = natOverVxlanUtil.getInternetVpnVni(vpnName, routerId);
697 for (Ports port : routerPorts.nonnullPorts().values()) {
698 //Get the DPN on which this interface resides
699 final String interfaceName = port.getPortName();
700 final Uint64 fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
701 if (fipCfgdDpnId.equals(Uint64.ZERO)) {
702 LOG.info("hndlTepAddForDnatInEachRtr : DNAT->Skip processing Floating ip configuration for the port {},"
703 + "since no DPN present for it", interfaceName);
706 if (!fipCfgdDpnId.equals(tepAddedDpnId)) {
707 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> TEP added DPN {} is not the DPN {} which has the "
708 + "floating IP configured for the port: {}",
709 tepAddedDpnId, fipCfgdDpnId, interfaceName);
712 for (InternalToExternalPortMap intExtPortMap : port.nonnullInternalToExternalPortMap().values()) {
713 final String internalIp = intExtPortMap.getInternalIp();
714 final String externalIp = intExtPortMap.getExternalIp();
715 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertising the FIB route to the floating IP {} "
716 + "configured for the port: {}", externalIp, interfaceName);
717 Uint32 serviceId = null;
718 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
720 if (extNwProvType == ProviderTypes.VXLAN) {
721 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertise the route to the externalIp {} "
722 + "having nextHopIp {}", externalIp, nextHopIp);
723 NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, vpnName, rd,
724 externalIp, nextHopIp, l3Vni, interfaceName, gwMacAddress, confTx, RouteOrigin.STATIC,
725 fipCfgdDpnId, extNwId);
728 serviceId = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
729 if (serviceId == null || serviceId == NatConstants.INVALID_ID) {
730 LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Unable to advertise to the DC GW since label "
734 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertise the route to the externalIp {} "
735 + "having nextHopIp {}", externalIp, nextHopIp);
736 Uint32 l3vni = Uint32.ZERO;
737 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
738 l3vni = natOverVxlanUtil.getInternetVpnVni(vpnName, l3vni);
740 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd,
741 fibExternalIp, nextHopIp, null, null, serviceId, l3vni,
742 RouteOrigin.STATIC, fipCfgdDpnId);
745 //Install custom FIB routes (Table 21 -> Push MPLS label to Tunnel port
746 List<Instruction> customInstructions = new ArrayList<>();
747 customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(0));
748 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
749 .setSourceDpid(fipCfgdDpnId).setInstruction(customInstructions)
750 .setIpAddressSource(FibEntryInputs.IpAddressSource.FloatingIP)
751 .setIpAddress(fibExternalIp).setServiceId(serviceId).setInstruction(customInstructions)
753 ListenableFuture<RpcResult<CreateFibEntryOutput>> listenableFuture =
754 fibRpcService.createFibEntry(input);
756 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
759 public void onFailure(@NonNull Throwable error) {
760 LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Error in generate label or fib install process",
765 public void onSuccess(@NonNull RpcResult<CreateFibEntryOutput> result) {
766 if (result.isSuccessful()) {
767 LOG.info("hndlTepAddForDnatInEachRtr : DNAT -> Successfully installed custom FIB routes "
768 + "for prefix {}", externalIp);
770 LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Error in rpc call to create custom Fib "
771 + "entries for prefix {} in DPN {}, {}", externalIp, fipCfgdDpnId, result.getErrors());
774 }, MoreExecutors.directExecutor());
779 protected boolean isTunnelInLogicalGroup(StateTunnelList stateTunnelList) {
780 String ifaceName = stateTunnelList.getTunnelInterfaceName();
781 if (getTunnelType(stateTunnelList) == NatConstants.ITMTunnelLocType.Internal.getValue()) {
782 Interface configIface = interfaceManager.getInterfaceInfoFromConfigDataStore(ifaceName);
783 IfTunnel ifTunnel = configIface != null ? configIface.augmentation(IfTunnel.class) : null;
784 if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) {
785 ParentRefs refs = configIface.augmentation(ParentRefs.class);
786 if (refs != null && !Strings.isNullOrEmpty(refs.getParentInterface())) {
787 return true; //multiple VxLAN tunnels enabled, i.e. only logical tunnel should be treated
791 LOG.trace("isTunnelInLogicalGroup: ignoring the tunnel event for {}", ifaceName);