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 org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
18 import org.opendaylight.genius.mdsalutil.*;
19 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
20 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
21 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
22 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
23 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersList;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersListKey;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.dpn.routers.list.RoutersList;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.*;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.*;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.IpMapping;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
40 import org.opendaylight.yangtools.yang.common.RpcResult;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
44 import java.math.BigInteger;
45 import java.util.ArrayList;
46 import java.util.HashMap;
47 import java.util.List;
48 import java.util.concurrent.Future;
50 public class NatTunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBase<StateTunnelList, NatTunnelInterfaceStateListener> implements
52 private static final Logger LOG = LoggerFactory.getLogger(NatTunnelInterfaceStateListener.class);
53 private final DataBroker dataBroker;
54 private IFibManager fibManager;
55 private SNATDefaultRouteProgrammer defaultRouteProgrammer;
56 private NaptSwitchHA naptSwitchHA;
57 private IMdsalApiManager mdsalManager;
58 private IdManagerService idManager;
59 private IBgpManager bgpManager;
60 private ExternalRoutersListener externalRouterListner;
61 private OdlInterfaceRpcService interfaceService;
62 private FloatingIPListener floatingIPListener;
63 private FibRpcService fibRpcService;
65 protected enum TunnelAction {
72 * Responsible for listening to tunnel interface state change
74 * @param dataBroker - dataBroker service reference
75 * @param bgpManager Used to advertise routes to the BGP Router
76 * @param fibManager - FIB Manager
77 * @param defaultRouteProgrammer - Default Route Programmer
78 * @param naptSwitchHA - NAPT Switch HA
79 * @param mdsalManager - MDSAL Manager
80 * @param idManager - ID manager
81 * @param externalRouterListner - External Router Listner
82 * @param interfaceService - Interface Service
83 * @param floatingIPListener - Floating IP Listner
84 * @param fibRpcService - FIB RPC Service
86 public NatTunnelInterfaceStateListener(final DataBroker dataBroker,
87 final IBgpManager bgpManager,
88 final IFibManager fibManager,
89 final SNATDefaultRouteProgrammer defaultRouteProgrammer,
90 final NaptSwitchHA naptSwitchHA,
91 final IMdsalApiManager mdsalManager,
92 final IdManagerService idManager,
93 final ExternalRoutersListener externalRouterListner,
94 final OdlInterfaceRpcService interfaceService,
95 final FloatingIPListener floatingIPListener,
96 final FibRpcService fibRpcService) {
97 super(StateTunnelList.class, NatTunnelInterfaceStateListener.class);
98 this.dataBroker = dataBroker;
99 this.bgpManager = bgpManager;
100 this.fibManager = fibManager;
101 this.defaultRouteProgrammer = defaultRouteProgrammer;
102 this.naptSwitchHA = naptSwitchHA;
103 this.mdsalManager = mdsalManager;
104 this.idManager = idManager;
105 this.externalRouterListner = externalRouterListner;
106 this.interfaceService = interfaceService;
107 this.floatingIPListener = floatingIPListener;
108 this.fibRpcService = fibRpcService;
113 LOG.info("{} init", getClass().getSimpleName());
114 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
118 protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
119 return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
123 protected NatTunnelInterfaceStateListener getDataTreeChangeListener() {
124 return NatTunnelInterfaceStateListener.this;
128 protected void add(InstanceIdentifier<StateTunnelList> instanceIdentifier, StateTunnelList add) {
129 LOG.trace("NAT Service : TEP addtion---- {}", add);
130 hndlTepEvntsForDpn(add, TunnelAction.TUNNEL_EP_ADD);
134 protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
135 LOG.trace("NAT Service : TEP deletion---- {}", del);
136 hndlTepEvntsForDpn(del, TunnelAction.TUNNEL_EP_DELETE);
140 protected void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original, StateTunnelList update) {
141 LOG.trace("NAT Service : Tunnel updation---- {}", update);
142 //UPDATE IS A SEQUENCE OF DELETE AND ADD EVENTS . DELETE MIGHT HAVE CHANGED THE PRIMARY AND ADVERTISED. SO
146 private int getTunnelType (StateTunnelList stateTunnelList) {
148 if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
149 tunTypeVal = NatConstants.ITMTunnelLocType.Internal.getValue();
150 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
151 tunTypeVal = NatConstants.ITMTunnelLocType.External.getValue();
152 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
153 tunTypeVal = NatConstants.ITMTunnelLocType.Hwvtep.getValue();
155 tunTypeVal = NatConstants.ITMTunnelLocType.Invalid.getValue();
160 void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerVpnId, Uuid networkId) {
161 //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
162 //remove miss entry to NAPT switch
163 //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
165 //get ExternalIpIn prior
166 List<String> externalIpCache;
168 HashMap<String,Long> externalIpLabel;
169 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
170 if (routerId == NatConstants.INVALID_ID) {
171 LOG.error("NAT Service : SNAT -> Invalid routerId returned for routerName {}",routerName);
174 externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
175 externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker,routerId);
177 final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
178 if (externalVpnName == null) {
179 LOG.error("NAT Service : SNAT -> No VPN associated with ext nw {} in router {}",
180 networkId, routerId);
184 BigInteger naptSwitch = dpnId;
185 boolean naptStatus = naptSwitchHA.isNaptSwitchDown(routerName,dpnId,naptSwitch,routerVpnId,externalIpCache,false);
187 LOG.debug("NAT Service : SNAT -> NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
189 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
190 FlowEntity flowEntity = null;
192 flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId, NatConstants.DEL_FLOW);
193 if (flowEntity == null) {
194 LOG.debug("NAT Service : SNAT -> Failed to populate flowentity for router {} with dpnId {} groupIs {}",routerName,dpnId,groupId);
197 LOG.debug("NAT Service : SNAT -> Removing default SNAT miss entry flow entity {}",flowEntity);
198 mdsalManager.removeFlow(flowEntity);
200 } catch (Exception ex) {
201 LOG.debug("NAT Service : SNAT -> Failed to remove default SNAT miss entry flow entity {} : {}",flowEntity,ex);
204 LOG.debug("NAT Service : SNAT -> Removed default SNAT miss entry flow for dpnID {} with routername {}", dpnId, routerName);
207 GroupEntity groupEntity = null;
209 groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
210 GroupTypes.GroupAll, null);
211 LOG.info("NAT Service : SNAT -> Removing NAPT GroupEntity:{}", groupEntity);
212 mdsalManager.removeGroup(groupEntity);
213 } catch (Exception ex) {
214 LOG.debug("NAT Service : SNAT -> Failed to remove group entity {} : {}",groupEntity,ex);
217 LOG.debug("NAT Service : SNAT -> Removed default SNAT miss entry flow for dpnID {} with routerName {}", dpnId, routerName);
219 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, dpnId,externalIpLabel);
220 //remove table 26 flow ppointing to table46
221 FlowEntity flowEntity = null;
223 flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId, NatConstants.DEL_FLOW);
224 if (flowEntity == null) {
225 LOG.debug("NAT Service : SNAT -> Failed to populate flowentity for router {} with dpnId {}",routerName,dpnId);
228 LOG.debug("NAT Service : SNAT -> Removing default SNAT miss entry flow entity for router {} with dpnId {} in napt switch {}"
229 ,routerName,dpnId,naptSwitch);
230 mdsalManager.removeFlow(flowEntity);
232 } catch (Exception ex) {
233 LOG.debug("NAT Service : SNAT -> Failed to remove default SNAT miss entry flow entity {} : {}",flowEntity,ex);
236 LOG.debug("NAT Service : SNAT -> Removed default SNAT miss entry flow for dpnID {} with routername {}", dpnId, routerName);
238 //best effort to check IntExt model
239 naptSwitchHA.bestEffortDeletion(routerId,routerName,externalIpLabel);
241 } catch (Exception ex) {
242 LOG.debug("NAT Service : SNAT -> Exception while handling naptSwitch down for router {} : {}",routerName,ex);
246 private void hndlTepEvntsForDpn(StateTunnelList stateTunnelList, TunnelAction tunnelAction) {
247 final BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
248 final String srcTepIp = String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue());
249 final String destTepIp = String.valueOf(stateTunnelList.getDstInfo().getTepIp().getValue());
250 LOG.trace("NAT Service : Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ", srcDpnId, srcTepIp,
252 int tunTypeVal = getTunnelType(stateTunnelList);
254 LOG.trace("NAT Service : tunTypeVal is {}", tunTypeVal);
257 String srcTepId = stateTunnelList.getSrcInfo().getTepDeviceId();
258 String tunnelType = stateTunnelList.getTransportType().toString();
259 String tunnelName = stateTunnelList.getTunnelInterfaceName();
261 if(tunTypeVal == NatConstants.ITMTunnelLocType.Internal.getValue()){
262 LOG.debug("NAT Service : Ignoring TEP event {} for the DPN {} " +
263 "since its a INTERNAL TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and " +
264 "TUNNEL NAME {} ", tunnelAction, srcTepId, tunnelType, srcTepIp, destTepIp, tunnelName);
266 }else if(tunTypeVal == NatConstants.ITMTunnelLocType.Invalid.getValue()){
267 LOG.warn("NAT Service : Ignoring TEP event {} for the DPN {} " +
268 "since its a INVALID TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and " +
269 "TUNNEL NAME {} ", tunnelAction, srcTepId, tunnelType, srcTepIp, destTepIp, tunnelName);
273 switch(tunnelAction){
275 if(!hndlTepAddForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp)){
276 LOG.debug("NAT Service : Unable to process TEP ADD");
279 case TUNNEL_EP_DELETE:
280 if(!handleTepDelForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp)){
281 LOG.debug("NAT Service : Unable to process TEP DEL");
285 } catch (Exception e) {
286 LOG.error("NAT Service : Unable to handle the TEP event.", e);
291 private boolean hndlTepAddForAllRtrs(BigInteger srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
292 String destTepIp) throws Exception{
293 LOG.trace("NAT Service: TEP ADD ----- for EXTERNAL/HWVTEP ITM Tunnel, TYPE {} ,State is UP b/w SRC IP" +
294 " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
296 InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
297 Optional<DpnRoutersList> optionalRouterDpnList = NatUtil.read(dataBroker, LogicalDatastoreType
298 .OPERATIONAL, dpnRoutersListId);
299 if (!optionalRouterDpnList.isPresent()) {
300 LOG.warn("NAT Service : RouterDpnList model is empty for DPN {}. Hence ignoring TEP add event for the ITM " +
301 "TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ", srcDpnId,
302 tunnelType, srcTepIp, destTepIp, tunnelName);
306 List<RoutersList> routersList = optionalRouterDpnList.get().getRoutersList();
307 if(routersList == null) {
308 LOG.debug("NAT Service : Ignoring TEP add for the DPN {} since no routers are associated" +
309 " for the DPN having the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and" +
310 "TUNNEL NAME {} ", srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
314 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
315 for (RoutersList router : routersList) {
317 LOG.debug("NAT Service : TEP ADD : DNAT -> Advertising routes for router {} ", router.getRouter());
318 hndlTepAddForDnatInEachRtr(router, nextHopIp, srcDpnId);
320 LOG.debug("NAT Service : TEP ADD : SNAT -> Advertising routes for router {} ", router.getRouter());
321 hndlTepAddForSnatInEachRtr(router, srcDpnId, tunnelType, srcTepIp, destTepIp,
322 tunnelName, nextHopIp);
327 private boolean handleTepDelForAllRtrs(BigInteger srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
328 String destTepIp) throws Exception{
330 LOG.trace("NAT Service: TEP DEL ----- for EXTERNAL/HWVTEP ITM Tunnel, TYPE {} ,State is UP b/w SRC IP" +
331 " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
333 // When tunnel EP is deleted on a DPN , VPN gets two deletion event.
334 // One for a DPN on which tunnel EP was deleted and another for other-end DPN.
335 // Handle only the DPN on which it was deleted , ignore other event.
336 // DPN on which TEP is deleted , endpoint IP will be null.
337 String endpointIpForDPN = null;
339 endpointIpForDPN = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
340 } catch (Exception e) {
341 /* this dpn does not have the VTEP */
342 LOG.debug("NAT Service : DPN {} does not have the VTEP", srcDpnId);
343 endpointIpForDPN = null;
346 if (endpointIpForDPN != null) {
347 LOG.trace("NAT Service : Ignore TEP DELETE event received for DPN {} VTEP IP {} since its the other end DPN w.r.t the delted TEP", srcDpnId,
352 List<RoutersList> routersList = null;
353 InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
354 Optional<DpnRoutersList> optionalRouterDpnList = NatUtil.read(dataBroker, LogicalDatastoreType
355 .OPERATIONAL, dpnRoutersListId);
356 if (optionalRouterDpnList.isPresent()) {
357 routersList = optionalRouterDpnList.get().getRoutersList();
359 LOG.warn("NAT Service : RouterDpnList is empty for DPN {}. Hence ignoring TEP DEL event for the ITM " +
360 "TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ", srcDpnId,
361 tunnelType, srcTepIp, destTepIp, tunnelName);
365 if(routersList == null) {
366 LOG.debug("NAT Service : DPN {} does not have the Routers presence", srcDpnId);
370 for (RoutersList router : routersList) {
371 LOG.debug("NAT Service : TEP DEL : DNAT -> Withdrawing routes for router {} ", router.getRouter());
372 hndlTepDelForDnatInEachRtr(router, srcDpnId);
373 LOG.debug("NAT Service : TEP DEL : SNAT -> Withdrawing and Advertising routes for router {} ",
375 hndlTepDelForSnatInEachRtr(router, srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
380 private void hndlTepAddForSnatInEachRtr(RoutersList router, final BigInteger srcDpnId, String tunnelType,
381 String srcTepIp, String destTepIp, String tunnelName, String nextHopIp){
383 /*SNAT : Remove the old routes to the external IP having the old TEP IP as the next hop IP
384 Advertise to the BGP about the new route to the external IP having the new TEP IP
385 added as the next hop IP
387 String routerName = router.getRouter();
389 // Check if this is externalRouter else ignore
390 InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
391 Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType
392 .CONFIGURATION, extRoutersId);
393 if (!routerData.isPresent()) {
394 LOG.debug("NAT Service : SNAT -> Ignoring TEP add for router {} since its not External Router",
399 long routerId = NatUtil.getVpnId(dataBroker, routerName);
400 BigInteger naptId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
401 if (naptId == null || naptId.equals(BigInteger.ZERO)) {
402 LOG.warn("NAT Service : SNAT -> Ignoring TEP add for the DPN {} having the router {} since" +
403 " the router is not part of the NAT service - the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and" +
404 "TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
408 //Check if the DPN having the router is the NAPT switch
409 if( !naptId.equals(srcDpnId)){
411 1) Install default NAT rule from table 21 to 26
412 2) Install the group which forward packet to the tunnel port for the NAPT switch.
413 3) Install the flow 26 which forwards the packet to the group.
415 if (!hndlTepAddOnNonNaptSwitch(srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName, routerName, routerId)){
416 LOG.debug("NAT Service : Unable to process the TEP add event on NON-NAPT switch {}", srcDpnId);
421 if (!hndlTepAddOnNaptSwitch(srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName, routerId, routerData, nextHopIp)){
422 LOG.debug("NAT Service : Unable to process the TEP add event on NAPT switch {}", srcDpnId);
428 private boolean hndlTepAddOnNonNaptSwitch(BigInteger srcDpnId, String tunnelType, String srcTepIp, String destTepIp,
429 String tunnelName, String routerName, long routerId){
432 1) Install default NAT rule from table 21 to 26
433 2) Install the group which forward packet to the tunnel port for the NAPT switch.
434 3) Install the flow 26 which forwards the packet to the group.
436 LOG.debug("NAT Service : SNAT -> Processing TEP add for the DPN {} having the router {} since " +
437 "its THE NON NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} " + "and TUNNEL NAME {} ",
438 srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
439 LOG.debug("NAT Service : SNAT -> Install default NAT rule from table 21 to 26");
440 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerName);
442 if (vpnName == null) {
443 LOG.debug("NAT Service : SNAT -> Internal VPN associated to router {}",routerId);
445 if (vpnId == NatConstants.INVALID_ID) {
446 LOG.error("NAT Service : SNAT -> Invalid Internal VPN ID returned for routerName {}",routerId);
449 LOG.debug("NAT Service : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerName);
450 //Install default entry in FIB to SNAT table
451 LOG.debug("NAT Service : Installing default route in FIB on DPN {} for router {} with" +
452 " vpn {}...", srcDpnId,routerName,vpnId);
453 defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId);
455 LOG.debug("NAT Service : SNAT -> Install the group which forward packet to the tunnel port for the NAPT switch" +
456 " and the flow 26 which forwards to group");
457 externalRouterListner.handleSwitches(srcDpnId, routerName, srcDpnId);
459 LOG.debug("NAT Service : SNAT -> External BGP VPN (Private BGP) associated to router {}",routerId);
460 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
461 if (vpnId == NatConstants.INVALID_ID) {
462 LOG.error("NAT Service : SNAT -> Invalid Private BGP VPN ID returned for routerName {}", routerId);
465 if (routerId == NatConstants.INVALID_ID) {
466 LOG.error("NAT Service : SNAT -> Invalid routId returned for routerName {}",routerId);
469 LOG.debug("NAT Service : SNAT -> Retrieved vpnId {} for router {}",vpnId, routerId);
470 //Install default entry in FIB to SNAT table
471 LOG.debug("NAT Service : Installing default route in FIB on dpn {} for routerId {} " +
472 "with vpnId {}...", srcDpnId,routerId,vpnId);
473 defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, routerId);
475 LOG.debug("NAT Service : Install group in non NAPT switch {}", srcDpnId);
476 List<BucketInfo> bucketInfoForNonNaptSwitches = externalRouterListner.getBucketInfoForNonNaptSwitches(srcDpnId, srcDpnId, routerName);
477 long groupId = externalRouterListner.installGroup(srcDpnId, routerName, bucketInfoForNonNaptSwitches);
479 LOG.debug("NAT Service : SNAT -> in the SNAT miss entry pointing to group {} in the non NAPT switch {}",
480 vpnId, groupId, srcDpnId);
481 FlowEntity flowEntity = externalRouterListner.buildSnatFlowEntityWithUpdatedVpnId(srcDpnId, routerName, groupId, vpnId);
482 mdsalManager.installFlow(flowEntity);
487 private boolean hndlTepAddOnNaptSwitch(BigInteger srcDpnId, String tunnelType, String srcTepIp,
488 String destTepIp, String tunnelName, long routerId,
489 Optional<Routers> routerData, String nextHopIp){
490 String routerName = routerData.get().getRouterName();
491 LOG.debug("NAT Service : SNAT -> Processing TEP add for the DPN {} having the router {} since " +
492 "its THE NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} " +
493 "and TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
495 Uuid networkId = routerData.get().getNetworkId();
496 if (networkId == null) {
497 LOG.warn("NAT Service : SNAT -> Ignoring TEP add since the router {} is not associated to the " +
498 "external network", routerName);
502 LOG.debug("NAT Service : SNAT -> Router {} is associated with Ext nw {}", routerId, networkId);
503 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerName);
505 if (vpnName == null) {
506 LOG.debug("NAT Service : SNAT -> Internal VPN associated to router {}", routerId);
507 vpnId = NatUtil.getVpnId(dataBroker, routerId);
508 if (vpnId == null || vpnId == NatConstants.INVALID_ID) {
509 LOG.error("Invalid External VPN-ID returned for routerName {}", routerName);
512 LOG.debug("NAT Service : SNAT -> Retrieved External VPN-ID {} for router {}", vpnId, routerId);
514 LOG.debug("NAT Service : SNAT -> Private BGP VPN associated to router {}", routerId);
515 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
516 if (vpnId == null || vpnId == NatConstants.INVALID_ID) {
517 LOG.error("NAT Service : Invalid vpnId returned for routerName {}", routerName);
520 LOG.debug("NAT Service : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
523 /*1) Withdraw the old route to the external IP from the BGP which was having the
524 next hop as the old TEP IP.
525 2) Advertise to the BGP about the new route to the external IP having the
526 new TEP IP as the next hop.
527 3) Populate a new FIB entry with the next hop IP as the new TEP IP using the
531 //Withdraw the old route to the external IP from the BGP which was having the
532 //next hop as the old TEP IP.
533 final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
534 if (externalVpnName == null) {
535 LOG.error("NAT Service : SNAT -> No VPN associated with ext nw {} in router {}",
536 networkId, routerId);
539 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
540 if (externalIps != null) {
541 LOG.debug("NAT Service : Clearing the FIB entries but not the BGP routes");
542 for (String externalIp : externalIps) {
543 String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
544 LOG.debug("NAT Service : Removing Fib entry rd {} prefix {}", rd, externalIp);
545 fibManager.removeFibEntry(dataBroker, rd, externalIp, null);
550 Advertise to the BGP about the new route to the external IP having the
551 new TEP IP as the next hop.
552 Populate a new FIB entry with the next hop IP as the new TEP IP using the
555 String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
556 if (externalIps != null) {
557 for (final String externalIp : externalIps) {
558 Long label = externalRouterListner.checkExternalIpLabel(routerId,
560 if(label == null || label == NatConstants.INVALID_ID){
561 LOG.debug("NAT Service : SNAT -> Unable to advertise to the DC GW since label is invalid" );
565 LOG.debug("NAT Service : SNAT -> Advertise the route to the externalIp {} having nextHopIp {}", externalIp,
567 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, rd, externalIp, nextHopIp,
568 label, LOG, RouteOrigin.STATIC);
570 LOG.debug("NAT Service : SNAT -> Install custom FIB routes ( Table 21 -> Push MPLS label to Tunnel port");
571 List<Instruction> customInstructions = new ArrayList<>();
572 customInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.INBOUND_NAPT_TABLE }).
573 buildInstruction(0));
574 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(externalVpnName).setSourceDpid(srcDpnId).
575 setInstruction(customInstructions).setIpAddress(externalIp + "/32").setServiceId(label).setInstruction(customInstructions).build();
576 Future<RpcResult<Void>> future = fibRpcService.createFibEntry(input);
577 ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
579 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
582 public void onFailure(Throwable error) {
583 LOG.error("NAT Service : SNAT -> Error in generate label or fib install process", error);
587 public void onSuccess(RpcResult<Void> result) {
588 if(result.isSuccessful()) {
589 LOG.info("NAT Service : SNAT -> Successfully installed custom FIB routes for prefix {}", externalIp);
591 LOG.error("NAT Service : SNAT -> Error in rpc call to create custom Fib entries for prefix {} in DPN {}, {}",
592 externalIp, srcDpnId, result.getErrors());
601 private void hndlTepAddForDnatInEachRtr(RoutersList router, String nextHopIp, BigInteger tepAddedDpnId){
602 //DNAT : Advertise the new route to the floating IP having the new TEP IP as the next hop IP
603 final String routerName = router.getRouter();
605 InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
606 Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType
607 .CONFIGURATION, routerPortsId);
608 if (!optRouterPorts.isPresent()) {
609 LOG.debug("NAT Service : DNAT -> Could not read Router Ports data object with id: {} from DNAT " +
610 "FloatinIpInfo", routerName);
613 RouterPorts routerPorts = optRouterPorts.get();
614 List<Ports> interfaces = routerPorts.getPorts();
616 Uuid extNwId = routerPorts.getExternalNetworkId();
617 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId, LOG);
618 if (vpnName == null) {
619 LOG.info("NAT Service : DNAT -> No External VPN associated with ext nw {} for router {}",
620 extNwId, routerName);
624 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
625 for (Ports port : interfaces) {
626 //Get the DPN on which this interface resides
627 final String interfaceName = port.getPortName();
628 final BigInteger fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
629 if(fipCfgdDpnId.equals(BigInteger.ZERO)) {
630 LOG.info("NAT Service : DNAT -> Skip processing Floating ip configuration for the port {}, since no DPN present for it", interfaceName);
633 if(!fipCfgdDpnId.equals(tepAddedDpnId)) {
634 LOG.debug("NAT Service : DNAT -> TEP added DPN {} is not the DPN {} which has the floating IP configured for the port: {}",
635 tepAddedDpnId, fipCfgdDpnId, interfaceName);
638 List<IpMapping> ipMapping = port.getIpMapping();
639 for (final IpMapping ipMap : ipMapping) {
640 final String internalIp = ipMap.getInternalIp();
641 final String externalIp = ipMap.getExternalIp();
642 LOG.debug("NAT Service : DNAT -> Advertising the FIB route to the floating IP {} configured for the port: {}",
643 externalIp, interfaceName);
644 long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
645 if(label == NatConstants.INVALID_ID){
646 LOG.debug("NAT Service : DNAT -> Unable to advertise to the DC GW since label is invalid" );
649 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, rd, externalIp + "/32", nextHopIp, label, LOG, RouteOrigin.STATIC);
651 //Install custom FIB routes ( Table 21 -> Push MPLS label to Tunnel port
652 List<Instruction> customInstructions = new ArrayList<>();
653 customInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.PDNAT_TABLE }).buildInstruction(0));
654 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(fipCfgdDpnId).setInstruction(customInstructions)
655 .setIpAddress(externalIp + "/32").setServiceId(label).setInstruction(customInstructions).build();
656 Future<RpcResult<Void>> future = fibRpcService.createFibEntry(input);
657 ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
659 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
662 public void onFailure(Throwable error) {
663 LOG.error("NAT Service : DNAT -> Error in generate label or fib install process", error);
667 public void onSuccess(RpcResult<Void> result) {
668 if(result.isSuccessful()) {
669 LOG.info("NAT Service : DNAT -> Successfully installed custom FIB routes for prefix {}", externalIp);
671 LOG.error("NAT Service : DNAT -> Error in rpc call to create custom Fib entries for prefix {} in DPN {}, {}", externalIp, fipCfgdDpnId, result.getErrors());
680 private void hndlTepDelForSnatInEachRtr(RoutersList router, BigInteger dpnId, String tunnelType,
681 String srcTepIp, String destTepIp, String tunnelName){
683 1) Elect a new switch as the primary NAPT
684 2) Advertise the new routes to BGP for the newly elected TEP IP as the DPN IP
685 3) This will make sure old routes are withdrawn and new routes are advertised.
688 String routerName = router.getRouter();
689 LOG.debug("NAT Service : SNAT -> Trying to clear routes to the External fixed IP associated to the router" +
692 // Check if this is externalRouter else ignore
693 InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
694 Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType
695 .CONFIGURATION, extRoutersId);
696 if (!routerData.isPresent()) {
697 LOG.debug("NAT Service : SNAT -> Ignoring TEP del for router {} since its not External Router",
702 //Check if the router ID is valid
703 long routerId = NatUtil.getVpnId(dataBroker, routerName);
704 if (routerId == NatConstants.INVALID_ID) {
705 LOG.error("NAT Service : SNAT -> Invalid ROUTER-ID {} returned for routerName {}", routerId, routerName);
709 //Check if the DPN having the router is the NAPT switch
710 BigInteger naptId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
711 if (naptId == null || naptId.equals(BigInteger.ZERO) || (!naptId.equals(dpnId))) {
712 LOG.warn("NAT Service : SNAT -> Ignoring TEP delete for the DPN {} since" +
713 " its NOT a NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and" +
714 "TUNNEL NAME {} ", dpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
718 Uuid networkId = routerData.get().getNetworkId();
719 if(networkId == null) {
720 LOG.debug("NAT Service : SNAT -> Ignoring TEP delete for the DPN {} having the router {} " +
721 "since the Router instance {} not found in ExtRouters model b/w SRC IP {} and DST IP {} " +
722 "and TUNNEL NAME {} ", dpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
726 LOG.debug("NAT Service : SNAT -> Router {} is associated with ext nw {}", routerId, networkId);
727 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerName);
729 if (vpnName == null) {
730 LOG.debug("NAT Service : SNAT -> Internal VPN-ID {} associated to router {}", routerId, routerName);
733 //Install default entry in FIB to SNAT table
734 LOG.debug("NAT Service : Installing default route in FIB on DPN {} for router {} with" +
735 " vpn {}...", dpnId,routerName,vpnId);
736 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId);
738 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
739 if (vpnId == NatConstants.INVALID_ID) {
740 LOG.error("NAT Service : SNAT -> Invalid Private BGP VPN ID returned for routerName {}", routerName);
743 LOG.debug("NAT Service : SNAT -> External BGP VPN (Private BGP) {} associated to router {}", vpnId, routerName);
744 //Install default entry in FIB to SNAT table
745 LOG.debug("NAT Service : Installing default route in FIB on dpn {} for routerId {} " +
746 "with vpnId {}...", dpnId, routerId, vpnId);
747 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routerId);
750 if (routerData.get().isEnableSnat()) {
751 LOG.info("NAT Service : SNAT enabled for router {}", routerId);
753 long routerVpnId = routerId;
754 long bgpVpnId = NatConstants.INVALID_ID;
755 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
756 if (bgpVpnUuid != null) {
757 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
759 if (bgpVpnId != NatConstants.INVALID_ID){
760 LOG.debug("NAT Service : SNAT -> Private BGP VPN ID (Internal BGP VPN ID) {} associated to the router {}", bgpVpnId, routerName);
761 routerVpnId = bgpVpnId;
763 LOG.debug("NAT Service : SNAT -> Internal L3 VPN ID (Router ID) {} associated to the router {}", routerVpnId, routerName);
765 //Re-elect the other available switch as the NAPT switch and program the NAT flows.
766 removeSNATFromDPN(dpnId, routerName ,routerVpnId, networkId);
768 LOG.info("NAT Service : SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
772 private void hndlTepDelForDnatInEachRtr(RoutersList router, BigInteger tepDeletedDpnId){
773 //DNAT : Withdraw the routes from the BGP
774 String routerName = router.getRouter();
775 LOG.debug("NAT Service : DNAT -> Trying to clear routes to the Floating IP associated to the router {}",
778 InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
779 Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType
780 .CONFIGURATION, routerPortsId);
781 if(!optRouterPorts.isPresent()) {
782 LOG.debug("NAT Service : DNAT -> Could not read Router Ports data object with id: {} from DNAT " +
787 RouterPorts routerPorts = optRouterPorts.get();
788 List<Ports> interfaces = routerPorts.getPorts();
789 Uuid extNwId = routerPorts.getExternalNetworkId();
790 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId, LOG);
791 if(vpnName == null) {
792 LOG.info("NAT Service : DNAT -> No External VPN associated with Ext N/W {} for Router {}",
793 extNwId, routerName);
796 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
797 for(Ports port : interfaces) {
798 //Get the DPN on which this interface resides
799 String interfaceName = port.getPortName();
800 BigInteger fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
801 if(fipCfgdDpnId.equals(BigInteger.ZERO)) {
802 LOG.info("NAT Service : DNAT -> Abort processing Floating ip configuration. No DPN for port : {}", interfaceName);
805 if(!fipCfgdDpnId.equals(tepDeletedDpnId)) {
806 LOG.info("NAT Service : DNAT -> TEP deleted DPN {} is not the DPN {} which has the floating IP configured for the port: {}",
807 tepDeletedDpnId, fipCfgdDpnId, interfaceName);
810 List<IpMapping> ipMapping = port.getIpMapping();
811 for(IpMapping ipMap : ipMapping) {
812 String internalIp = ipMap.getInternalIp();
813 String externalIp = ipMap.getExternalIp();
814 LOG.debug("NAT Service : DNAT -> Withdrawing the FIB route to the floating IP {} configured for the port: {}",
815 externalIp, interfaceName);
816 NatUtil.removePrefixFromBGP(dataBroker, bgpManager, fibManager, rd, externalIp + "/32", LOG);
817 long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
818 if(label == NatConstants.INVALID_ID){
819 LOG.debug("NAT Service : DNAT -> Unable to remove the table 21 entry pushing the MPLS label to the tunnel since label is invalid" );
822 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(fipCfgdDpnId).setIpAddress(externalIp + "/32").setServiceId(label).build();
823 Future<RpcResult<Void>> future = fibRpcService.removeFibEntry(input);
824 ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
826 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
829 public void onFailure(Throwable error) {
830 LOG.error("NAT Service : DNAT -> Error in removing the table 21 entry pushing the MPLS label to the tunnel since label is invalid ", error);
834 public void onSuccess(RpcResult<Void> result) {
835 if(result.isSuccessful()) {
836 LOG.info("NAT Service : DNAT -> Successfully removed the entry pushing the MPLS label to the tunnel");
838 LOG.error("NAT Service : DNAT -> Error in fib rpc call to remove the table 21 entry pushing the MPLS label to the tunnnel due to {}", result.getErrors());