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.util.ArrayList;
20 import java.util.Collection;
21 import java.util.List;
22 import java.util.concurrent.ExecutionException;
23 import javax.annotation.PostConstruct;
24 import javax.inject.Inject;
25 import javax.inject.Singleton;
26 import org.eclipse.jdt.annotation.NonNull;
27 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
30 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
31 import org.opendaylight.genius.infra.Datastore.Configuration;
32 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
33 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
34 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
35 import org.opendaylight.genius.infra.TypedWriteTransaction;
36 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
37 import org.opendaylight.genius.mdsalutil.BucketInfo;
38 import org.opendaylight.genius.mdsalutil.FlowEntity;
39 import org.opendaylight.genius.mdsalutil.MDSALUtil;
40 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
41 import org.opendaylight.genius.mdsalutil.NwConstants;
42 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
43 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
44 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
45 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
46 import org.opendaylight.netvirt.elanmanager.api.IElanService;
47 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
48 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
49 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.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
86 extends AsyncDataTreeChangeListenerBase<StateTunnelList, NatTunnelInterfaceStateListener> {
88 private static final Logger LOG = LoggerFactory.getLogger(NatTunnelInterfaceStateListener.class);
89 private final DataBroker dataBroker;
90 private final ManagedNewTransactionRunner txRunner;
91 private final IFibManager fibManager;
92 private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
93 private final NaptSwitchHA naptSwitchHA;
94 private final IMdsalApiManager mdsalManager;
95 private final IdManagerService idManager;
96 private final IBgpManager bgpManager;
97 private final ExternalRoutersListener externalRouterListner;
98 private final SnatServiceManager natServiceManager;
99 private final OdlInterfaceRpcService interfaceService;
100 private final FloatingIPListener floatingIPListener;
101 private final FibRpcService fibRpcService;
102 private final IElanService elanManager;
103 private final IInterfaceManager interfaceManager;
104 private final NatOverVxlanUtil natOverVxlanUtil;
105 private final NatMode natMode;
107 protected enum TunnelAction {
114 * Responsible for listening to tunnel interface state change.
116 * @param dataBroker - dataBroker service reference
117 * @param bgpManager Used to advertise routes to the BGP Router
118 * @param fibManager - FIB Manager
119 * @param defaultRouteProgrammer - Default Route Programmer
120 * @param naptSwitchHA - NAPT Switch HA
121 * @param mdsalManager - MDSAL Manager
122 * @param idManager - ID manager
123 * @param externalRouterListner - External Router Listener
124 * @param natServiceManager - Nat Service Manager
125 * @param interfaceService - Interface Service
126 * @param floatingIPListener - Floating IP Listener
127 * @param fibRpcService - FIB RPC Service
128 * @param config - Nat Service Config
129 * @param elanManager - Elan Manager
130 * @param interfaceManager - Interface Manager
131 * @param natOverVxlanUtils - Nat Over Vxlan Utility
134 public NatTunnelInterfaceStateListener(final DataBroker dataBroker,
135 final IBgpManager bgpManager,
136 final IFibManager fibManager,
137 final SNATDefaultRouteProgrammer defaultRouteProgrammer,
138 final NaptSwitchHA naptSwitchHA,
139 final IMdsalApiManager mdsalManager,
140 final IdManagerService idManager,
141 final ExternalRoutersListener externalRouterListner,
142 final SnatServiceManager natServiceManager,
143 final OdlInterfaceRpcService interfaceService,
144 final FloatingIPListener floatingIPListener,
145 final FibRpcService fibRpcService,
146 final NatserviceConfig config,
147 final IElanService elanManager,
148 final IInterfaceManager interfaceManager,
149 final NatOverVxlanUtil natOverVxlanUtils) {
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 this.natOverVxlanUtil = natOverVxlanUtils;
167 if (config != null) {
168 this.natMode = config.getNatMode();
170 this.natMode = NatMode.Controller;
177 LOG.info("{} init", getClass().getSimpleName());
178 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
182 protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
183 return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
187 protected NatTunnelInterfaceStateListener getDataTreeChangeListener() {
188 return NatTunnelInterfaceStateListener.this;
192 protected void add(InstanceIdentifier<StateTunnelList> instanceIdentifier, StateTunnelList add) {
193 LOG.trace("add : TEP addtion---- {}", add);
194 hndlTepEvntsForDpn(add, TunnelAction.TUNNEL_EP_ADD);
198 protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
199 LOG.trace("remove : TEP deletion---- {}", del);
200 // Moved the remove implementation logic to NatTepChangeLister.remove()
204 protected void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original,
205 StateTunnelList update) {
206 LOG.trace("update : Tunnel updation---- {}", update);
207 //UPDATE IS A SEQUENCE OF DELETE AND ADD EVENTS . DELETE MIGHT HAVE CHANGED THE PRIMARY AND ADVERTISED. SO
211 private int getTunnelType(StateTunnelList stateTunnelList) {
213 if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
214 tunTypeVal = NatConstants.ITMTunnelLocType.Internal.getValue();
215 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
216 tunTypeVal = NatConstants.ITMTunnelLocType.External.getValue();
217 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
218 tunTypeVal = NatConstants.ITMTunnelLocType.Hwvtep.getValue();
220 tunTypeVal = NatConstants.ITMTunnelLocType.Invalid.getValue();
225 private void hndlTepEvntsForDpn(StateTunnelList stateTunnelList, TunnelAction tunnelAction) {
226 LOG.trace("hndlTepEvntsForDpn : stateTunnelList {}", stateTunnelList);
227 final Uint64 srcDpnId = stateTunnelList.getSrcInfo() != null
228 ? Uint64.valueOf(stateTunnelList.getSrcInfo().getTepDeviceId()) : Uint64.ZERO;
229 final String srcTepIp = stateTunnelList.getSrcInfo() != null
230 ? stateTunnelList.getSrcInfo().getTepIp().stringValue() : null;
231 final String destTepIp = stateTunnelList.getDstInfo() != null
232 ? stateTunnelList.getDstInfo().getTepIp().stringValue() : null;
233 LOG.trace("hndlTepEvntsForDpn : Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ",
234 srcDpnId, srcTepIp, destTepIp);
235 if (srcDpnId == Uint64.ZERO || srcTepIp == null || destTepIp == null) {
236 LOG.error("hndlTepEvntsForDpn invalid srcDpnId {}, srcTepIp {}, destTepIp {}",
237 srcDpnId, srcTepIp, destTepIp);
240 int tunTypeVal = getTunnelType(stateTunnelList);
241 LOG.trace("hndlTepEvntsForDpn : tunTypeVal is {}", tunTypeVal);
242 String srcTepId = stateTunnelList.getSrcInfo().getTepDeviceId() != null
243 ? stateTunnelList.getSrcInfo().getTepDeviceId() : "0";
244 String tunnelType = stateTunnelList.getTransportType() != null
245 ? stateTunnelList.getTransportType().toString() : null;
246 String tunnelName = stateTunnelList.getTunnelInterfaceName();
248 if (tunTypeVal == NatConstants.ITMTunnelLocType.Invalid.getValue() || srcDpnId.equals(Uint64.ZERO)
249 || srcTepIp == null || destTepIp == null) {
250 LOG.warn("hndlTepEvntsForDpn : Ignoring TEP event {} for the DPN {} "
251 + "since its a INVALID TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and " + "TUNNEL NAME {} ",
252 tunnelAction, srcTepId, tunnelType, srcTepIp, destTepIp, tunnelName);
256 switch (tunnelAction) {
259 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
260 if (isTunnelInLogicalGroup(stateTunnelList)
261 || !hndlTepAddForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp,
263 LOG.debug("hndlTepEvntsForDpn : Unable to process TEP ADD");
266 } catch (InterruptedException | ExecutionException e) {
267 LOG.error("Error processing tunnel endpoint addition", e);
270 case TUNNEL_EP_DELETE:
271 // Moved the current implementation logic to NatTepChangeListener.remove()
273 case TUNNEL_EP_UPDATE:
276 LOG.warn("hndlTepEvntsForDpn: unknown tunnelAction: {}", tunnelAction);
281 private boolean hndlTepAddForAllRtrs(Uint64 srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
282 String destTepIp, TypedReadWriteTransaction<Configuration> writeFlowInvTx)
283 throws ExecutionException, InterruptedException {
284 LOG.trace("hndlTepAddForAllRtrs: TEP ADD ----- for EXTERNAL/HWVTEP ITM Tunnel, TYPE {} ,State is UP b/w SRC IP"
285 + " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
287 InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
288 Optional<DpnRoutersList> optionalRouterDpnList =
289 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
290 LogicalDatastoreType.OPERATIONAL, dpnRoutersListId);
291 if (!optionalRouterDpnList.isPresent()) {
292 LOG.info("hndlTepAddForAllRtrs : RouterDpnList model is empty for DPN {}. Hence ignoring TEP add event "
293 + "for the ITM TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ",
294 srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
298 List<RoutersList> routersList = optionalRouterDpnList.get().getRoutersList();
299 if (routersList == null) {
300 LOG.debug("hndlTepAddForAllRtrs : Ignoring TEP add for the DPN {} since no routers are associated"
301 + " for the DPN having the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
302 + "TUNNEL NAME {} ", srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
306 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
307 for (RoutersList router : routersList) {
308 String routerName = router.getRouter();
309 Uint32 routerId = NatUtil.getVpnId(dataBroker, routerName);
310 if (routerId == NatConstants.INVALID_ID) {
311 LOG.error("hndlTepAddForAllRtrs :Invalid ROUTER-ID {} returned for routerName {}",
312 routerId, routerName);
315 LOG.debug("hndlTepAddForAllRtrs : TEP ADD : DNAT -> Advertising routes for router {} ", routerName);
316 Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
317 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
318 routerName, externalNetworkId);
319 if (extNwProvType == null) {
322 hndlTepAddForDnatInEachRtr(router, routerId, nextHopIp, srcDpnId, extNwProvType, writeFlowInvTx);
324 LOG.debug("hndlTepAddForAllRtrs : TEP ADD : SNAT -> Advertising routes for router {} ", routerName);
325 hndlTepAddForSnatInEachRtr(router, routerId, srcDpnId, tunnelType, srcTepIp, destTepIp,
326 tunnelName, nextHopIp, extNwProvType, writeFlowInvTx);
331 private void hndlTepAddForSnatInEachRtr(RoutersList router, Uint32 routerId, final Uint64 srcDpnId,
332 String tunnelType, String srcTepIp, String destTepIp, String tunnelName, String nextHopIp,
333 ProviderTypes extNwProvType, TypedReadWriteTransaction<Configuration> writeFlowInvTx)
334 throws ExecutionException, InterruptedException {
336 /*SNAT : Remove the old routes to the external IP having the old TEP IP as the next hop IP
337 Advertise to the BGP about the new route to the external IP having the new TEP IP
338 added as the next hop IP
340 String routerName = router.getRouter();
342 // Check if this is externalRouter else ignore
343 InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
344 Optional<Routers> routerData;
346 routerData = writeFlowInvTx.read(extRoutersId).get();
347 } catch (InterruptedException | ExecutionException e) {
348 LOG.error("Error reading router data for {}", extRoutersId, e);
349 routerData = Optional.absent();
351 if (!routerData.isPresent()) {
352 LOG.warn("hndlTepAddForSnatInEachRtr : SNAT->Ignoring TEP add for router {} since its not External Router",
357 Uint64 naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
358 if (naptId == null || naptId.equals(Uint64.ZERO)) {
359 LOG.warn("hndlTepAddForSnatInEachRtr : SNAT -> Ignoring TEP add for the DPN {} having the router {} since"
360 + " the router is not part of the NAT service - the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
361 + "TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
364 if (natMode == NatMode.Conntrack) {
365 Routers extRouter = routerData.get();
366 natServiceManager.notify(writeFlowInvTx, extRouter, null, naptId, srcDpnId,
367 SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_ENBL);
368 if (extRouter.isEnableSnat()) {
369 natServiceManager.notify(writeFlowInvTx, extRouter, null, naptId, srcDpnId,
370 SnatServiceManager.Action.SNAT_ROUTER_ENBL);
373 Uuid bgpVpnUuId = NatUtil.getVpnForRouter(dataBroker, routerName);
374 //Check if the DPN having the router is the NAPT switch
375 if (!naptId.equals(srcDpnId)) {
377 1) Install default NAT rule from table 21 to 26
378 2) Install the group which forward packet to the tunnel port for the NAPT switch.
379 3) Install the flow 26 which forwards the packet to the group.
381 if (!hndlTepAddOnNonNaptSwitch(srcDpnId, naptId, tunnelType, srcTepIp, destTepIp, tunnelName,
382 routerName, routerId, bgpVpnUuId, writeFlowInvTx)) {
383 LOG.error("hndlTepAddForSnatInEachRtr : Unable to process the TEP add event on NON-NAPT switch {}",
389 if (!hndlTepAddOnNaptSwitch(srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName, routerId,
390 routerData, nextHopIp, bgpVpnUuId, extNwProvType, writeFlowInvTx)) {
391 LOG.debug("hndlTepAddForSnatInEachRtr : Unable to process the TEP add event on NAPT switch {}",
399 private boolean hndlTepAddOnNonNaptSwitch(Uint64 srcDpnId, Uint64 primaryDpnId, String tunnelType,
400 String srcTepIp, String destTepIp, String tunnelName, String routerName, Uint32 routerId, Uuid vpnName,
401 TypedWriteTransaction<Configuration> confTx) {
404 1) Install default NAT rule from table 21 to 26
405 2) Install the group which forward packet to the tunnel port for the NAPT switch.
406 3) Install the flow 26 which forwards the packet to the group.
408 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Processing TEP add for the DPN {} having the router {} since "
409 + "its THE NON NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
410 + "and TUNNEL NAME {} ",
411 srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
412 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Install default NAT rule from table 21 to 26");
414 if (vpnName == null) {
415 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Internal VPN associated to router {}", routerId);
417 if (vpnId == NatConstants.INVALID_ID) {
418 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid Internal VPN ID returned for routerName {}",
422 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerName);
423 //Install default entry in FIB to SNAT table
424 LOG.debug("hndlTepAddOnNonNaptSwitch : Installing default route in FIB on DPN {} for router {} with"
425 + " vpn {}...", srcDpnId, routerName, vpnId);
426 defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, confTx);
428 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Install the group which forward packet to the tunnel port "
429 + "for the NAPT switch {} and the flow 26 which forwards to group", primaryDpnId);
430 externalRouterListner.handleSwitches(srcDpnId, routerName, routerId, primaryDpnId);
432 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> External BGP VPN (Private BGP) associated to router {}",
434 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
435 if (vpnId == NatConstants.INVALID_ID) {
436 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid Private BGP VPN ID returned for routerName {}",
440 if (routerId == NatConstants.INVALID_ID) {
441 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid routId returned for routerName {}", routerId);
444 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
445 //Install default entry in FIB to SNAT table
446 LOG.debug("hndlTepAddOnNonNaptSwitch : Installing default route in FIB on dpn {} for routerId {} "
447 + "with vpnId {}...", srcDpnId, routerId, vpnId);
448 defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, routerId, confTx);
450 LOG.debug("hndlTepAddOnNonNaptSwitch : Install group in non NAPT switch {} for router {}",
451 srcDpnId, routerName);
452 List<BucketInfo> bucketInfoForNonNaptSwitches =
453 externalRouterListner.getBucketInfoForNonNaptSwitches(srcDpnId, primaryDpnId, routerName, routerId);
454 Uint32 groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME,
455 NatUtil.getGroupIdKey(routerName));
456 if (groupId != NatConstants.INVALID_ID) {
457 externalRouterListner.installGroup(srcDpnId, routerName, groupId, bucketInfoForNonNaptSwitches);
458 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> in the SNAT miss entry pointing to group {} "
459 + "in the non NAPT switch {}", groupId, srcDpnId);
460 FlowEntity flowEntity =
461 externalRouterListner.buildSnatFlowEntityWithUpdatedVpnId(srcDpnId, routerName, groupId, vpnId);
462 mdsalManager.addFlow(confTx, flowEntity);
464 LOG.error("hndlTepAddOnNonNaptSwitch: Unable to obtain group ID for Key: {}", routerName);
470 private boolean hndlTepAddOnNaptSwitch(Uint64 srcDpnId, String tunnelType, String srcTepIp,
471 String destTepIp, String tunnelName, Uint32 routerId,
472 Optional<Routers> routerData, String nextHopIp, Uuid vpnName,
473 ProviderTypes extNwProvType, TypedWriteTransaction<Configuration> confTx) {
474 if (!routerData.isPresent()) {
475 LOG.warn("hndlTepAddOnNaptSwitch: routerData is not present");
478 Routers router = routerData.get();
479 String routerName = router.getRouterName();
480 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Processing TEP add for the DPN {} having the router {} since "
481 + "its THE NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
482 + "and TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
484 Uuid networkId = router.getNetworkId();
485 if (networkId == null) {
486 LOG.warn("hndlTepAddOnNaptSwitch : SNAT -> Ignoring TEP add since the router {} is not associated to the "
487 + "external network", routerName);
491 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Router {} is associated with Ext nw {}", routerId, networkId);
493 if (vpnName == null) {
494 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Internal VPN associated to router {}", routerId);
495 vpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
496 if (vpnId == NatConstants.INVALID_ID) {
497 LOG.error("hndlTepAddOnNaptSwitch : Invalid External VPN-ID returned for routerName {}", routerName);
500 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Retrieved External VPN-ID {} for router {}", vpnId, routerId);
502 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Private BGP VPN associated to router {}", routerId);
503 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
504 if (vpnId == NatConstants.INVALID_ID) {
505 LOG.error("hndlTepAddOnNaptSwitch : Invalid vpnId returned for routerName {}", routerName);
508 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
511 /*1) Withdraw the old route to the external IP from the BGP which was having the
512 next hop as the old TEP IP.
513 2) Advertise to the BGP about the new route to the external IP having the
514 new TEP IP as the next hop.
515 3) Populate a new FIB entry with the next hop IP as the new TEP IP using the
519 //Withdraw the old route to the external IP from the BGP which was having the
520 //next hop as the old TEP IP.
521 final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
522 if (externalVpnName == null) {
523 LOG.error("hndlTepAddOnNaptSwitch : SNAT -> No VPN associated with ext nw {} in router {}",
524 networkId, routerId);
527 Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
528 LOG.debug("hndlTepAddOnNaptSwitch : Clearing the FIB entries but not the BGP routes");
529 for (String externalIp : externalIps) {
530 String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
531 LOG.debug("hndlTepAddOnNaptSwitch : Removing Fib entry rd {} prefix {}", rd, externalIp);
532 fibManager.removeFibEntry(rd, externalIp, null, null);
536 Advertise to the BGP about the new route to the external IP having the
537 new TEP IP as the next hop.
538 Populate a new FIB entry with the next hop IP as the new TEP IP using the
541 String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
542 if (extNwProvType == null) {
545 String gwMacAddress = null;
546 Uint32 l3Vni = Uint32.ZERO;
547 if (extNwProvType == ProviderTypes.VXLAN) {
548 // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
549 gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
550 if (gwMacAddress != null) {
551 LOG.debug("hndlTepAddOnNaptSwitch : External Gateway MAC address {} found for External Router ID {}",
552 gwMacAddress, routerId);
554 LOG.error("hndlTepAddOnNaptSwitch : No External Gateway MAC address found for External Router ID {}",
558 //get l3Vni value for external VPN
559 l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
560 if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
561 LOG.debug("hndlTepAddOnNaptSwitch : L3VNI value is not configured in Internet VPN {} and RD {} "
562 + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
563 + "NAT flows", vpnName, rd);
564 l3Vni = natOverVxlanUtil.getInternetVpnVni(externalVpnName, routerId);
568 for (final String externalIp : externalIps) {
569 Uint32 serviceId = null;
570 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
571 if (extNwProvType == ProviderTypes.VXLAN) {
572 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Advertise the route to the externalIp {} "
573 + "having nextHopIp {}", externalIp, nextHopIp);
574 NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, externalVpnName, rd,
575 externalIp, nextHopIp, l3Vni, tunnelName, gwMacAddress, confTx, RouteOrigin.STATIC,
576 srcDpnId, networkId);
580 serviceId = externalRouterListner.checkExternalIpLabel(routerId,
582 if (serviceId == null || serviceId == NatConstants.INVALID_ID) {
583 LOG.error("hndlTepAddOnNaptSwitch : SNAT->Unable to advertise to the DC GW "
584 + "since label is invalid");
587 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Advertise the route to the externalIp {} "
588 + "having nextHopIp {}", externalIp, nextHopIp);
589 Uint32 l3vni = Uint32.ZERO;
590 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
591 l3vni = natOverVxlanUtil.getInternetVpnVni(externalVpnName, l3vni);
593 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, externalVpnName, rd,
594 fibExternalIp, nextHopIp, networkId.getValue(), null /* mac-address */, serviceId, l3vni,
595 RouteOrigin.STATIC, srcDpnId);
598 LOG.debug("hndlTepAddOnNaptSwitch: SNAT -> Install custom FIB routes "
599 + "(Table 21 -> Push MPLS label to Tunnel port");
600 List<Instruction> customInstructions = new ArrayList<>();
601 int customInstructionIndex = 0;
602 Uint32 externalSubnetVpnId = NatUtil.getExternalSubnetVpnIdForRouterExternalIp(dataBroker, externalIp,
604 if (externalSubnetVpnId != NatConstants.INVALID_ID) {
605 LOG.debug("hndlTepAddOnNaptSwitch : Will install custom FIB router with external subnet VPN ID {}",
606 externalSubnetVpnId);
607 Uint64 subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(externalSubnetVpnId.longValue());
608 customInstructions.add(new InstructionWriteMetadata(subnetIdMetaData,
609 MetaDataUtil.METADATA_MASK_VRFID).buildInstruction(customInstructionIndex));
610 customInstructionIndex++;
612 customInstructions.add(new InstructionGotoTable(NwConstants.INBOUND_NAPT_TABLE)
613 .buildInstruction(customInstructionIndex));
614 CreateFibEntryInput input =
615 new CreateFibEntryInputBuilder().setVpnName(externalVpnName).setSourceDpid(srcDpnId)
616 .setInstruction(customInstructions).setIpAddress(fibExternalIp)
617 .setIpAddressSource(FibEntryInputs.IpAddressSource.ExternalFixedIP)
618 .setServiceId(serviceId).setInstruction(customInstructions).build();
619 ListenableFuture<RpcResult<CreateFibEntryOutput>> listenableFuture = fibRpcService.createFibEntry(input);
621 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
624 public void onFailure(@NonNull Throwable error) {
625 LOG.error("hndlTepAddOnNaptSwitch : SNAT->Error in generate label or fib install process",
630 public void onSuccess(@NonNull RpcResult<CreateFibEntryOutput> result) {
631 if (result.isSuccessful()) {
632 LOG.info("hndlTepAddOnNaptSwitch : SNAT -> Successfully installed custom FIB routes "
633 + "for prefix {}", externalIp);
635 LOG.error("hndlTepAddOnNaptSwitch : SNAT -> Error in rpc call to create custom Fib entries "
636 + "for prefix {} in DPN {}, {}", externalIp, srcDpnId, result.getErrors());
639 }, MoreExecutors.directExecutor());
645 private void hndlTepAddForDnatInEachRtr(RoutersList router, Uint32 routerId, String nextHopIp,
646 Uint64 tepAddedDpnId, ProviderTypes extNwProvType, TypedWriteTransaction<Configuration> confTx) {
647 //DNAT : Advertise the new route to the floating IP having the new TEP IP as the next hop IP
648 final String routerName = router.getRouter();
650 InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
651 Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType
652 .CONFIGURATION, routerPortsId);
653 if (!optRouterPorts.isPresent()) {
654 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Could not read Router Ports data object with id: {} "
655 + "from DNAT FloatinIpInfo", routerName);
658 RouterPorts routerPorts = optRouterPorts.get();
659 Uuid extNwId = routerPorts.getExternalNetworkId();
660 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId);
661 if (vpnName == null) {
662 LOG.info("hndlTepAddForDnatInEachRtr : DNAT -> No External VPN associated with ext nw {} for router {}",
663 extNwId, routerName);
667 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
668 if (extNwProvType == null) {
671 String gwMacAddress = null;
672 Uint32 l3Vni = Uint32.ZERO;
673 if (extNwProvType == ProviderTypes.VXLAN) {
674 // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
675 gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
676 if (gwMacAddress != null) {
677 LOG.debug("hndlTepAddForDnatInEachRtr : External GwMAC address {} found for External Router ID {}",
678 gwMacAddress, routerId);
680 LOG.error("hndlTepAddForDnatInEachRtr : No External GwMAC address found for External Router ID {}",
684 //get l3Vni value for external VPN
685 l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
686 if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
687 LOG.debug("hndlTepAddForDnatInEachRtr : L3VNI value is not configured in Internet VPN {} and RD {} "
688 + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
689 + "NAT flows", vpnName, rd);
690 l3Vni = natOverVxlanUtil.getInternetVpnVni(vpnName, routerId);
693 for (Ports port : routerPorts.nonnullPorts()) {
694 //Get the DPN on which this interface resides
695 final String interfaceName = port.getPortName();
696 final Uint64 fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
697 if (fipCfgdDpnId.equals(Uint64.ZERO)) {
698 LOG.info("hndlTepAddForDnatInEachRtr : DNAT->Skip processing Floating ip configuration for the port {},"
699 + "since no DPN present for it", interfaceName);
702 if (!fipCfgdDpnId.equals(tepAddedDpnId)) {
703 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> TEP added DPN {} is not the DPN {} which has the "
704 + "floating IP configured for the port: {}",
705 tepAddedDpnId, fipCfgdDpnId, interfaceName);
708 for (InternalToExternalPortMap intExtPortMap : port.nonnullInternalToExternalPortMap()) {
709 final String internalIp = intExtPortMap.getInternalIp();
710 final String externalIp = intExtPortMap.getExternalIp();
711 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertising the FIB route to the floating IP {} "
712 + "configured for the port: {}", externalIp, interfaceName);
713 Uint32 serviceId = null;
714 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
716 if (extNwProvType == ProviderTypes.VXLAN) {
717 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertise the route to the externalIp {} "
718 + "having nextHopIp {}", externalIp, nextHopIp);
719 NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, vpnName, rd,
720 externalIp, nextHopIp, l3Vni, interfaceName, gwMacAddress, confTx, RouteOrigin.STATIC,
721 fipCfgdDpnId, extNwId);
724 serviceId = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
725 if (serviceId == null || serviceId == NatConstants.INVALID_ID) {
726 LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Unable to advertise to the DC GW since label "
730 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertise the route to the externalIp {} "
731 + "having nextHopIp {}", externalIp, nextHopIp);
732 Uint32 l3vni = Uint32.ZERO;
733 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
734 l3vni = natOverVxlanUtil.getInternetVpnVni(vpnName, l3vni);
736 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd,
737 fibExternalIp, nextHopIp, null, null, serviceId, l3vni,
738 RouteOrigin.STATIC, fipCfgdDpnId);
741 //Install custom FIB routes (Table 21 -> Push MPLS label to Tunnel port
742 List<Instruction> customInstructions = new ArrayList<>();
743 customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(0));
744 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
745 .setSourceDpid(fipCfgdDpnId).setInstruction(customInstructions)
746 .setIpAddressSource(FibEntryInputs.IpAddressSource.FloatingIP)
747 .setIpAddress(fibExternalIp).setServiceId(serviceId).setInstruction(customInstructions)
749 ListenableFuture<RpcResult<CreateFibEntryOutput>> listenableFuture =
750 fibRpcService.createFibEntry(input);
752 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
755 public void onFailure(@NonNull Throwable error) {
756 LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Error in generate label or fib install process",
761 public void onSuccess(@NonNull RpcResult<CreateFibEntryOutput> result) {
762 if (result.isSuccessful()) {
763 LOG.info("hndlTepAddForDnatInEachRtr : DNAT -> Successfully installed custom FIB routes "
764 + "for prefix {}", externalIp);
766 LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Error in rpc call to create custom Fib "
767 + "entries for prefix {} in DPN {}, {}", externalIp, fipCfgdDpnId, result.getErrors());
770 }, MoreExecutors.directExecutor());
775 protected boolean isTunnelInLogicalGroup(StateTunnelList stateTunnelList) {
776 String ifaceName = stateTunnelList.getTunnelInterfaceName();
777 if (getTunnelType(stateTunnelList) == NatConstants.ITMTunnelLocType.Internal.getValue()) {
778 Interface configIface = interfaceManager.getInterfaceInfoFromConfigDataStore(ifaceName);
779 IfTunnel ifTunnel = configIface != null ? configIface.augmentation(IfTunnel.class) : null;
780 if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) {
781 ParentRefs refs = configIface.augmentation(ParentRefs.class);
782 if (refs != null && !Strings.isNullOrEmpty(refs.getParentInterface())) {
783 return true; //multiple VxLAN tunnels enabled, i.e. only logical tunnel should be treated
787 LOG.trace("isTunnelInLogicalGroup: ignoring the tunnel event for {}", ifaceName);