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.vpnservice.natservice.internal;
11 import java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.List;
14 import java.util.concurrent.ExecutionException;
15 import java.util.concurrent.Future;
17 import org.opendaylight.bgpmanager.api.IBgpManager;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.FibRpcService;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.VpnRpcService;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMapping;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.GenerateVpnLabelOutput;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.GenerateVpnLabelInput;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.GenerateVpnLabelInputBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.CreateFibEntryInput;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.CreateFibEntryInputBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.RemoveVpnLabelInput;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.RemoveFibEntryInput;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.RemoveVpnLabelInputBuilder;
34 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
35 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
36 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
37 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
38 import org.opendaylight.vpnservice.datastoreutils.AsyncDataTreeChangeListenerBase;
39 import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
40 import org.opendaylight.vpnservice.mdsalutil.ActionType;
41 import org.opendaylight.vpnservice.mdsalutil.BucketInfo;
42 import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
43 import org.opendaylight.vpnservice.mdsalutil.GroupEntity;
44 import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
45 import org.opendaylight.vpnservice.mdsalutil.InstructionType;
46 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
47 import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
48 import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
49 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
50 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
51 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetFieldCase;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInput;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInputBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdOutput;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInput;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInputBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetTunnelInterfaceNameInputBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetTunnelInterfaceNameOutput;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ExtRouters;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.RouterIdName;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.RoutersKey;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.id.name.RouterIds;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.id.name.RouterIdsBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.id.name.RouterIdsKey;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.Subnetmaps;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.subnetmaps.Subnetmap;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
88 import org.opendaylight.yangtools.concepts.ListenerRegistration;
89 import org.opendaylight.yangtools.yang.binding.DataObject;
90 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
91 import org.opendaylight.yangtools.yang.common.RpcResult;
92 import org.slf4j.Logger;
93 import org.slf4j.LoggerFactory;
95 import com.google.common.base.Optional;
96 import com.google.common.util.concurrent.AsyncFunction;
97 import com.google.common.util.concurrent.FutureCallback;
98 import com.google.common.util.concurrent.Futures;
99 import com.google.common.util.concurrent.JdkFutureAdapters;
100 import com.google.common.util.concurrent.ListenableFuture;
103 * Created by EYUGSAR on 2/20/2016.
106 public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Routers, ExternalRoutersListener>{
108 private static final Logger LOG = LoggerFactory.getLogger( ExternalRoutersListener.class);
109 private static long label;
110 private ListenerRegistration<DataChangeListener> listenerRegistration;
111 private final DataBroker dataBroker;
112 private IMdsalApiManager mdsalManager;
113 private ItmRpcService itmManager;
114 private OdlInterfaceRpcService interfaceManager;
115 private IdManagerService idManager;
116 private NaptManager naptManager;
117 private NAPTSwitchSelector naptSwitchSelector;
118 private IBgpManager bgpManager;
119 private VpnRpcService vpnService;
120 private FibRpcService fibService;
121 private SNATDefaultRouteProgrammer defaultRouteProgrammer;
122 private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
123 static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000022", 16);
125 public void setMdsalManager(IMdsalApiManager mdsalManager) {
126 this.mdsalManager = mdsalManager;
129 public void setItmManager(ItmRpcService itmManager) {
130 this.itmManager = itmManager;
133 public void setIdManager(IdManagerService idManager) {
134 this.idManager = idManager;
138 void setDefaultProgrammer(SNATDefaultRouteProgrammer defaultRouteProgrammer) {
139 this.defaultRouteProgrammer = defaultRouteProgrammer;
143 public void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {
144 this.interfaceManager = interfaceManager;
147 public void setNaptManager(NaptManager naptManager) {
148 this.naptManager = naptManager;
151 public void setNaptSwitchSelector(NAPTSwitchSelector naptSwitchSelector) {
152 this.naptSwitchSelector = naptSwitchSelector;
155 public void setBgpManager(IBgpManager bgpManager) {
156 this.bgpManager = bgpManager;
159 public void setVpnService(VpnRpcService vpnService) {
160 this.vpnService = vpnService;
163 public void setFibService(FibRpcService fibService) {
164 this.fibService = fibService;
167 public ExternalRoutersListener(DataBroker dataBroker )
169 super( Routers.class, ExternalRoutersListener.class );
170 this.dataBroker = dataBroker;
174 protected void add(InstanceIdentifier<Routers> identifier, Routers routers) {
176 LOG.info( "Add external router event for {}", routers.getRouterName() );
178 LOG.info("Installing NAT default route on all dpns part of router {}", routers.getRouterName());
179 addOrDelDefFibRouteToSNAT(routers.getRouterName(), true);
181 if( !routers.isEnableSnat()) {
182 LOG.info( "SNAT is disabled for external router {} ", routers.getRouterName());
186 // Populate the router-id-name container
187 String routerName = routers.getRouterName();
188 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
189 RouterIds rtrs = new RouterIdsBuilder().setKey(new RouterIdsKey(routerId)).setRouterId(routerId).setRouterName(routerName).build();
190 MDSALUtil.syncWrite( dataBroker, LogicalDatastoreType.CONFIGURATION, getRoutersIdentifier(routerId), rtrs);
192 handleEnableSnat(routerName);
195 public void handleEnableSnat(String routerName){
196 LOG.info("Handling SNAT for router {}", routerName);
198 // Allocate Primary Napt Switch for this router
199 BigInteger primarySwitchId = naptSwitchSelector.selectNewNAPTSwitch(routerName);
201 LOG.debug("NAT Service : About to create and install outbound miss entry in Primary Switch {} for router {}", primarySwitchId, routerName);
202 // write metadata and punt
203 installOutboundMissEntry(routerName, primarySwitchId);
204 // Now install entries in SNAT tables to point to Primary for each router
205 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
206 for(BigInteger dpnId : switches) {
207 // Handle switches and NAPT switches separately
208 if( dpnId != primarySwitchId ) {
209 LOG.debug("NAT Service : Handle Ordinary switch");
210 handleSwitches(dpnId, routerName, primarySwitchId);
212 LOG.debug("NAT Service : Handle NAPT switch");
213 handlePrimaryNaptSwitch(dpnId, routerName, primarySwitchId);
217 // call registerMapping Api
218 long segmentId = NatUtil.getVpnId(dataBroker, routerName);
219 LOG.debug("NAT Service : Preparing to call registerMapping for routerName {} and Id {}", routerName, segmentId);
221 List<Uuid> subnetList = null;
222 List<String> externalIps = null;
224 InstanceIdentifier<Routers> id = InstanceIdentifier
225 .builder(ExtRouters.class)
226 .child(Routers.class, new RoutersKey(routerName))
229 Optional<Routers> extRouters = read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
231 if(extRouters.isPresent())
233 LOG.debug("NAT Service : Fetching values from extRouters model");
234 Routers routerEntry= extRouters.get();
235 subnetList = routerEntry.getSubnetIds();
236 externalIps = routerEntry.getExternalIps();
238 int extIpCounter = externalIps.size();
239 LOG.debug("NAT Service : counter values before looping counter {} and extIpCounter {}", counter, extIpCounter);
240 for(Uuid subnet : subnetList) {
241 LOG.debug("NAT Service : Looping internal subnets for subnet {}", subnet);
242 InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier
243 .builder(Subnetmaps.class)
244 .child(Subnetmap.class, new SubnetmapKey(subnet))
246 Optional<Subnetmap> sn = read(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetmapId);
249 Subnetmap subnetmapEntry = sn.get();
250 String subnetString = subnetmapEntry.getSubnetIp();
251 String[] subnetSplit = subnetString.split("/");
252 String subnetIp = subnetSplit[0];
253 String subnetPrefix = "0";
254 if(subnetSplit.length == 2) {
255 subnetPrefix = subnetSplit[1];
257 IPAddress subnetAddr = new IPAddress(subnetIp, Integer.parseInt(subnetPrefix));
258 LOG.debug("NAT Service : subnetAddr is {} and subnetPrefix is {}", subnetAddr.getIpAddress(), subnetAddr.getPrefixLength());
260 LOG.debug("NAT Service : counter values counter {} and extIpCounter {}", counter, extIpCounter);
261 if(extIpCounter != 0) {
262 if(counter < extIpCounter) {
263 String[] IpSplit = externalIps.get(counter).split("/");
264 String externalIp = IpSplit[0];
265 String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
266 if(IpSplit.length==2) {
267 extPrefix = IpSplit[1];
269 IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
270 LOG.debug("NAT Service : externalIp is {} and extPrefix is {}", externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
271 naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
272 LOG.debug("NAT Service : Called registerMapping for subnetIp {}, prefix {}, externalIp {}. prefix {}", subnetIp, subnetPrefix,
273 externalIp, extPrefix);
275 String externalIpAddrPrefix = externalIpAddr.getIpAddress() + "/" + externalIpAddr.getPrefixLength();
276 LOG.debug("NAT Service : Calling handleSnatReverseTraffic for primarySwitchId {}, routerName {} and externalIpAddPrefix {}", primarySwitchId, routerName, externalIpAddrPrefix);
277 handleSnatReverseTraffic(primarySwitchId, segmentId, externalIpAddrPrefix);
280 counter = 0; //Reset the counter which runs on externalIps for round-robbin effect
281 LOG.debug("NAT Service : Counter on externalIps got reset");
282 String[] IpSplit = externalIps.get(counter).split("/");
283 String externalIp = IpSplit[0];
284 String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
285 if(IpSplit.length==2) {
286 extPrefix = IpSplit[1];
288 IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
289 LOG.debug("NAT Service : externalIp is {} and extPrefix is {}", externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
290 naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
291 LOG.debug("NAT Service : Called registerMapping for subnetIp {}, prefix {}, externalIp {}. prefix {}", subnetIp, subnetPrefix,
292 externalIp, extPrefix);
294 String externalIpAddrPrefix = externalIpAddr.getIpAddress() + "/" + externalIpAddr.getPrefixLength();
295 LOG.debug("NAT Service : Calling handleSnatReverseTraffic for primarySwitchId {}, routerName {} and externalIpAddPrefix {}", primarySwitchId, routerName, externalIpAddrPrefix);
296 handleSnatReverseTraffic(primarySwitchId, segmentId, externalIpAddrPrefix);
301 LOG.debug("NAT Service : Counter on externalIps incremented to {}", counter);
304 LOG.warn("NAT Service : No internal subnets present in extRouters Model");
309 LOG.info("NAT Service : handleEnableSnat() Exit");
312 private void addOrDelDefFibRouteToSNAT(String routerName, boolean create) {
313 //Router ID is used as the internal VPN's name, hence the vrf-id in VpnInstance Op DataStore
314 InstanceIdentifier<VpnInstanceOpDataEntry> id = NatUtil.getVpnInstanceOpDataIdentifier(routerName);
315 Optional<VpnInstanceOpDataEntry> vpnInstOp = NatUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
316 if (vpnInstOp.isPresent()) {
317 List<VpnToDpnList> dpnListInVpn = vpnInstOp.get().getVpnToDpnList();
318 if(dpnListInVpn == null) {
319 LOG.debug("Current no dpns part of router {} to program default NAT route", routerName);
322 long vpnId = NatUtil.readVpnId(dataBroker, routerName);
323 if(vpnId == NatConstants.INVALID_ID) {
324 LOG.error("Could not retrieve router Id for {} to program default NAT route in FIB", routerName);
327 for (VpnToDpnList dpn : dpnListInVpn) {
328 BigInteger dpnId = dpn.getDpnId();
329 if (create == true) {
330 //installDefNATRouteInDPN(dpnId, vpnId);
331 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId);
333 //removeDefNATRouteInDPN(dpnId, vpnId);
334 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId);
340 public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
342 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
344 Optional<T> result = Optional.absent();
347 result = tx.read(datastoreType, path).get();
351 throw new RuntimeException(e);
357 public void close() throws Exception
359 if (listenerRegistration != null)
363 listenerRegistration.close();
365 catch (final Exception e)
367 LOG.error("Error when cleaning up ExternalRoutersListener.", e);
370 listenerRegistration = null;
372 LOG.debug("ExternalRoutersListener Closed");
375 protected void installOutboundMissEntry(String routerName, BigInteger primarySwitchId) {
376 long routerId = NatUtil.getVpnId(dataBroker, routerName);
377 LOG.debug("NAT Service : Router ID from getVpnId {}", routerId);
378 if(routerId != NatConstants.INVALID_ID) {
379 LOG.debug("NAT Service : Creating miss entry on primary {}, for router {}", primarySwitchId, routerId);
380 createOutboundTblEntry(primarySwitchId, routerId);
382 LOG.error("NAT Service : Unable to fetch Router Id for RouterName {}, failed to createAndInstallMissEntry", routerName);
386 public String getFlowRefOutbound(BigInteger dpnId, short tableId, long routerID) {
387 return new StringBuilder().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
388 append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
391 public BigInteger getCookieOutboundFlow(long routerId) {
392 return NatConstants.COOKIE_OUTBOUND_NAPT_TABLE.add(new BigInteger("0110001", 16)).add(
393 BigInteger.valueOf(routerId));
396 protected FlowEntity buildOutboundFlowEntity(BigInteger dpId, long routerId) {
397 LOG.debug("NAT Service : buildOutboundFlowEntity called for dpId {} and routerId{}", dpId, routerId);
398 List<MatchInfo> matches = new ArrayList<MatchInfo>();
399 matches.add(new MatchInfo(MatchFieldType.eth_type,
400 new long[] { 0x0800L }));
401 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
402 BigInteger.valueOf(routerId), MetaDataUtil.METADATA_MASK_VRFID }));
404 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
405 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
406 actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[] {}));
407 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
408 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { BigInteger.valueOf(routerId), MetaDataUtil.METADATA_MASK_VRFID }));
410 String flowRef = getFlowRefOutbound(dpId, NatConstants.OUTBOUND_NAPT_TABLE, routerId);
411 BigInteger cookie = getCookieOutboundFlow(routerId);
412 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.OUTBOUND_NAPT_TABLE, flowRef,
414 cookie, matches, instructions);
415 LOG.debug("NAT Service : returning flowEntity {}", flowEntity);
419 public void createOutboundTblEntry(BigInteger dpnId, long routerId) {
420 LOG.debug("NAT Service : createOutboundTblEntry called for dpId {} and routerId {}", dpnId, routerId);
421 FlowEntity flowEntity = buildOutboundFlowEntity(dpnId, routerId);
422 LOG.debug("NAT Service : Installing flow {}", flowEntity);
423 mdsalManager.installFlow(flowEntity);
426 protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
428 Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
429 .setSourceDpid(srcDpId)
430 .setDestinationDpid(dstDpId).build());
431 RpcResult<GetTunnelInterfaceNameOutput> rpcResult = result.get();
432 if(!rpcResult.isSuccessful()) {
433 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
435 return rpcResult.getResult().getInterfaceName();
437 } catch (InterruptedException | ExecutionException | NullPointerException e) {
438 LOG.warn("NAT Service : Exception when getting tunnel interface Id for tunnel between {} and {}", srcDpId, dstDpId);
444 protected List<ActionInfo> getEgressActionsForInterface(String ifName, long routerId) {
445 LOG.debug("NAT Service : getEgressActionsForInterface called for interface {}", ifName);
446 List<ActionInfo> listActionInfo = new ArrayList<ActionInfo>();
448 Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
449 interfaceManager.getEgressActionsForInterface(
450 new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).setTunnelKey(routerId).build());
451 RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
452 if(!rpcResult.isSuccessful()) {
453 LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName, rpcResult.getErrors());
455 List<Action> actions =
456 rpcResult.getResult().getAction();
457 for (Action action : actions) {
458 org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionClass = action.getAction();
459 if (actionClass instanceof OutputActionCase) {
460 listActionInfo.add(new ActionInfo(ActionType.output,
461 new String[] {((OutputActionCase)actionClass).getOutputAction()
462 .getOutputNodeConnector().getValue()}));
463 } else if (actionClass instanceof PushVlanActionCase) {
464 listActionInfo.add(new ActionInfo(ActionType.push_vlan, new String[] {}));
465 } else if (actionClass instanceof SetFieldCase) {
466 if (((SetFieldCase)actionClass).getSetField().getVlanMatch() != null) {
467 int vlanVid = ((SetFieldCase)actionClass).getSetField().getVlanMatch().getVlanId().getVlanId().getValue();
468 listActionInfo.add(new ActionInfo(ActionType.set_field_vlan_vid,
469 new String[] { Long.toString(vlanVid) }));
474 } catch (InterruptedException | ExecutionException e) {
475 LOG.warn("Exception when egress actions for interface {}", ifName, e);
477 return listActionInfo;
480 protected void installSnatMissEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
481 LOG.debug("NAT Service : installSnatMissEntry called for dpnId {} with primaryBucket {} ", dpnId, bucketInfo.get(0));
482 // Install the select group
483 long groupId = createGroupId(getGroupIdKey(routerName));
484 GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
485 LOG.debug("NAT Service : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
486 mdsalManager.installGroup(groupEntity);
487 // Install miss entry pointing to group
488 FlowEntity flowEntity = buildSnatFlowEntity(dpnId, routerName, groupId);
489 mdsalManager.installFlow(flowEntity);
492 public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId) {
494 LOG.debug("NAT Service : buildSnatFlowEntity is called for dpId {}, routerName {} and groupId {}", dpId, routerName, groupId );
495 long routerId = NatUtil.getVpnId(dataBroker, routerName);
496 List<MatchInfo> matches = new ArrayList<MatchInfo>();
497 matches.add(new MatchInfo(MatchFieldType.eth_type,
498 new long[] { 0x0800L }));
499 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
500 BigInteger.valueOf(routerId), MetaDataUtil.METADATA_MASK_VRFID }));
503 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
504 List<ActionInfo> actionsInfo = new ArrayList<ActionInfo>();
506 ActionInfo actionSetField = new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
507 BigInteger.valueOf(routerId)}) ;
508 actionsInfo.add(actionSetField);
509 LOG.debug("NAT Service : Setting the tunnel to the list of action infos {}", actionsInfo);
510 actionsInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
511 instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfo));
512 String flowRef = getFlowRefSnat(dpId, NatConstants.PSNAT_TABLE, routerName);
513 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
514 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
515 NatConstants.COOKIE_SNAT_TABLE, matches, instructions);
517 LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
521 // TODO : Replace this with ITM Rpc once its available with full functionality
522 protected void installTerminatingServiceTblEntry(BigInteger dpnId, String routerName) {
523 LOG.debug("NAT Service : creating entry for Terminating Service Table for switch {}, routerName {}", dpnId, routerName);
524 FlowEntity flowEntity = buildTsFlowEntity(dpnId, routerName);
525 mdsalManager.installFlow(flowEntity);
529 private FlowEntity buildTsFlowEntity(BigInteger dpId, String routerName) {
531 BigInteger routerId = BigInteger.valueOf (NatUtil.getVpnId(dataBroker, routerName));
532 List<MatchInfo> matches = new ArrayList<MatchInfo>();
533 matches.add(new MatchInfo(MatchFieldType.eth_type,
534 new long[] { 0x0800L }));
535 matches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {routerId }));
537 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
538 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[]
539 { routerId, MetaDataUtil.METADATA_MASK_VRFID }));
540 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[]
541 { NatConstants.OUTBOUND_NAPT_TABLE }));
542 String flowRef = getFlowRefTs(dpId, NatConstants.TERMINATING_SERVICE_TABLE, routerId.longValue());
543 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.TERMINATING_SERVICE_TABLE, flowRef,
544 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0,
545 NatConstants.COOKIE_TS_TABLE, matches, instructions);
549 public String getFlowRefTs(BigInteger dpnId, short tableId, long routerID) {
550 return new StringBuilder().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
551 append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
554 public static String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
555 return new StringBuilder().append(NatConstants.SNAT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
556 append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
559 private String getGroupIdKey(String routerName){
560 String groupIdKey = new String("snatmiss." + routerName);
564 protected long createGroupId(String groupIdKey) {
565 AllocateIdInput getIdInput = new AllocateIdInputBuilder()
566 .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
569 Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
570 RpcResult<AllocateIdOutput> rpcResult = result.get();
571 return rpcResult.getResult().getIdValue();
572 } catch (NullPointerException | InterruptedException | ExecutionException e) {
578 protected void createGroupIdPool() {
579 CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
580 .setPoolName(NatConstants.SNAT_IDPOOL_NAME)
581 .setLow(NatConstants.SNAT_ID_LOW_VALUE)
582 .setHigh(NatConstants.SNAT_ID_HIGH_VALUE)
585 Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
586 if ((result != null) && (result.get().isSuccessful())) {
587 LOG.debug("NAT Service : Created GroupIdPool");
589 LOG.error("NAT Service : Unable to create GroupIdPool");
591 } catch (InterruptedException | ExecutionException e) {
592 LOG.error("Failed to create PortPool for NAPT Service",e);
596 protected void handleSwitches (BigInteger dpnId, String routerName, BigInteger primarySwitchId) {
597 LOG.debug("NAT Service : Installing SNAT miss entry in switch {}", dpnId);
598 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
599 String ifNamePrimary = getTunnelInterfaceName( dpnId, primarySwitchId);
600 List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
601 long routerId = NatUtil.getVpnId(dataBroker, routerName);
603 if(ifNamePrimary != null) {
604 LOG.debug("NAT Service : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
605 listActionInfoPrimary = getEgressActionsForInterface(ifNamePrimary, routerId);
607 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
609 listBucketInfo.add(0, bucketPrimary);
610 installSnatMissEntry(dpnId, listBucketInfo, routerName);
614 protected void handlePrimaryNaptSwitch (BigInteger dpnId, String routerName, BigInteger primarySwitchId) {
617 * Primary NAPT Switch – bucket Should always point back to its own Outbound Table
620 LOG.debug("NAT Service : Installing SNAT miss entry in Primary NAPT switch {} ", dpnId);
622 List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
623 List<ActionInfo> listActionInfoPrimary = new ArrayList<ActionInfo>();
624 listActionInfoPrimary.add(new ActionInfo(ActionType.nx_resubmit, new String[]{String.valueOf(NatConstants.TERMINATING_SERVICE_TABLE)}));
625 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
626 listBucketInfo.add(0, bucketPrimary);
628 long routerId = NatUtil.getVpnId(dataBroker, routerName);
630 installSnatMissEntry(dpnId, listBucketInfo, routerName);
631 installTerminatingServiceTblEntry(dpnId, routerName);
632 installNaptPfibEntry(dpnId, routerId);
636 public void installNaptPfibEntry(BigInteger dpnId, long routerId) {
637 LOG.debug("NAT Service : installNaptPfibEntry called for dpnId {} and routerId {} ", dpnId, routerId);
638 FlowEntity flowEntity = buildNaptPfibFlowEntity(dpnId, routerId);
639 mdsalManager.installFlow(flowEntity);
642 public FlowEntity buildNaptPfibFlowEntity(BigInteger dpId, long routerId) {
644 LOG.debug("NAT Service : buildNaptPfibFlowEntity is called for dpId {}, routerId {}", dpId, routerId );
645 List<MatchInfo> matches = new ArrayList<MatchInfo>();
646 matches.add(new MatchInfo(MatchFieldType.eth_type,
647 new long[] { 0x0800L }));
648 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
649 BigInteger.valueOf(routerId), MetaDataUtil.METADATA_MASK_VRFID }));
651 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
652 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
653 listActionInfo.add(new ActionInfo(ActionType.nx_resubmit, new String[] { Integer.toString(NatConstants.L3_FIB_TABLE) }));
654 instructionInfo.add(new InstructionInfo(InstructionType.apply_actions, listActionInfo));
656 String flowRef = getFlowRefTs(dpId, NatConstants.NAPT_PFIB_TABLE, routerId);
657 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.NAPT_PFIB_TABLE, flowRef,
658 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
659 NatConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
661 LOG.debug("NAT Service : Returning NaptPFib Flow Entity {}", flowEntity);
665 private void handleSnatReverseTraffic(BigInteger dpnId, long routerId, String externalIp) {
666 LOG.debug("NAT Service : handleSnatReverseTraffic() entry for DPN ID, routerId, externalIp : {}", dpnId, routerId, externalIp);
667 Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
668 if(networkId == null) {
669 LOG.error("NAT Service : networkId is null for the router ID {}", routerId);
672 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
673 if(vpnName == null) {
674 LOG.error("NAT Service : No VPN associated with ext nw {} to handle add external ip configuration {} in router {}",
675 networkId, externalIp, routerId);
678 advToBgpAndInstallFibAndTsFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, vpnName, routerId, externalIp, vpnService, fibService, bgpManager, dataBroker, LOG);
679 LOG.debug("NAT Service : handleSnatReverseTraffic() exit for DPN ID, routerId, externalIp : {}", dpnId, routerId, externalIp);
682 public void advToBgpAndInstallFibAndTsFlows(final BigInteger dpnId, final short tableId, final String vpnName, final long routerId, final String externalIp,
683 VpnRpcService vpnService, final FibRpcService fibService, final IBgpManager bgpManager, final DataBroker dataBroker,
685 LOG.debug("NAT Service : advToBgpAndInstallFibAndTsFlows() entry for DPN ID {}, tableId {}, vpnname {} and externalIp {}", dpnId, tableId, vpnName, externalIp);
686 //Generate VPN label for the external IP
687 GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
688 Future<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
690 //On successful generation of the VPN label, advertise the route to the BGP and install the FIB routes.
691 ListenableFuture<RpcResult<Void>> future = Futures.transform(JdkFutureAdapters.listenInPoolThread(labelFuture), new AsyncFunction<RpcResult<GenerateVpnLabelOutput>, RpcResult<Void>>() {
694 public ListenableFuture<RpcResult<Void>> apply(RpcResult<GenerateVpnLabelOutput> result) throws Exception {
695 if (result.isSuccessful()) {
696 LOG.debug("NAT Service : inside apply with result success");
697 GenerateVpnLabelOutput output = result.getResult();
698 long label = output.getLabel();
701 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
702 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
703 NatUtil.addPrefixToBGP(bgpManager, rd, externalIp, nextHopIp, label, log);
705 //Get IPMaps from the DB for the router ID
706 List<IpMap> dbIpMaps = naptManager.getIpMapList(dataBroker, routerId);
708 for (IpMap dbIpMap : dbIpMaps) {
709 String dbExternalIp = dbIpMap.getExternalIp();
710 //Select the IPMap, whose external IP is the IP for which FIB is installed
711 if (externalIp.contains(dbExternalIp)) {
712 String dbInternalIp = dbIpMap.getInternalIp();
713 IpMapKey dbIpMapKey = dbIpMap.getKey();
714 IpMap newIpm = new IpMapBuilder().setKey(dbIpMapKey).setInternalIp(dbInternalIp).setExternalIp(dbExternalIp).setLabel(label).build();
715 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, naptManager.getIpMapIdentifier(routerId, dbInternalIp), newIpm);
719 //Install custom FIB routes
720 List<Instruction> customInstructions = new ArrayList<>();
721 customInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[]{tableId}).buildInstruction(0));
722 makeTunnelTableEntry(dpnId, label, customInstructions);
723 makeLFibTableEntry(dpnId, label, customInstructions);
725 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId)
726 .setIpAddress(externalIp).setServiceId(label).setInstruction(customInstructions).build();
727 Future<RpcResult<Void>> future = fibService.createFibEntry(input);
728 return JdkFutureAdapters.listenInPoolThread(future);
730 LOG.error("NAT Service : inside apply with result failed");
731 String errMsg = String.format("Could not retrieve the label for prefix %s in VPN %s, %s", externalIp, vpnName, result.getErrors());
732 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
737 Futures.addCallback(future, new FutureCallback<RpcResult<Void>>() {
740 public void onFailure(Throwable error) {
741 log.error("NAT Service : Error in generate label or fib install process", error);
745 public void onSuccess(RpcResult<Void> result) {
746 if (result.isSuccessful()) {
747 log.info("NAT Service : Successfully installed custom FIB routes for prefix {}", externalIp);
749 log.error("NAT Service : Error in rpc call to create custom Fib entries for prefix {} in DPN {}, {}", externalIp, dpnId, result.getErrors());
755 private void makeLFibTableEntry(BigInteger dpId, long serviceId, List<Instruction> customInstructions) {
756 List<MatchInfo> matches = new ArrayList<MatchInfo>();
757 matches.add(new MatchInfo(MatchFieldType.eth_type,
758 new long[] { 0x8847L }));
759 matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
761 List<Instruction> instructions = new ArrayList<Instruction>();
762 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
763 actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
764 Instruction writeInstruction = new InstructionInfo(InstructionType.write_actions, actionsInfos).buildInstruction(0);
765 instructions.add(writeInstruction);
766 instructions.addAll(customInstructions);
768 // Install the flow entry in L3_LFIB_TABLE
769 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
771 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
773 COOKIE_VM_LFIB_TABLE, matches, instructions);
775 mdsalManager.installFlow(dpId, flowEntity);
777 LOG.debug("NAT Service : LFIB Entry for dpID {} : label : {} modified successfully {}",dpId, serviceId );
780 private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, List<Instruction> customInstructions) {
781 List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
783 LOG.debug("NAT Service : Create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", dpnId , serviceId);
785 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
787 Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
788 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5, String.format("%s:%d","TST Flow Entry ",serviceId),
789 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)),mkMatches, customInstructions);
791 mdsalManager.installFlow(dpnId, terminatingServiceTableFlowEntity);
794 protected InstanceIdentifier<RouterIds> getRoutersIdentifier(long routerId) {
795 InstanceIdentifier<RouterIds> id = InstanceIdentifier.builder(
796 RouterIdName.class).child(RouterIds.class, new RouterIdsKey(routerId)).build();
800 private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
801 return new StringBuilder(64).append(NatConstants.SNAT_FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
802 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
803 .append(id).append(NwConstants.FLOWID_SEPARATOR).append(ipAddress).toString();
807 protected void update(InstanceIdentifier<Routers> identifier, Routers original, Routers update) {
808 boolean originalSNATEnabled = original.isEnableSnat();
809 boolean updatedSNATEnabled = update.isEnableSnat();
810 if(originalSNATEnabled != updatedSNATEnabled) {
811 if(originalSNATEnabled) {
812 //SNAT disabled for the router
813 String routerName = original.getRouterName();
814 Uuid networkUuid = original.getNetworkId();
815 List<String> externalIps = original.getExternalIps();
816 LOG.info("NAT Service : SNAT disabled for Router {}", routerName);
817 handleDisableSnat(routerName, networkUuid, externalIps);
819 String routerName = original.getRouterName();
820 LOG.info("NAT Service : SNAT enabled for Router {}", original.getRouterName());
821 handleEnableSnat(routerName);
827 protected void remove(InstanceIdentifier<Routers> identifier, Routers router) {
828 LOG.trace("NAT Service : Router delete method");
831 ROUTER DELETE SCENARIO
832 1) Get the router ID from the event.
833 2) Build the cookie information from the router ID.
834 3) Get the primary and secondary switch DPN IDs using the router ID from the model.
835 4) Build the flow with the cookie value.
836 5) Delete the flows which matches the cookie information from the NAPT outbound, inbound tables.
837 6) Remove the flows from the other switches which points to the primary and secondary switches for the flows related the router ID.
838 7) Get the list of external IP address maintained for the router ID.
839 8) Use the NaptMananager removeMapping API to remove the list of IP addresses maintained.
840 9) Withdraw the corresponding routes from the BGP.
843 if (identifier == null || router == null) {
844 LOG.info("++++++++++++++NAT Service : ExternalRoutersListener:remove:: returning without processing since routers is null");
848 String routerName = router.getRouterName();
849 LOG.info("Removing default NAT route from FIB on all dpns part of router {} ", routerName);
850 addOrDelDefFibRouteToSNAT(routerName, false);
851 Uuid networkUuid = router.getNetworkId();
852 List<String> externalIps = router.getExternalIps();
853 handleDisableSnat(routerName, networkUuid, externalIps);
857 public void handleDisableSnat(String routerName, Uuid networkUuid, List<String> externalIps){
858 LOG.info("NAT Service : handleDisableSnat() Entry");
859 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
861 BigInteger naptSwitchDpnId = null;
862 InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch = NatUtil.buildNaptSwitchRouterIdentifier(routerName);
863 Optional<RouterToNaptSwitch> rtrToNapt = read(dataBroker, LogicalDatastoreType.OPERATIONAL, routerToNaptSwitch );
864 if(rtrToNapt.isPresent()) {
865 naptSwitchDpnId = rtrToNapt.get().getPrimarySwitchId();
867 LOG.debug("NAT Service : got primarySwitch as dpnId{} ", naptSwitchDpnId);
869 removeNaptFlowsFromActiveSwitch(routerId, routerName, naptSwitchDpnId);
870 removeFlowsFromNonActiveSwitches(routerName, naptSwitchDpnId);
871 advToBgpAndRemoveFibAndTsFlows(naptSwitchDpnId, routerId, networkUuid, externalIps);
873 //Use the NaptMananager removeMapping API to remove the entire list of IP addresses maintained for the router ID.
874 LOG.debug("NAT Service : Remove the Internal to external IP address maintained for the router ID {} in the DS", routerId);
875 naptManager.removeMapping(routerId);
877 LOG.info("NAT Service : handleDisableSnat() Exit");
880 public void removeNaptFlowsFromActiveSwitch(long routerId, String routerName, BigInteger dpnId){
881 LOG.debug("NAT Service : Remove NAPT flows from Active switch");
882 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
884 //Remove the PSNAT entry which forwards the packet to Terminating Service table
885 String pSNatFlowRef = getFlowRefSnat(dpnId, NatConstants.PSNAT_TABLE, routerName);
886 FlowEntity pSNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.PSNAT_TABLE, pSNatFlowRef);
888 LOG.info("NAT Service : Remove the flow in the " + NatConstants.PSNAT_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
889 mdsalManager.removeFlow(pSNatFlowEntity);
891 //Remove the group entry which resubmits the packet to the Terminating Service table or to the out port accordingly.
892 long groupId = createGroupId(getGroupIdKey(routerName));
893 List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
894 GroupEntity pSNatGroupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, listBucketInfo);
896 LOG.info("NAT Service : Remove the group {} for the active switch with the DPN ID {} and router ID {}", groupId, dpnId, routerId);
897 mdsalManager.removeGroup(pSNatGroupEntity);
899 //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table
900 String tsFlowRef = getFlowRefTs(dpnId, NatConstants.TERMINATING_SERVICE_TABLE, routerId);
901 FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.TERMINATING_SERVICE_TABLE, tsFlowRef);
903 LOG.info("NAT Service : Remove the flow in the " + NatConstants.TERMINATING_SERVICE_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
904 mdsalManager.removeFlow(tsNatFlowEntity);
906 //Remove the Outbound flow entry which forwards the packet to FIB Table
907 String outboundNatFlowRef = getFlowRefOutbound(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, routerId);
908 FlowEntity outboundNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, outboundNatFlowRef);
910 LOG.info("NAT Service : Remove the flow in the " + NatConstants.OUTBOUND_NAPT_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
911 mdsalManager.removeFlow(outboundNatFlowEntity);
913 //Remove the NAPT PFIB TABLE which forwards the packet to FIB Table
914 String natPfibFlowRef = getFlowRefTs(dpnId, NatConstants.NAPT_PFIB_TABLE, routerId);
915 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.NAPT_PFIB_TABLE, natPfibFlowRef);
917 LOG.info("NAT Service : Remove the flow in the " + NatConstants.NAPT_PFIB_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
918 mdsalManager.removeFlow(natPfibFlowEntity);
920 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
921 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
922 if(ipPortMapping == null){
923 LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
927 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
928 for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes){
929 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
930 for(IpPortMap ipPortMap : ipPortMaps){
931 String ipPortInternal = ipPortMap.getIpPortInternal();
932 String[] ipPortParts = ipPortInternal.split(":");
933 if(ipPortParts.length != 2) {
934 LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
937 String internalIp = ipPortParts[0];
938 String internalPort = ipPortParts[1];
940 //Build the flow for the outbound NAPT table
941 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId), internalIp, Integer.valueOf(internalPort));
942 FlowEntity outboundNaptFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
944 LOG.info("NAT Service : Remove the flow in the " + NatConstants.OUTBOUND_NAPT_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
945 mdsalManager.removeFlow(outboundNaptFlowEntity);
947 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
948 String externalIp = ipPortExternal.getIpAddress();
949 int externalPort = ipPortExternal.getPortNum();
951 //Build the flow for the inbound NAPT table
952 switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NatConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId), externalIp, externalPort);
953 FlowEntity inboundNaptFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
955 LOG.info("NAT Service : Remove the flow in the " + NatConstants.INBOUND_NAPT_TABLE + " for the active active switch with the DPN ID {} and router ID {}", dpnId, routerId);
956 mdsalManager.removeFlow(inboundNaptFlowEntity);
961 public void removeFlowsFromNonActiveSwitches(String routerName, BigInteger naptSwitchDpnId){
962 LOG.debug("NAT Service : Remove NAPT related flows from non active switches");
964 //Remove the flows from the other switches which points to the primary and secondary switches for the flows related the router ID.
965 List<VpnToDpnList> allSwitchList = NatUtil.getVpnToDpnList(dataBroker, routerName);
966 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
967 for (VpnToDpnList eachSwitch : allSwitchList) {
968 BigInteger dpnId = eachSwitch.getDpnId();
969 if (naptSwitchDpnId != dpnId) {
970 LOG.info("NAT Service : Handle Ordinary switch");
972 //Remove the PSNAT entry which forwards the packet to Terminating Service table
973 String pSNatFlowRef = getFlowRefSnat(dpnId, NatConstants.PSNAT_TABLE, String.valueOf(routerName));
974 FlowEntity pSNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.PSNAT_TABLE, pSNatFlowRef);
976 LOG.info("Remove the flow in the " + NatConstants.PSNAT_TABLE + " for the non active switch with the DPN ID {} and router ID {}", dpnId, routerId);
977 mdsalManager.removeFlow(pSNatFlowEntity);
979 //Remove the group entry which resubmits the packet to the Terminating Service table or to the out port accordingly.
980 long groupId = createGroupId(getGroupIdKey(routerName));
981 List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
982 GroupEntity pSNatGroupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, listBucketInfo);
984 LOG.info("NAT Service : Remove the group {} for the non active switch with the DPN ID {} and router ID {}", groupId, dpnId, routerId);
985 mdsalManager.removeGroup(pSNatGroupEntity);
991 public void advToBgpAndRemoveFibAndTsFlows(final BigInteger dpnId, Long routerId, Uuid networkUuid, List<String> externalIps){
992 //Withdraw the corresponding routes from the BGP.
993 //Get the network ID using the router ID.
994 LOG.debug("NAT Service : Advertise to BGP and remove routes");
995 if(networkUuid == null ){
996 LOG.error("NAT Service : networkId is null");
1000 //Get the VPN Name using the network ID
1001 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid, LOG);
1002 if (vpnName == null) {
1003 LOG.error("No VPN associated with ext nw {} for the router {}",
1004 networkUuid, routerId);
1008 //Inform BGP about the route removal
1009 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
1010 String prefix = "32";
1011 NatUtil.removePrefixFromBGP(bgpManager, rd, prefix, LOG);
1013 //Remove custom FIB routes
1014 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
1015 final String externalIp = externalIps.get(0);
1017 //Get IPMaps from the DB for the router ID
1018 List<IpMap> dbIpMaps = naptManager.getIpMapList(dataBroker, routerId);
1019 if(dbIpMaps == null ){
1020 LOG.error("NAT Service : IPMaps is null");
1024 long tempLabel = -1;
1025 for(IpMap dbIpMap: dbIpMaps) {
1026 String dbExternalIp = dbIpMap.getExternalIp();
1027 //Select the IPMap, whose external IP is the IP for which FIB is installed
1028 if (externalIp.contains(dbExternalIp)) {
1029 tempLabel = dbIpMap.getLabel();
1033 if(tempLabel == -1){
1034 LOG.error("NAT Service : Label is null");
1038 final long label = tempLabel;
1039 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp + "/" +
1040 NatConstants.DEFAULT_PREFIX).setServiceId(label).build();
1041 Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
1043 ListenableFuture<RpcResult<Void>> labelFuture = Futures.transform(JdkFutureAdapters.listenInPoolThread(future), new AsyncFunction<RpcResult<Void>, RpcResult<Void>>() {
1046 public ListenableFuture<RpcResult<Void>> apply(RpcResult<Void> result) throws Exception {
1048 if (result.isSuccessful()) {
1049 removeTunnelTableEntry(dpnId, label);
1050 removeLFibTableEntry(dpnId, label);
1051 RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
1052 Future<RpcResult<Void>> labelFuture = vpnService.removeVpnLabel(labelInput);
1053 return JdkFutureAdapters.listenInPoolThread(labelFuture);
1055 String errMsg = String.format("RPC call to remove custom FIB entries on dpn %s for prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
1057 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
1063 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
1066 public void onFailure(Throwable error) {
1067 LOG.error("NAT Service : Error in removing the label or custom fib entries", error);
1071 public void onSuccess(RpcResult<Void> result) {
1072 if (result.isSuccessful()) {
1073 LOG.debug("NAT Service : Successfully removed the label for the prefix {} from VPN {}", externalIp, vpnName);
1075 LOG.error("NAT Service : Error in removing the label for prefix {} from VPN {}, {}", externalIp, vpnName, result.getErrors());
1081 private void removeTunnelTableEntry(BigInteger dpnId, long serviceId) {
1082 LOG.info("NAT Service : remove terminatingServiceActions called with DpnId = {} and label = {}", dpnId , serviceId);
1083 List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
1084 // Matching metadata
1085 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
1086 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
1087 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
1088 5, String.format("%s:%d","TST Flow Entry ",serviceId), 0, 0,
1089 COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null);
1090 mdsalManager.removeFlow(dpnId, flowEntity);
1091 LOG.debug("NAT Service : Terminating service Entry for dpID {} : label : {} removed successfully {}",dpnId, serviceId);
1094 private void removeLFibTableEntry(BigInteger dpnId, long serviceId) {
1095 List<MatchInfo> matches = new ArrayList<MatchInfo>();
1096 matches.add(new MatchInfo(MatchFieldType.eth_type,
1097 new long[] { 0x8847L }));
1098 matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
1100 String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
1102 LOG.debug("NAT Service : removing LFib entry with flow ref {}", flowRef);
1104 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
1106 COOKIE_VM_LFIB_TABLE, matches, null);
1108 mdsalManager.removeFlow(dpnId, flowEntity);
1110 LOG.debug("NAT Service : LFIB Entry for dpID : {} label : {} removed successfully {}",dpnId, serviceId);
1113 public static GroupEntity buildGroupEntity(BigInteger dpnId, long groupId) {
1114 GroupEntity groupEntity = new GroupEntity(dpnId);
1115 groupEntity.setGroupId(groupId);
1119 protected InstanceIdentifier<Routers> getWildCardPath()
1121 return InstanceIdentifier.create(ExtRouters.class).child(Routers.class);
1125 protected ExternalRoutersListener getDataTreeChangeListener()
1127 return ExternalRoutersListener.this;