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 com.google.common.base.Optional;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.JdkFutureAdapters;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import java.math.BigInteger;
17 import java.util.ArrayList;
18 import java.util.HashMap;
19 import java.util.List;
20 import java.util.concurrent.Future;
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
24 import org.opendaylight.genius.mdsalutil.BucketInfo;
25 import org.opendaylight.genius.mdsalutil.FlowEntity;
26 import org.opendaylight.genius.mdsalutil.GroupEntity;
27 import org.opendaylight.genius.mdsalutil.MDSALUtil;
28 import org.opendaylight.genius.mdsalutil.NwConstants;
29 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
30 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
31 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
32 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
33 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersList;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.dpn.routers.list.RoutersList;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
55 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
56 import org.opendaylight.yangtools.yang.common.RpcResult;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
60 public class NatTunnelInterfaceStateListener
61 extends AsyncDataTreeChangeListenerBase<StateTunnelList, NatTunnelInterfaceStateListener>
62 implements AutoCloseable {
64 private static final Logger LOG = LoggerFactory.getLogger(NatTunnelInterfaceStateListener.class);
65 private final DataBroker dataBroker;
66 private IFibManager fibManager;
67 private SNATDefaultRouteProgrammer defaultRouteProgrammer;
68 private NaptSwitchHA naptSwitchHA;
69 private IMdsalApiManager mdsalManager;
70 private IdManagerService idManager;
71 private IBgpManager bgpManager;
72 private ExternalRoutersListener externalRouterListner;
73 private OdlInterfaceRpcService interfaceService;
74 private FloatingIPListener floatingIPListener;
75 private FibRpcService fibRpcService;
77 protected enum TunnelAction {
84 * Responsible for listening to tunnel interface state change.
86 * @param dataBroker - dataBroker service reference
87 * @param bgpManager Used to advertise routes to the BGP Router
88 * @param fibManager - FIB Manager
89 * @param defaultRouteProgrammer - Default Route Programmer
90 * @param naptSwitchHA - NAPT Switch HA
91 * @param mdsalManager - MDSAL Manager
92 * @param idManager - ID manager
93 * @param externalRouterListner - External Router Listner
94 * @param interfaceService - Interface Service
95 * @param floatingIPListener - Floating IP Listner
96 * @param fibRpcService - FIB RPC Service
98 public NatTunnelInterfaceStateListener(final DataBroker dataBroker,
99 final IBgpManager bgpManager,
100 final IFibManager fibManager,
101 final SNATDefaultRouteProgrammer defaultRouteProgrammer,
102 final NaptSwitchHA naptSwitchHA,
103 final IMdsalApiManager mdsalManager,
104 final IdManagerService idManager,
105 final ExternalRoutersListener externalRouterListner,
106 final OdlInterfaceRpcService interfaceService,
107 final FloatingIPListener floatingIPListener,
108 final FibRpcService fibRpcService) {
109 super(StateTunnelList.class, NatTunnelInterfaceStateListener.class);
110 this.dataBroker = dataBroker;
111 this.bgpManager = bgpManager;
112 this.fibManager = fibManager;
113 this.defaultRouteProgrammer = defaultRouteProgrammer;
114 this.naptSwitchHA = naptSwitchHA;
115 this.mdsalManager = mdsalManager;
116 this.idManager = idManager;
117 this.externalRouterListner = externalRouterListner;
118 this.interfaceService = interfaceService;
119 this.floatingIPListener = floatingIPListener;
120 this.fibRpcService = fibRpcService;
125 LOG.info("{} init", getClass().getSimpleName());
126 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
130 protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
131 return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
135 protected NatTunnelInterfaceStateListener getDataTreeChangeListener() {
136 return NatTunnelInterfaceStateListener.this;
140 protected void add(InstanceIdentifier<StateTunnelList> instanceIdentifier, StateTunnelList add) {
141 LOG.trace("NAT Service : TEP addtion---- {}", add);
142 hndlTepEvntsForDpn(add, TunnelAction.TUNNEL_EP_ADD);
146 protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
147 LOG.trace("NAT Service : TEP deletion---- {}", del);
148 hndlTepEvntsForDpn(del, TunnelAction.TUNNEL_EP_DELETE);
152 protected void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original,
153 StateTunnelList update) {
154 LOG.trace("NAT Service : Tunnel updation---- {}", update);
155 //UPDATE IS A SEQUENCE OF DELETE AND ADD EVENTS . DELETE MIGHT HAVE CHANGED THE PRIMARY AND ADVERTISED. SO
159 private int getTunnelType(StateTunnelList stateTunnelList) {
161 if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
162 tunTypeVal = NatConstants.ITMTunnelLocType.Internal.getValue();
163 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
164 tunTypeVal = NatConstants.ITMTunnelLocType.External.getValue();
165 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
166 tunTypeVal = NatConstants.ITMTunnelLocType.Hwvtep.getValue();
168 tunTypeVal = NatConstants.ITMTunnelLocType.Invalid.getValue();
173 // TODO Clean up the exception handling
174 @SuppressWarnings("checkstyle:IllegalCatch")
175 void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerVpnId, Uuid networkId) {
176 //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
177 //remove miss entry to NAPT switch
178 //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
180 //get ExternalIpIn prior
181 List<String> externalIpCache;
183 HashMap<String, Long> externalIpLabel;
184 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
185 if (routerId == NatConstants.INVALID_ID) {
186 LOG.error("NAT Service : SNAT -> Invalid routerId returned for routerName {}", routerName);
189 externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
190 externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
192 final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
193 if (externalVpnName == null) {
194 LOG.error("NAT Service : SNAT -> No VPN associated with ext nw {} in router {}",
195 networkId, routerId);
199 BigInteger naptSwitch = dpnId;
201 naptSwitchHA.isNaptSwitchDown(routerName, dpnId, naptSwitch, routerVpnId, externalIpCache, false);
203 LOG.debug("NAT Service : SNAT -> NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
205 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
206 FlowEntity flowEntity = null;
208 flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId,
209 routerVpnId, NatConstants.DEL_FLOW);
210 if (flowEntity == null) {
211 LOG.debug("NAT Service : SNAT -> Failed to populate flowentity for "
212 + "router {} with dpnId {} groupIs {}", routerName, dpnId, groupId);
215 LOG.debug("NAT Service : SNAT -> Removing default SNAT miss entry flow entity {}", flowEntity);
216 mdsalManager.removeFlow(flowEntity);
218 } catch (Exception ex) {
219 LOG.debug("NAT Service : SNAT -> Failed to remove default SNAT miss entry flow entity {} : {}",
223 LOG.debug("NAT Service : SNAT -> Removed default SNAT miss entry flow for dpnID {} with routername {}",
227 GroupEntity groupEntity = null;
229 groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
230 GroupTypes.GroupAll, null);
231 LOG.info("NAT Service : SNAT -> Removing NAPT GroupEntity:{}", groupEntity);
232 mdsalManager.removeGroup(groupEntity);
233 } catch (Exception ex) {
234 LOG.debug("NAT Service : SNAT -> Failed to remove group entity {} : {}", groupEntity, ex);
237 LOG.debug("NAT Service : SNAT -> Removed default SNAT miss entry flow for dpnID {} with routerName {}",
240 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, dpnId, externalIpLabel);
241 //remove table 26 flow ppointing to table46
242 FlowEntity flowEntity = null;
244 flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId,
245 NatConstants.DEL_FLOW);
246 if (flowEntity == null) {
247 LOG.debug("NAT Service : SNAT -> Failed to populate flowentity for router {} with dpnId {}",
251 LOG.debug("NAT Service : SNAT -> Removing default SNAT miss entry flow entity for "
252 + "router {} with dpnId {} in napt switch {}", routerName, dpnId, naptSwitch);
253 mdsalManager.removeFlow(flowEntity);
255 } catch (Exception ex) {
256 LOG.debug("NAT Service : SNAT -> Failed to remove default SNAT miss entry flow entity {} : {}",
260 LOG.debug("NAT Service : SNAT -> Removed default SNAT miss entry flow for dpnID {} with routername {}",
263 //best effort to check IntExt model
264 naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel);
266 } catch (Exception ex) {
267 LOG.debug("NAT Service : SNAT -> Exception while handling naptSwitch down for router {} : {}",
272 // TODO Clean up the exception handling
273 @SuppressWarnings("checkstyle:IllegalCatch")
274 private void hndlTepEvntsForDpn(StateTunnelList stateTunnelList, TunnelAction tunnelAction) {
275 final BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
276 final String srcTepIp = String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue());
277 final String destTepIp = String.valueOf(stateTunnelList.getDstInfo().getTepIp().getValue());
278 LOG.trace("NAT Service : Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ", srcDpnId, srcTepIp,
280 int tunTypeVal = getTunnelType(stateTunnelList);
282 LOG.trace("NAT Service : tunTypeVal is {}", tunTypeVal);
285 String srcTepId = stateTunnelList.getSrcInfo().getTepDeviceId();
286 String tunnelType = stateTunnelList.getTransportType().toString();
287 String tunnelName = stateTunnelList.getTunnelInterfaceName();
289 if (tunTypeVal == NatConstants.ITMTunnelLocType.Invalid.getValue()) {
290 LOG.warn("NAT Service : Ignoring TEP event {} for the DPN {} "
291 + "since its a INVALID TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and " + "TUNNEL NAME {} ",
292 tunnelAction, srcTepId, tunnelType, srcTepIp, destTepIp, tunnelName);
296 switch (tunnelAction) {
298 if (!hndlTepAddForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp)) {
299 LOG.debug("NAT Service : Unable to process TEP ADD");
302 case TUNNEL_EP_DELETE:
303 if (!handleTepDelForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp)) {
304 LOG.debug("NAT Service : Unable to process TEP DEL");
308 LOG.warn("hndlTepEvntsForDpn: unknown tunnelAction: {}", tunnelAction);
311 } catch (Exception e) {
312 LOG.error("NAT Service : Unable to handle the TEP event.", e);
317 private boolean hndlTepAddForAllRtrs(BigInteger srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
318 String destTepIp) throws Exception {
319 LOG.trace("NAT Service: TEP ADD ----- for EXTERNAL/HWVTEP ITM Tunnel, TYPE {} ,State is UP b/w SRC IP"
320 + " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
322 InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
323 Optional<DpnRoutersList> optionalRouterDpnList = NatUtil.read(dataBroker, LogicalDatastoreType
324 .OPERATIONAL, dpnRoutersListId);
325 if (!optionalRouterDpnList.isPresent()) {
326 LOG.warn("NAT Service : RouterDpnList model is empty for DPN {}. Hence ignoring TEP add event for the ITM "
327 + "TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ",
328 srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
332 List<RoutersList> routersList = optionalRouterDpnList.get().getRoutersList();
333 if (routersList == null) {
334 LOG.debug("NAT Service : Ignoring TEP add for the DPN {} since no routers are associated"
335 + " for the DPN having the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
336 + "TUNNEL NAME {} ", srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
340 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
341 for (RoutersList router : routersList) {
343 LOG.debug("NAT Service : TEP ADD : DNAT -> Advertising routes for router {} ", router.getRouter());
344 hndlTepAddForDnatInEachRtr(router, nextHopIp, srcDpnId);
346 LOG.debug("NAT Service : TEP ADD : SNAT -> Advertising routes for router {} ", router.getRouter());
347 hndlTepAddForSnatInEachRtr(router, srcDpnId, tunnelType, srcTepIp, destTepIp,
348 tunnelName, nextHopIp);
353 // TODO Clean up the exception handling
354 @SuppressWarnings("checkstyle:IllegalCatch")
355 private boolean handleTepDelForAllRtrs(BigInteger srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
356 String destTepIp) throws Exception {
358 LOG.trace("NAT Service: TEP DEL ----- for EXTERNAL/HWVTEP ITM Tunnel, TYPE {} ,State is UP b/w SRC IP"
359 + " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
361 // When tunnel EP is deleted on a DPN , VPN gets two deletion event.
362 // One for a DPN on which tunnel EP was deleted and another for other-end DPN.
363 // Handle only the DPN on which it was deleted , ignore other event.
364 // DPN on which TEP is deleted , endpoint IP will be null.
365 String endpointIpForDPN = null;
367 endpointIpForDPN = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
368 } catch (Exception e) {
369 /* this dpn does not have the VTEP */
370 LOG.debug("NAT Service : DPN {} does not have the VTEP", srcDpnId);
371 endpointIpForDPN = null;
374 if (endpointIpForDPN != null) {
375 LOG.trace("NAT Service : Ignore TEP DELETE event received for DPN {} VTEP IP {} since its "
376 + "the other end DPN w.r.t the delted TEP", srcDpnId, srcTepIp);
380 List<RoutersList> routersList = null;
381 InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
382 Optional<DpnRoutersList> optionalRouterDpnList = NatUtil.read(dataBroker, LogicalDatastoreType
383 .OPERATIONAL, dpnRoutersListId);
384 if (optionalRouterDpnList.isPresent()) {
385 routersList = optionalRouterDpnList.get().getRoutersList();
387 LOG.warn("NAT Service : RouterDpnList is empty for DPN {}. Hence ignoring TEP DEL event for the ITM "
388 + "TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ",
389 srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
393 if (routersList == null) {
394 LOG.debug("NAT Service : DPN {} does not have the Routers presence", srcDpnId);
398 for (RoutersList router : routersList) {
399 LOG.debug("NAT Service : TEP DEL : DNAT -> Withdrawing routes for router {} ", router.getRouter());
400 hndlTepDelForDnatInEachRtr(router, srcDpnId);
401 LOG.debug("NAT Service : TEP DEL : SNAT -> Withdrawing and Advertising routes for router {} ",
403 hndlTepDelForSnatInEachRtr(router, srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
408 private void hndlTepAddForSnatInEachRtr(RoutersList router, final BigInteger srcDpnId, String tunnelType,
409 String srcTepIp, String destTepIp, String tunnelName, String nextHopIp) {
411 /*SNAT : Remove the old routes to the external IP having the old TEP IP as the next hop IP
412 Advertise to the BGP about the new route to the external IP having the new TEP IP
413 added as the next hop IP
415 String routerName = router.getRouter();
417 // Check if this is externalRouter else ignore
418 InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
419 Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType
420 .CONFIGURATION, extRoutersId);
421 if (!routerData.isPresent()) {
422 LOG.debug("NAT Service : SNAT -> Ignoring TEP add for router {} since its not External Router",
427 long routerId = NatUtil.getVpnId(dataBroker, routerName);
428 BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
429 if (naptId == null || naptId.equals(BigInteger.ZERO)) {
430 LOG.warn("NAT Service : SNAT -> Ignoring TEP add for the DPN {} having the router {} since"
431 + " the router is not part of the NAT service - the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
432 + "TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
436 //Check if the DPN having the router is the NAPT switch
437 if (!naptId.equals(srcDpnId)) {
439 1) Install default NAT rule from table 21 to 26
440 2) Install the group which forward packet to the tunnel port for the NAPT switch.
441 3) Install the flow 26 which forwards the packet to the group.
443 if (!hndlTepAddOnNonNaptSwitch(srcDpnId, naptId, tunnelType, srcTepIp, destTepIp, tunnelName,
444 routerName, routerId)) {
445 LOG.debug("NAT Service : Unable to process the TEP add event on NON-NAPT switch {}", srcDpnId);
450 if (!hndlTepAddOnNaptSwitch(srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName, routerId,
451 routerData, nextHopIp)) {
452 LOG.debug("NAT Service : Unable to process the TEP add event on NAPT switch {}", srcDpnId);
458 private boolean hndlTepAddOnNonNaptSwitch(BigInteger srcDpnId, BigInteger primaryDpnId, String tunnelType,
459 String srcTepIp, String destTepIp, String tunnelName, String routerName,
463 1) Install default NAT rule from table 21 to 26
464 2) Install the group which forward packet to the tunnel port for the NAPT switch.
465 3) Install the flow 26 which forwards the packet to the group.
467 LOG.debug("NAT Service : SNAT -> Processing TEP add for the DPN {} having the router {} since "
468 + "its THE NON NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
469 + "and TUNNEL NAME {} ",
470 srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
471 LOG.debug("NAT Service : SNAT -> Install default NAT rule from table 21 to 26");
472 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerName);
474 if (vpnName == null) {
475 LOG.debug("NAT Service : SNAT -> Internal VPN associated to router {}", routerId);
477 if (vpnId == NatConstants.INVALID_ID) {
478 LOG.error("NAT Service : SNAT -> Invalid Internal VPN ID returned for routerName {}", routerId);
481 LOG.debug("NAT Service : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerName);
482 //Install default entry in FIB to SNAT table
483 LOG.debug("NAT Service : Installing default route in FIB on DPN {} for router {} with"
484 + " vpn {}...", srcDpnId, routerName, vpnId);
485 defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId);
487 LOG.debug("NAT Service : SNAT -> Install the group which forward packet to the tunnel port "
488 + "for the NAPT switch {} and the flow 26 which forwards to group", primaryDpnId);
489 externalRouterListner.handleSwitches(srcDpnId, routerName, primaryDpnId);
491 LOG.debug("NAT Service : SNAT -> External BGP VPN (Private BGP) associated to router {}", routerId);
492 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
493 if (vpnId == NatConstants.INVALID_ID) {
494 LOG.error("NAT Service : SNAT -> Invalid Private BGP VPN ID returned for routerName {}", routerId);
497 if (routerId == NatConstants.INVALID_ID) {
498 LOG.error("NAT Service : SNAT -> Invalid routId returned for routerName {}", routerId);
501 LOG.debug("NAT Service : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
502 //Install default entry in FIB to SNAT table
503 LOG.debug("NAT Service : Installing default route in FIB on dpn {} for routerId {} "
504 + "with vpnId {}...", srcDpnId, routerId, vpnId);
505 defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, routerId);
507 LOG.debug("NAT Service : Install group in non NAPT switch {}", srcDpnId);
508 List<BucketInfo> bucketInfoForNonNaptSwitches =
509 externalRouterListner.getBucketInfoForNonNaptSwitches(srcDpnId, srcDpnId, routerName);
510 long groupId = externalRouterListner.installGroup(srcDpnId, routerName, bucketInfoForNonNaptSwitches);
512 LOG.debug("NAT Service : SNAT -> in the SNAT miss entry pointing to group {} in the non NAPT switch {}",
513 vpnId, groupId, srcDpnId);
514 FlowEntity flowEntity =
515 externalRouterListner.buildSnatFlowEntityWithUpdatedVpnId(srcDpnId, routerName, groupId, vpnId);
516 mdsalManager.installFlow(flowEntity);
521 private boolean hndlTepAddOnNaptSwitch(BigInteger srcDpnId, String tunnelType, String srcTepIp,
522 String destTepIp, String tunnelName, long routerId,
523 Optional<Routers> routerData, String nextHopIp) {
524 if (!routerData.isPresent()) {
525 LOG.warn("hndlTepAddOnNaptSwitch: routerData is not present");
528 String routerName = routerData.get().getRouterName();
529 LOG.debug("NAT Service : SNAT -> Processing TEP add for the DPN {} having the router {} since "
530 + "its THE NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
531 + "and TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
533 Uuid networkId = routerData.get().getNetworkId();
534 if (networkId == null) {
535 LOG.warn("NAT Service : SNAT -> Ignoring TEP add since the router {} is not associated to the "
536 + "external network", routerName);
540 LOG.debug("NAT Service : SNAT -> Router {} is associated with Ext nw {}", routerId, networkId);
541 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerName);
543 if (vpnName == null) {
544 LOG.debug("NAT Service : SNAT -> Internal VPN associated to router {}", routerId);
545 vpnId = NatUtil.getVpnId(dataBroker, routerId);
546 if (vpnId == null || vpnId == NatConstants.INVALID_ID) {
547 LOG.error("Invalid External VPN-ID returned for routerName {}", routerName);
550 LOG.debug("NAT Service : SNAT -> Retrieved External VPN-ID {} for router {}", vpnId, routerId);
552 LOG.debug("NAT Service : SNAT -> Private BGP VPN associated to router {}", routerId);
553 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
554 if (vpnId == null || vpnId == NatConstants.INVALID_ID) {
555 LOG.error("NAT Service : Invalid vpnId returned for routerName {}", routerName);
558 LOG.debug("NAT Service : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
561 /*1) Withdraw the old route to the external IP from the BGP which was having the
562 next hop as the old TEP IP.
563 2) Advertise to the BGP about the new route to the external IP having the
564 new TEP IP as the next hop.
565 3) Populate a new FIB entry with the next hop IP as the new TEP IP using the
569 //Withdraw the old route to the external IP from the BGP which was having the
570 //next hop as the old TEP IP.
571 final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
572 if (externalVpnName == null) {
573 LOG.error("NAT Service : SNAT -> No VPN associated with ext nw {} in router {}",
574 networkId, routerId);
577 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
578 if (externalIps != null) {
579 LOG.debug("NAT Service : Clearing the FIB entries but not the BGP routes");
580 for (String externalIp : externalIps) {
581 String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
582 LOG.debug("NAT Service : Removing Fib entry rd {} prefix {}", rd, externalIp);
583 fibManager.removeFibEntry(dataBroker, rd, externalIp, null);
588 Advertise to the BGP about the new route to the external IP having the
589 new TEP IP as the next hop.
590 Populate a new FIB entry with the next hop IP as the new TEP IP using the
593 String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
594 if (externalIps != null) {
595 for (final String externalIp : externalIps) {
596 Long label = externalRouterListner.checkExternalIpLabel(routerId,
598 if (label == null || label == NatConstants.INVALID_ID) {
599 LOG.debug("NAT Service : SNAT -> Unable to advertise to the DC GW since label is invalid");
603 LOG.debug("NAT Service : SNAT -> Advertise the route to the externalIp {} having nextHopIp {}",
604 externalIp, nextHopIp);
605 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, externalVpnName, rd, externalIp,
606 nextHopIp, label, LOG, RouteOrigin.STATIC, srcDpnId);
608 LOG.debug("NAT Service : SNAT -> Install custom FIB routes "
609 + "(Table 21 -> Push MPLS label to Tunnel port");
610 List<Instruction> customInstructions = new ArrayList<>();
611 customInstructions.add(new InstructionGotoTable(NwConstants.INBOUND_NAPT_TABLE).buildInstruction(0));
612 CreateFibEntryInput input =
613 new CreateFibEntryInputBuilder().setVpnName(externalVpnName).setSourceDpid(srcDpnId)
614 .setInstruction(customInstructions).setIpAddress(externalIp + "/32")
615 .setServiceId(label).setInstruction(customInstructions).build();
616 Future<RpcResult<Void>> future = fibRpcService.createFibEntry(input);
617 ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
619 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
622 public void onFailure(Throwable error) {
623 LOG.error("NAT Service : SNAT -> Error in generate label or fib install process", error);
627 public void onSuccess(RpcResult<Void> result) {
628 if (result.isSuccessful()) {
629 LOG.info("NAT Service : SNAT -> Successfully installed custom FIB routes for prefix {}",
632 LOG.error("NAT Service : SNAT -> Error in rpc call to create custom Fib entries "
633 + "for prefix {} in DPN {}, {}",
634 externalIp, srcDpnId, result.getErrors());
643 private void hndlTepAddForDnatInEachRtr(RoutersList router, String nextHopIp, BigInteger tepAddedDpnId) {
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 = MDSALUtil.read(dataBroker, LogicalDatastoreType
649 .CONFIGURATION, routerPortsId);
650 if (!optRouterPorts.isPresent()) {
651 LOG.debug("NAT Service : DNAT -> Could not read Router Ports data object with id: {} from DNAT "
652 + "FloatinIpInfo", routerName);
655 RouterPorts routerPorts = optRouterPorts.get();
656 List<Ports> interfaces = routerPorts.getPorts();
658 Uuid extNwId = routerPorts.getExternalNetworkId();
659 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId, LOG);
660 if (vpnName == null) {
661 LOG.info("NAT Service : DNAT -> No External VPN associated with ext nw {} for router {}",
662 extNwId, routerName);
666 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
667 for (Ports port : interfaces) {
668 //Get the DPN on which this interface resides
669 final String interfaceName = port.getPortName();
670 final BigInteger fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
671 if (fipCfgdDpnId.equals(BigInteger.ZERO)) {
672 LOG.info("NAT Service : DNAT -> Skip processing Floating ip configuration for the port {}, "
673 + "since no DPN present for it", interfaceName);
676 if (!fipCfgdDpnId.equals(tepAddedDpnId)) {
677 LOG.debug("NAT Service : DNAT -> TEP added DPN {} is not the DPN {} which has the "
678 + "floating IP configured for the port: {}",
679 tepAddedDpnId, fipCfgdDpnId, interfaceName);
682 List<InternalToExternalPortMap> intExtPortMapList = port.getInternalToExternalPortMap();
683 for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) {
684 final String internalIp = intExtPortMap.getInternalIp();
685 final String externalIp = intExtPortMap.getExternalIp();
686 LOG.debug("NAT Service : DNAT -> Advertising the FIB route to the floating IP {} configured "
687 + "for the port: {}",
688 externalIp, interfaceName);
689 long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
690 if (label == NatConstants.INVALID_ID) {
691 LOG.debug("NAT Service : DNAT -> Unable to advertise to the DC GW since label is invalid");
694 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd,
695 externalIp + "/32", nextHopIp, label, LOG, RouteOrigin.STATIC, fipCfgdDpnId);
697 //Install custom FIB routes (Table 21 -> Push MPLS label to Tunnel port
698 List<Instruction> customInstructions = new ArrayList<>();
699 customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(0));
700 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
701 .setSourceDpid(fipCfgdDpnId).setInstruction(customInstructions)
702 .setIpAddress(externalIp + "/32").setServiceId(label).setInstruction(customInstructions).build();
703 Future<RpcResult<Void>> future = fibRpcService.createFibEntry(input);
704 ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
706 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
709 public void onFailure(Throwable error) {
710 LOG.error("NAT Service : DNAT -> Error in generate label or fib install process", error);
714 public void onSuccess(RpcResult<Void> result) {
715 if (result.isSuccessful()) {
716 LOG.info("NAT Service : DNAT -> Successfully installed custom FIB routes for prefix {}",
719 LOG.error("NAT Service : DNAT -> Error in rpc call to create custom Fib "
720 + "entries for prefix {} in DPN {}, {}", externalIp, fipCfgdDpnId, result.getErrors());
728 private void hndlTepDelForSnatInEachRtr(RoutersList router, BigInteger dpnId, String tunnelType,
729 String srcTepIp, String destTepIp, String tunnelName) {
731 1) Elect a new switch as the primary NAPT
732 2) Advertise the new routes to BGP for the newly elected TEP IP as the DPN IP
733 3) This will make sure old routes are withdrawn and new routes are advertised.
736 String routerName = router.getRouter();
737 LOG.debug("NAT Service : SNAT -> Trying to clear routes to the External fixed IP associated to the router"
738 + " {}", routerName);
740 // Check if this is externalRouter else ignore
741 InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
742 Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType
743 .CONFIGURATION, extRoutersId);
744 if (!routerData.isPresent()) {
745 LOG.debug("NAT Service : SNAT -> Ignoring TEP del for router {} since its not External Router",
750 //Check if the router ID is valid
751 long routerId = NatUtil.getVpnId(dataBroker, routerName);
752 if (routerId == NatConstants.INVALID_ID) {
753 LOG.error("NAT Service : SNAT -> Invalid ROUTER-ID {} returned for routerName {}", routerId, routerName);
757 //Check if the DPN having the router is the NAPT switch
758 BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
759 if (naptId == null || naptId.equals(BigInteger.ZERO) || (!naptId.equals(dpnId))) {
760 LOG.warn("NAT Service : SNAT -> Ignoring TEP delete for the DPN {} since"
761 + " its NOT a NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
762 + "TUNNEL NAME {} ", dpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
766 Uuid networkId = routerData.get().getNetworkId();
767 if (networkId == null) {
768 LOG.debug("NAT Service : SNAT -> Ignoring TEP delete for the DPN {} having the router {} "
769 + "since the Router instance {} not found in ExtRouters model b/w SRC IP {} and DST IP {} "
770 + "and TUNNEL NAME {} ", dpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
774 LOG.debug("NAT Service : SNAT -> Router {} is associated with ext nw {}", routerId, networkId);
775 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerName);
777 if (vpnName == null) {
778 LOG.debug("NAT Service : SNAT -> Internal VPN-ID {} associated to router {}", routerId, routerName);
781 //Install default entry in FIB to SNAT table
782 LOG.debug("NAT Service : Installing default route in FIB on DPN {} for router {} with"
783 + " vpn {}...", dpnId, routerName, vpnId);
784 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId);
786 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
787 if (vpnId == NatConstants.INVALID_ID) {
788 LOG.error("NAT Service : SNAT -> Invalid Private BGP VPN ID returned for routerName {}", routerName);
791 LOG.debug("NAT Service : SNAT -> External BGP VPN (Private BGP) {} associated to router {}",
793 //Install default entry in FIB to SNAT table
794 LOG.debug("NAT Service : Installing default route in FIB on dpn {} for routerId {} "
795 + "with vpnId {}...", dpnId, routerId, vpnId);
796 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routerId);
799 if (routerData.get().isEnableSnat()) {
800 LOG.info("NAT Service : SNAT enabled for router {}", routerId);
802 long routerVpnId = routerId;
803 long bgpVpnId = NatConstants.INVALID_ID;
804 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
805 if (bgpVpnUuid != null) {
806 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
808 if (bgpVpnId != NatConstants.INVALID_ID) {
809 LOG.debug("NAT Service : SNAT -> Private BGP VPN ID (Internal BGP VPN ID) {} associated "
810 + "to the router {}", bgpVpnId, routerName);
811 routerVpnId = bgpVpnId;
813 LOG.debug("NAT Service : SNAT -> Internal L3 VPN ID (Router ID) {} associated to the router {}",
814 routerVpnId, routerName);
816 //Re-elect the other available switch as the NAPT switch and program the NAT flows.
817 removeSNATFromDPN(dpnId, routerName, routerVpnId, networkId);
819 LOG.info("NAT Service : SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
823 private void hndlTepDelForDnatInEachRtr(RoutersList router, BigInteger tepDeletedDpnId) {
824 //DNAT : Withdraw the routes from the BGP
825 String routerName = router.getRouter();
826 LOG.debug("NAT Service : DNAT -> Trying to clear routes to the Floating IP associated to the router {}",
829 InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
830 Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType
831 .CONFIGURATION, routerPortsId);
832 if (!optRouterPorts.isPresent()) {
833 LOG.debug("NAT Service : DNAT -> Could not read Router Ports data object with id: {} from DNAT "
838 RouterPorts routerPorts = optRouterPorts.get();
839 List<Ports> interfaces = routerPorts.getPorts();
840 Uuid extNwId = routerPorts.getExternalNetworkId();
841 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId, LOG);
842 if (vpnName == null) {
843 LOG.info("NAT Service : DNAT -> No External VPN associated with Ext N/W {} for Router {}",
844 extNwId, routerName);
847 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
848 for (Ports port : interfaces) {
849 //Get the DPN on which this interface resides
850 String interfaceName = port.getPortName();
851 BigInteger fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
852 if (fipCfgdDpnId.equals(BigInteger.ZERO)) {
853 LOG.info("NAT Service : DNAT -> Abort processing Floating ip configuration. No DPN for port : {}",
857 if (!fipCfgdDpnId.equals(tepDeletedDpnId)) {
858 LOG.info("NAT Service : DNAT -> TEP deleted DPN {} is not the DPN {} which has the "
859 + "floating IP configured for the port: {}",
860 tepDeletedDpnId, fipCfgdDpnId, interfaceName);
863 List<InternalToExternalPortMap> intExtPortMapList = port.getInternalToExternalPortMap();
864 for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) {
865 String internalIp = intExtPortMap.getInternalIp();
866 String externalIp = intExtPortMap.getExternalIp();
867 LOG.debug("NAT Service : DNAT -> Withdrawing the FIB route to the floating IP {} "
868 + "configured for the port: {}",
869 externalIp, interfaceName);
870 NatUtil.removePrefixFromBGP(dataBroker, bgpManager, fibManager, rd, externalIp + "/32", vpnName, LOG);
871 long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
872 if (label == NatConstants.INVALID_ID) {
873 LOG.debug("NAT Service : DNAT -> Unable to remove the table 21 entry pushing the "
874 + "MPLS label to the tunnel since label is invalid");
877 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
878 .setSourceDpid(fipCfgdDpnId).setIpAddress(externalIp + "/32").setServiceId(label).build();
879 Future<RpcResult<Void>> future = fibRpcService.removeFibEntry(input);
880 ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
882 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
885 public void onFailure(Throwable error) {
886 LOG.error("NAT Service : DNAT -> Error in removing the table 21 entry pushing "
887 + "the MPLS label to the tunnel since label is invalid ", error);
891 public void onSuccess(RpcResult<Void> result) {
892 if (result.isSuccessful()) {
893 LOG.info("NAT Service : DNAT -> Successfully removed the entry pushing the "
894 + "MPLS label to the tunnel");
896 LOG.error("NAT Service : DNAT -> Error in fib rpc call to remove the table 21 "
897 + "entry pushing the MPLS label to the tunnnel due to {}", result.getErrors());