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.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;
21 import java.util.Optional;
22 import java.util.concurrent.ExecutionException;
23 import javax.annotation.PreDestroy;
24 import javax.inject.Inject;
25 import javax.inject.Singleton;
26 import org.eclipse.jdt.annotation.NonNull;
27 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
28 import org.opendaylight.genius.infra.Datastore.Configuration;
29 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
30 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
31 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
32 import org.opendaylight.genius.infra.TypedWriteTransaction;
33 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
34 import org.opendaylight.genius.mdsalutil.BucketInfo;
35 import org.opendaylight.genius.mdsalutil.FlowEntity;
36 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
37 import org.opendaylight.genius.mdsalutil.NwConstants;
38 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
39 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
40 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
41 import org.opendaylight.infrautils.utils.concurrent.Executors;
42 import org.opendaylight.mdsal.binding.api.DataBroker;
43 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
44 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
45 import org.opendaylight.netvirt.elanmanager.api.IElanService;
46 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
47 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
48 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
49 import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryOutput;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibEntryInputs;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersList;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.dpn.routers.list.RoutersList;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
77 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
78 import org.opendaylight.yangtools.yang.common.RpcResult;
79 import org.opendaylight.yangtools.yang.common.Uint32;
80 import org.opendaylight.yangtools.yang.common.Uint64;
81 import org.slf4j.Logger;
82 import org.slf4j.LoggerFactory;
85 public class NatTunnelInterfaceStateListener extends AbstractAsyncDataTreeChangeListener<StateTunnelList> {
87 private static final Logger LOG = LoggerFactory.getLogger(NatTunnelInterfaceStateListener.class);
88 private final DataBroker dataBroker;
89 private final ManagedNewTransactionRunner txRunner;
90 private final IFibManager fibManager;
91 private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
92 private final NaptSwitchHA naptSwitchHA;
93 private final IMdsalApiManager mdsalManager;
94 private final IdManagerService idManager;
95 private final IBgpManager bgpManager;
96 private final ExternalRoutersListener externalRouterListner;
97 private final SnatServiceManager natServiceManager;
98 private final OdlInterfaceRpcService interfaceService;
99 private final FloatingIPListener floatingIPListener;
100 private final FibRpcService fibRpcService;
101 private final IElanService elanManager;
102 private final IInterfaceManager interfaceManager;
103 private final NatOverVxlanUtil natOverVxlanUtil;
104 private final NatMode natMode;
106 protected enum TunnelAction {
113 * Responsible for listening to tunnel interface state change.
115 * @param dataBroker - dataBroker service reference
116 * @param bgpManager Used to advertise routes to the BGP Router
117 * @param fibManager - FIB Manager
118 * @param defaultRouteProgrammer - Default Route Programmer
119 * @param naptSwitchHA - NAPT Switch HA
120 * @param mdsalManager - MDSAL Manager
121 * @param idManager - ID manager
122 * @param externalRouterListner - External Router Listener
123 * @param natServiceManager - Nat Service Manager
124 * @param interfaceService - Interface Service
125 * @param floatingIPListener - Floating IP Listener
126 * @param fibRpcService - FIB RPC Service
127 * @param config - Nat Service Config
128 * @param elanManager - Elan Manager
129 * @param interfaceManager - Interface Manager
130 * @param natOverVxlanUtils - Nat Over Vxlan Utility
133 public NatTunnelInterfaceStateListener(final DataBroker dataBroker,
134 final IBgpManager bgpManager,
135 final IFibManager fibManager,
136 final SNATDefaultRouteProgrammer defaultRouteProgrammer,
137 final NaptSwitchHA naptSwitchHA,
138 final IMdsalApiManager mdsalManager,
139 final IdManagerService idManager,
140 final ExternalRoutersListener externalRouterListner,
141 final SnatServiceManager natServiceManager,
142 final OdlInterfaceRpcService interfaceService,
143 final FloatingIPListener floatingIPListener,
144 final FibRpcService fibRpcService,
145 final NatserviceConfig config,
146 final IElanService elanManager,
147 final IInterfaceManager interfaceManager,
148 final NatOverVxlanUtil natOverVxlanUtils) {
149 super(dataBroker, LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(TunnelsState.class)
150 .child(StateTunnelList.class),
151 Executors.newListeningSingleThreadExecutor("NatTunnelInterfaceStateListener", LOG));
152 this.dataBroker = dataBroker;
153 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
154 this.bgpManager = bgpManager;
155 this.fibManager = fibManager;
156 this.defaultRouteProgrammer = defaultRouteProgrammer;
157 this.naptSwitchHA = naptSwitchHA;
158 this.mdsalManager = mdsalManager;
159 this.idManager = idManager;
160 this.externalRouterListner = externalRouterListner;
161 this.natServiceManager = natServiceManager;
162 this.interfaceService = interfaceService;
163 this.floatingIPListener = floatingIPListener;
164 this.fibRpcService = fibRpcService;
165 this.elanManager = elanManager;
166 this.interfaceManager = interfaceManager;
167 this.natOverVxlanUtil = natOverVxlanUtils;
168 if (config != null) {
169 this.natMode = config.getNatMode();
171 this.natMode = NatMode.Controller;
176 LOG.info("{} init", getClass().getSimpleName());
181 public void close() {
183 Executors.shutdownAndAwaitTermination(getExecutorService());
187 public void add(InstanceIdentifier<StateTunnelList> instanceIdentifier, StateTunnelList add) {
188 LOG.trace("add : TEP addtion---- {}", add);
189 hndlTepEvntsForDpn(add, TunnelAction.TUNNEL_EP_ADD);
193 public void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
194 LOG.trace("remove : TEP deletion---- {}", del);
195 // Moved the remove implementation logic to NatTepChangeLister.remove()
199 public void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original,
200 StateTunnelList update) {
201 LOG.trace("update : Tunnel updation---- {}", update);
202 //UPDATE IS A SEQUENCE OF DELETE AND ADD EVENTS . DELETE MIGHT HAVE CHANGED THE PRIMARY AND ADVERTISED. SO
206 private int getTunnelType(StateTunnelList stateTunnelList) {
208 if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
209 tunTypeVal = NatConstants.ITMTunnelLocType.Internal.getValue();
210 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
211 tunTypeVal = NatConstants.ITMTunnelLocType.External.getValue();
212 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
213 tunTypeVal = NatConstants.ITMTunnelLocType.Hwvtep.getValue();
215 tunTypeVal = NatConstants.ITMTunnelLocType.Invalid.getValue();
220 private void hndlTepEvntsForDpn(StateTunnelList stateTunnelList, TunnelAction tunnelAction) {
221 LOG.trace("hndlTepEvntsForDpn : stateTunnelList {}", stateTunnelList);
222 final Uint64 srcDpnId = stateTunnelList.getSrcInfo() != null
223 ? Uint64.valueOf(stateTunnelList.getSrcInfo().getTepDeviceId()) : Uint64.ZERO;
224 final String srcTepIp = stateTunnelList.getSrcInfo() != null
225 ? stateTunnelList.getSrcInfo().getTepIp().stringValue() : null;
226 final String destTepIp = stateTunnelList.getDstInfo() != null
227 ? stateTunnelList.getDstInfo().getTepIp().stringValue() : null;
228 LOG.trace("hndlTepEvntsForDpn : Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ",
229 srcDpnId, srcTepIp, destTepIp);
230 if (srcDpnId == Uint64.ZERO || srcTepIp == null || destTepIp == null) {
231 LOG.error("hndlTepEvntsForDpn invalid srcDpnId {}, srcTepIp {}, destTepIp {}",
232 srcDpnId, srcTepIp, destTepIp);
235 int tunTypeVal = getTunnelType(stateTunnelList);
236 LOG.trace("hndlTepEvntsForDpn : tunTypeVal is {}", tunTypeVal);
237 String srcTepId = stateTunnelList.getSrcInfo().getTepDeviceId() != null
238 ? stateTunnelList.getSrcInfo().getTepDeviceId() : "0";
239 String tunnelType = stateTunnelList.getTransportType() != null
240 ? stateTunnelList.getTransportType().toString() : null;
241 String tunnelName = stateTunnelList.getTunnelInterfaceName();
243 if (tunTypeVal == NatConstants.ITMTunnelLocType.Invalid.getValue() || srcDpnId.equals(Uint64.ZERO)
244 || srcTepIp == null || destTepIp == null) {
245 LOG.warn("hndlTepEvntsForDpn : Ignoring TEP event {} for the DPN {} "
246 + "since its a INVALID TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and " + "TUNNEL NAME {} ",
247 tunnelAction, srcTepId, tunnelType, srcTepIp, destTepIp, tunnelName);
251 switch (tunnelAction) {
254 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
255 if (isTunnelInLogicalGroup(stateTunnelList)
256 || !hndlTepAddForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp,
258 LOG.debug("hndlTepEvntsForDpn : Unable to process TEP ADD");
261 } catch (InterruptedException | ExecutionException e) {
262 LOG.error("Error processing tunnel endpoint addition", e);
265 case TUNNEL_EP_DELETE:
266 // Moved the current implementation logic to NatTepChangeListener.remove()
268 case TUNNEL_EP_UPDATE:
271 LOG.warn("hndlTepEvntsForDpn: unknown tunnelAction: {}", tunnelAction);
276 private boolean hndlTepAddForAllRtrs(Uint64 srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
277 String destTepIp, TypedReadWriteTransaction<Configuration> writeFlowInvTx)
278 throws ExecutionException, InterruptedException {
279 LOG.trace("hndlTepAddForAllRtrs: TEP ADD ----- for EXTERNAL/HWVTEP ITM Tunnel, TYPE {} ,State is UP b/w SRC IP"
280 + " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
282 InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
283 Optional<DpnRoutersList> optionalRouterDpnList =
284 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
285 LogicalDatastoreType.OPERATIONAL, dpnRoutersListId);
286 if (!optionalRouterDpnList.isPresent()) {
287 LOG.info("hndlTepAddForAllRtrs : RouterDpnList model is empty for DPN {}. Hence ignoring TEP add event "
288 + "for the ITM TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ",
289 srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
293 List<RoutersList> routersList = optionalRouterDpnList.get().getRoutersList();
294 if (routersList == null) {
295 LOG.debug("hndlTepAddForAllRtrs : Ignoring TEP add for the DPN {} since no routers are associated"
296 + " for the DPN having the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
297 + "TUNNEL NAME {} ", srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
301 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
302 for (RoutersList router : routersList) {
303 String routerName = router.getRouter();
304 Uint32 routerId = NatUtil.getVpnId(dataBroker, routerName);
305 if (routerId == NatConstants.INVALID_ID) {
306 LOG.error("hndlTepAddForAllRtrs :Invalid ROUTER-ID {} returned for routerName {}",
307 routerId, routerName);
310 LOG.debug("hndlTepAddForAllRtrs : TEP ADD : DNAT -> Advertising routes for router {} ", routerName);
311 Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
312 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
313 routerName, externalNetworkId);
314 if (extNwProvType == null) {
317 hndlTepAddForDnatInEachRtr(router, routerId, nextHopIp, srcDpnId, extNwProvType, writeFlowInvTx);
319 LOG.debug("hndlTepAddForAllRtrs : TEP ADD : SNAT -> Advertising routes for router {} ", routerName);
320 hndlTepAddForSnatInEachRtr(router, routerId, srcDpnId, tunnelType, srcTepIp, destTepIp,
321 tunnelName, nextHopIp, extNwProvType, writeFlowInvTx);
326 private void hndlTepAddForSnatInEachRtr(RoutersList router, Uint32 routerId, final Uint64 srcDpnId,
327 String tunnelType, String srcTepIp, String destTepIp, String tunnelName, String nextHopIp,
328 ProviderTypes extNwProvType, TypedReadWriteTransaction<Configuration> writeFlowInvTx)
329 throws ExecutionException, InterruptedException {
331 /*SNAT : Remove the old routes to the external IP having the old TEP IP as the next hop IP
332 Advertise to the BGP about the new route to the external IP having the new TEP IP
333 added as the next hop IP
335 String routerName = router.getRouter();
337 // Check if this is externalRouter else ignore
338 InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
339 Optional<Routers> routerData;
341 routerData = writeFlowInvTx.read(extRoutersId).get();
342 } catch (InterruptedException | ExecutionException e) {
343 LOG.error("Error reading router data for {}", extRoutersId, e);
344 routerData = Optional.empty();
346 if (!routerData.isPresent()) {
347 LOG.warn("hndlTepAddForSnatInEachRtr : SNAT->Ignoring TEP add for router {} since its not External Router",
352 Uint64 naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
353 if (naptId == null || naptId.equals(Uint64.ZERO)) {
354 LOG.warn("hndlTepAddForSnatInEachRtr : SNAT -> Ignoring TEP add for the DPN {} having the router {} since"
355 + " the router is not part of the NAT service - the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
356 + "TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
359 if (natMode == NatMode.Conntrack) {
360 Routers extRouter = routerData.get();
361 natServiceManager.notify(writeFlowInvTx, extRouter, null, naptId, srcDpnId,
362 SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_ENBL);
363 if (extRouter.isEnableSnat()) {
364 natServiceManager.notify(writeFlowInvTx, extRouter, null, naptId, srcDpnId,
365 SnatServiceManager.Action.SNAT_ROUTER_ENBL);
368 Uuid bgpVpnUuId = NatUtil.getVpnForRouter(dataBroker, routerName);
369 //Check if the DPN having the router is the NAPT switch
370 if (!naptId.equals(srcDpnId)) {
372 1) Install default NAT rule from table 21 to 26
373 2) Install the group which forward packet to the tunnel port for the NAPT switch.
374 3) Install the flow 26 which forwards the packet to the group.
376 if (!hndlTepAddOnNonNaptSwitch(srcDpnId, naptId, tunnelType, srcTepIp, destTepIp, tunnelName,
377 routerName, routerId, bgpVpnUuId, writeFlowInvTx)) {
378 LOG.error("hndlTepAddForSnatInEachRtr : Unable to process the TEP add event on NON-NAPT switch {}",
384 if (!hndlTepAddOnNaptSwitch(srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName, routerId,
385 routerData, nextHopIp, bgpVpnUuId, extNwProvType, writeFlowInvTx)) {
386 LOG.debug("hndlTepAddForSnatInEachRtr : Unable to process the TEP add event on NAPT switch {}",
394 private boolean hndlTepAddOnNonNaptSwitch(Uint64 srcDpnId, Uint64 primaryDpnId, String tunnelType,
395 String srcTepIp, String destTepIp, String tunnelName, String routerName, Uint32 routerId, Uuid vpnName,
396 TypedWriteTransaction<Configuration> confTx) {
399 1) Install default NAT rule from table 21 to 26
400 2) Install the group which forward packet to the tunnel port for the NAPT switch.
401 3) Install the flow 26 which forwards the packet to the group.
403 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Processing TEP add for the DPN {} having the router {} since "
404 + "its THE NON NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
405 + "and TUNNEL NAME {} ",
406 srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
407 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Install default NAT rule from table 21 to 26");
409 if (vpnName == null) {
410 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Internal VPN associated to router {}", routerId);
412 if (vpnId == NatConstants.INVALID_ID) {
413 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid Internal VPN ID returned for routerName {}",
417 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerName);
418 //Install default entry in FIB to SNAT table
419 LOG.debug("hndlTepAddOnNonNaptSwitch : Installing default route in FIB on DPN {} for router {} with"
420 + " vpn {}...", srcDpnId, routerName, vpnId);
421 defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, confTx);
423 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Install the group which forward packet to the tunnel port "
424 + "for the NAPT switch {} and the flow 26 which forwards to group", primaryDpnId);
425 externalRouterListner.handleSwitches(srcDpnId, routerName, routerId, primaryDpnId);
427 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> External BGP VPN (Private BGP) associated to router {}",
429 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
430 if (vpnId == NatConstants.INVALID_ID) {
431 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid Private BGP VPN ID returned for routerName {}",
435 if (routerId == NatConstants.INVALID_ID) {
436 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid routId returned for routerName {}", routerId);
439 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
440 //Install default entry in FIB to SNAT table
441 LOG.debug("hndlTepAddOnNonNaptSwitch : Installing default route in FIB on dpn {} for routerId {} "
442 + "with vpnId {}...", srcDpnId, routerId, vpnId);
443 defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, routerId, confTx);
445 LOG.debug("hndlTepAddOnNonNaptSwitch : Install group in non NAPT switch {} for router {}",
446 srcDpnId, routerName);
447 List<BucketInfo> bucketInfoForNonNaptSwitches =
448 externalRouterListner.getBucketInfoForNonNaptSwitches(srcDpnId, primaryDpnId, routerName, routerId);
449 Uint32 groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME,
450 NatUtil.getGroupIdKey(routerName));
451 if (groupId != NatConstants.INVALID_ID) {
452 externalRouterListner.installGroup(srcDpnId, routerName, groupId, bucketInfoForNonNaptSwitches);
453 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> in the SNAT miss entry pointing to group {} "
454 + "in the non NAPT switch {}", groupId, srcDpnId);
455 FlowEntity flowEntity =
456 externalRouterListner.buildSnatFlowEntityWithUpdatedVpnId(srcDpnId, routerName, groupId, vpnId);
457 mdsalManager.addFlow(confTx, flowEntity);
459 LOG.error("hndlTepAddOnNonNaptSwitch: Unable to obtain group ID for Key: {}", routerName);
465 private boolean hndlTepAddOnNaptSwitch(Uint64 srcDpnId, String tunnelType, String srcTepIp,
466 String destTepIp, String tunnelName, Uint32 routerId,
467 Optional<Routers> routerData, String nextHopIp, Uuid vpnName,
468 ProviderTypes extNwProvType, TypedWriteTransaction<Configuration> confTx) {
469 if (!routerData.isPresent()) {
470 LOG.warn("hndlTepAddOnNaptSwitch: routerData is not present");
473 Routers router = routerData.get();
474 String routerName = router.getRouterName();
475 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Processing TEP add for the DPN {} having the router {} since "
476 + "its THE NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
477 + "and TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
479 Uuid networkId = router.getNetworkId();
480 if (networkId == null) {
481 LOG.warn("hndlTepAddOnNaptSwitch : SNAT -> Ignoring TEP add since the router {} is not associated to the "
482 + "external network", routerName);
486 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Router {} is associated with Ext nw {}", routerId, networkId);
488 if (vpnName == null) {
489 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Internal VPN associated to router {}", routerId);
490 vpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
491 if (vpnId == NatConstants.INVALID_ID) {
492 LOG.error("hndlTepAddOnNaptSwitch : Invalid External VPN-ID returned for routerName {}", routerName);
495 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Retrieved External VPN-ID {} for router {}", vpnId, routerId);
497 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Private BGP VPN associated to router {}", routerId);
498 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
499 if (vpnId == NatConstants.INVALID_ID) {
500 LOG.error("hndlTepAddOnNaptSwitch : Invalid vpnId returned for routerName {}", routerName);
503 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
506 /*1) Withdraw the old route to the external IP from the BGP which was having the
507 next hop as the old TEP IP.
508 2) Advertise to the BGP about the new route to the external IP having the
509 new TEP IP as the next hop.
510 3) Populate a new FIB entry with the next hop IP as the new TEP IP using the
514 //Withdraw the old route to the external IP from the BGP which was having the
515 //next hop as the old TEP IP.
516 final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
517 if (externalVpnName == null) {
518 LOG.error("hndlTepAddOnNaptSwitch : SNAT -> No VPN associated with ext nw {} in router {}",
519 networkId, routerId);
522 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
523 LOG.debug("hndlTepAddOnNaptSwitch : Clearing the FIB entries but not the BGP routes");
524 for (String externalIp : externalIps) {
525 String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
526 LOG.debug("hndlTepAddOnNaptSwitch : Removing Fib entry rd {} prefix {}", rd, externalIp);
527 fibManager.removeFibEntry(rd, externalIp, null, null);
531 Advertise to the BGP about the new route to the external IP having the
532 new TEP IP as the next hop.
533 Populate a new FIB entry with the next hop IP as the new TEP IP using the
536 String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
537 if (extNwProvType == null) {
540 String gwMacAddress = null;
541 Uint32 l3Vni = Uint32.ZERO;
542 if (extNwProvType == ProviderTypes.VXLAN) {
543 // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
544 gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
545 if (gwMacAddress != null) {
546 LOG.debug("hndlTepAddOnNaptSwitch : External Gateway MAC address {} found for External Router ID {}",
547 gwMacAddress, routerId);
549 LOG.error("hndlTepAddOnNaptSwitch : No External Gateway MAC address found for External Router ID {}",
553 //get l3Vni value for external VPN
554 l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
555 if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
556 LOG.debug("hndlTepAddOnNaptSwitch : L3VNI value is not configured in Internet VPN {} and RD {} "
557 + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
558 + "NAT flows", vpnName, rd);
559 l3Vni = natOverVxlanUtil.getInternetVpnVni(externalVpnName, routerId);
563 for (final String externalIp : externalIps) {
564 Uint32 serviceId = null;
565 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
566 if (extNwProvType == ProviderTypes.VXLAN) {
567 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Advertise the route to the externalIp {} "
568 + "having nextHopIp {}", externalIp, nextHopIp);
569 NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, externalVpnName, rd,
570 externalIp, nextHopIp, l3Vni, tunnelName, gwMacAddress, confTx, RouteOrigin.STATIC,
571 srcDpnId, networkId);
575 serviceId = externalRouterListner.checkExternalIpLabel(routerId,
577 if (serviceId == null || serviceId == NatConstants.INVALID_ID) {
578 LOG.error("hndlTepAddOnNaptSwitch : SNAT->Unable to advertise to the DC GW "
579 + "since label is invalid");
582 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Advertise the route to the externalIp {} "
583 + "having nextHopIp {}", externalIp, nextHopIp);
584 Uint32 l3vni = Uint32.ZERO;
585 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
586 l3vni = natOverVxlanUtil.getInternetVpnVni(externalVpnName, l3vni);
588 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, externalVpnName, rd,
589 fibExternalIp, nextHopIp, networkId.getValue(), null /* mac-address */, serviceId, l3vni,
590 RouteOrigin.STATIC, srcDpnId);
593 LOG.debug("hndlTepAddOnNaptSwitch: SNAT -> Install custom FIB routes "
594 + "(Table 21 -> Push MPLS label to Tunnel port");
595 List<Instruction> customInstructions = new ArrayList<>();
596 int customInstructionIndex = 0;
597 Uint32 externalSubnetVpnId = NatUtil.getExternalSubnetVpnIdForRouterExternalIp(dataBroker, externalIp,
599 if (externalSubnetVpnId != NatConstants.INVALID_ID) {
600 LOG.debug("hndlTepAddOnNaptSwitch : Will install custom FIB router with external subnet VPN ID {}",
601 externalSubnetVpnId);
602 Uint64 subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(externalSubnetVpnId.longValue());
603 customInstructions.add(new InstructionWriteMetadata(subnetIdMetaData,
604 MetaDataUtil.METADATA_MASK_VRFID).buildInstruction(customInstructionIndex));
605 customInstructionIndex++;
607 customInstructions.add(new InstructionGotoTable(NwConstants.INBOUND_NAPT_TABLE)
608 .buildInstruction(customInstructionIndex));
609 CreateFibEntryInput input =
610 new CreateFibEntryInputBuilder().setVpnName(externalVpnName).setSourceDpid(srcDpnId)
611 .setInstruction(customInstructions).setIpAddress(fibExternalIp)
612 .setIpAddressSource(FibEntryInputs.IpAddressSource.ExternalFixedIP)
613 .setServiceId(serviceId).setInstruction(customInstructions).build();
614 ListenableFuture<RpcResult<CreateFibEntryOutput>> listenableFuture = fibRpcService.createFibEntry(input);
616 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
619 public void onFailure(@NonNull Throwable error) {
620 LOG.error("hndlTepAddOnNaptSwitch : SNAT->Error in generate label or fib install process",
625 public void onSuccess(@NonNull RpcResult<CreateFibEntryOutput> result) {
626 if (result.isSuccessful()) {
627 LOG.info("hndlTepAddOnNaptSwitch : SNAT -> Successfully installed custom FIB routes "
628 + "for prefix {}", externalIp);
630 LOG.error("hndlTepAddOnNaptSwitch : SNAT -> Error in rpc call to create custom Fib entries "
631 + "for prefix {} in DPN {}, {}", externalIp, srcDpnId, result.getErrors());
634 }, MoreExecutors.directExecutor());
640 private void hndlTepAddForDnatInEachRtr(RoutersList router, Uint32 routerId, String nextHopIp,
641 Uint64 tepAddedDpnId, ProviderTypes extNwProvType, TypedWriteTransaction<Configuration> confTx) {
642 //DNAT : Advertise the new route to the floating IP having the new TEP IP as the next hop IP
643 final String routerName = router.getRouter();
645 InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
646 Optional<RouterPorts> optRouterPorts;
648 optRouterPorts = SingleTransactionDataBroker.syncReadOptional(dataBroker,
649 LogicalDatastoreType.CONFIGURATION, routerPortsId);
650 } catch (ExecutionException | InterruptedException e) {
651 LOG.error("hndlTepAddForDnatInEachRtr: Exception while reading RouterPorts DS for the router {}",
655 if (!optRouterPorts.isPresent()) {
656 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Could not read Router Ports data object with id: {} "
657 + "from DNAT FloatinIpInfo", routerName);
660 RouterPorts routerPorts = optRouterPorts.get();
661 Uuid extNwId = routerPorts.getExternalNetworkId();
662 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId);
663 if (vpnName == null) {
664 LOG.info("hndlTepAddForDnatInEachRtr : DNAT -> No External VPN associated with ext nw {} for router {}",
665 extNwId, routerName);
669 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
670 if (extNwProvType == null) {
673 String gwMacAddress = null;
674 Uint32 l3Vni = Uint32.ZERO;
675 if (extNwProvType == ProviderTypes.VXLAN) {
676 // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
677 gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
678 if (gwMacAddress != null) {
679 LOG.debug("hndlTepAddForDnatInEachRtr : External GwMAC address {} found for External Router ID {}",
680 gwMacAddress, routerId);
682 LOG.error("hndlTepAddForDnatInEachRtr : No External GwMAC address found for External Router ID {}",
686 //get l3Vni value for external VPN
687 l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
688 if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
689 LOG.debug("hndlTepAddForDnatInEachRtr : L3VNI value is not configured in Internet VPN {} and RD {} "
690 + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
691 + "NAT flows", vpnName, rd);
692 l3Vni = natOverVxlanUtil.getInternetVpnVni(vpnName, routerId);
695 for (Ports port : routerPorts.nonnullPorts()) {
696 //Get the DPN on which this interface resides
697 final String interfaceName = port.getPortName();
698 final Uint64 fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
699 if (fipCfgdDpnId.equals(Uint64.ZERO)) {
700 LOG.info("hndlTepAddForDnatInEachRtr : DNAT->Skip processing Floating ip configuration for the port {},"
701 + "since no DPN present for it", interfaceName);
704 if (!fipCfgdDpnId.equals(tepAddedDpnId)) {
705 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> TEP added DPN {} is not the DPN {} which has the "
706 + "floating IP configured for the port: {}",
707 tepAddedDpnId, fipCfgdDpnId, interfaceName);
710 for (InternalToExternalPortMap intExtPortMap : port.nonnullInternalToExternalPortMap()) {
711 final String internalIp = intExtPortMap.getInternalIp();
712 final String externalIp = intExtPortMap.getExternalIp();
713 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertising the FIB route to the floating IP {} "
714 + "configured for the port: {}", externalIp, interfaceName);
715 Uint32 serviceId = null;
716 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
718 if (extNwProvType == ProviderTypes.VXLAN) {
719 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertise the route to the externalIp {} "
720 + "having nextHopIp {}", externalIp, nextHopIp);
721 NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, vpnName, rd,
722 externalIp, nextHopIp, l3Vni, interfaceName, gwMacAddress, confTx, RouteOrigin.STATIC,
723 fipCfgdDpnId, extNwId);
726 serviceId = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
727 if (serviceId == null || serviceId == NatConstants.INVALID_ID) {
728 LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Unable to advertise to the DC GW since label "
732 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertise the route to the externalIp {} "
733 + "having nextHopIp {}", externalIp, nextHopIp);
734 Uint32 l3vni = Uint32.ZERO;
735 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
736 l3vni = natOverVxlanUtil.getInternetVpnVni(vpnName, l3vni);
738 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd,
739 fibExternalIp, nextHopIp, null, null, serviceId, l3vni,
740 RouteOrigin.STATIC, fipCfgdDpnId);
743 //Install custom FIB routes (Table 21 -> Push MPLS label to Tunnel port
744 List<Instruction> customInstructions = new ArrayList<>();
745 customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(0));
746 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
747 .setSourceDpid(fipCfgdDpnId).setInstruction(customInstructions)
748 .setIpAddressSource(FibEntryInputs.IpAddressSource.FloatingIP)
749 .setIpAddress(fibExternalIp).setServiceId(serviceId).setInstruction(customInstructions)
751 ListenableFuture<RpcResult<CreateFibEntryOutput>> listenableFuture =
752 fibRpcService.createFibEntry(input);
754 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
757 public void onFailure(@NonNull Throwable error) {
758 LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Error in generate label or fib install process",
763 public void onSuccess(@NonNull RpcResult<CreateFibEntryOutput> result) {
764 if (result.isSuccessful()) {
765 LOG.info("hndlTepAddForDnatInEachRtr : DNAT -> Successfully installed custom FIB routes "
766 + "for prefix {}", externalIp);
768 LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Error in rpc call to create custom Fib "
769 + "entries for prefix {} in DPN {}, {}", externalIp, fipCfgdDpnId, result.getErrors());
772 }, MoreExecutors.directExecutor());
777 protected boolean isTunnelInLogicalGroup(StateTunnelList stateTunnelList) {
778 String ifaceName = stateTunnelList.getTunnelInterfaceName();
779 if (getTunnelType(stateTunnelList) == NatConstants.ITMTunnelLocType.Internal.getValue()) {
780 Interface configIface = interfaceManager.getInterfaceInfoFromConfigDataStore(ifaceName);
781 IfTunnel ifTunnel = configIface != null ? configIface.augmentation(IfTunnel.class) : null;
782 if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) {
783 ParentRefs refs = configIface.augmentation(ParentRefs.class);
784 if (refs != null && !Strings.isNullOrEmpty(refs.getParentInterface())) {
785 return true; //multiple VxLAN tunnels enabled, i.e. only logical tunnel should be treated
789 LOG.trace("isTunnelInLogicalGroup: ignoring the tunnel event for {}", ifaceName);