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
8 package org.opendaylight.netvirt.natservice.internal;
10 import com.google.common.base.Optional;
11 import com.google.common.collect.Sets;
13 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
16 import org.opendaylight.genius.mdsalutil.*;
17 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetFieldCase;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.*;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.RoutersKey;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.IpMapping;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.IpMappingKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
57 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
58 import org.opendaylight.yangtools.yang.common.RpcResult;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
62 import java.math.BigInteger;
63 import java.util.ArrayList;
64 import java.util.List;
66 import java.util.concurrent.ExecutionException;
67 import java.util.concurrent.Future;
68 import java.util.HashMap;
70 public class NaptSwitchHA {
71 private static final Logger LOG = LoggerFactory.getLogger(NaptSwitchHA.class);
72 private final DataBroker dataBroker;
73 private final IMdsalApiManager mdsalManager;
74 private final ItmRpcService itmManager;
75 private final OdlInterfaceRpcService interfaceManager;
76 private final IdManagerService idManager;
77 private final NAPTSwitchSelector naptSwitchSelector;
78 private final ExternalRoutersListener externalRouterListener;
79 private final IBgpManager bgpManager;
80 private final VpnRpcService vpnService;
81 private final FibRpcService fibService;
82 private List<String> externalIpsCache;
83 private HashMap<String,Long> externalIpsLabel;
85 public NaptSwitchHA(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
86 final ExternalRoutersListener externalRouterListener,
87 final ItmRpcService itmManager,
88 final OdlInterfaceRpcService interfaceManager,
89 final IdManagerService idManager,
90 final NAPTSwitchSelector naptSwitchSelector,
91 final IBgpManager bgpManager,
92 final VpnRpcService vpnService,
93 final FibRpcService fibService) {
94 this.dataBroker = dataBroker;
95 this.mdsalManager = mdsalManager;
96 this.externalRouterListener = externalRouterListener;
97 this.itmManager = itmManager;
98 this.interfaceManager = interfaceManager;
99 this.idManager = idManager;
100 this.naptSwitchSelector = naptSwitchSelector;
101 this.bgpManager = bgpManager;
102 this.vpnService = vpnService;
103 this.fibService =fibService;
106 /* This method checks the switch that gone down is a NaptSwitch for a router.
107 If it is a NaptSwitch
108 1) selects new NAPT switch
109 2) installs nat flows in new NAPT switch
110 table 21(FIB)->26(PSNAT)->group(resubmit/napttunnel)->36(Terminating)->46(outbound)->47(resubmit)->21
111 3) modify the group and miss entry flow in other vSwitches pointing to newNaptSwitch
112 4) Remove nat flows in oldNaptSwitch
114 /*public void handleNaptSwitchDown(BigInteger dpnId){
116 LOG.debug("handleNaptSwitchDown method is called with dpnId {}",dpnId);
117 BigInteger naptSwitch;
119 NaptSwitches naptSwitches = NatUtil.getNaptSwitch(dataBroker);
120 if (naptSwitches == null || naptSwitches.getRouterToNaptSwitch() == null || naptSwitches.getRouterToNaptSwitch().isEmpty()) {
121 LOG.debug("NaptSwitchDown: NaptSwitch is not allocated for none of the routers");
124 for (RouterToNaptSwitch routerToNaptSwitch : naptSwitches.getRouterToNaptSwitch()) {
125 String routerName = routerToNaptSwitch.getRouterName();
126 naptSwitch = routerToNaptSwitch.getPrimarySwitchId();
127 boolean naptStatus = isNaptSwitchDown(routerName,dpnId,naptSwitch);
129 LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
132 removeSnatFlowsInOldNaptSwitch(routerName,naptSwitch);
136 } catch (Exception ex) {
137 LOG.error("Exception in handleNaptSwitchDown method {}",ex);
141 protected void removeSnatFlowsInOldNaptSwitch(String routerName, BigInteger naptSwitch,HashMap<String,Long> externalIpmap) {
142 externalIpsLabel = externalIpmap;
143 //remove SNAT flows in old NAPT SWITCH
144 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
145 if (routerId == NatConstants.INVALID_ID) {
146 LOG.error("Invalid routerId returned for routerName {}",routerName);
150 //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table
151 String tsFlowRef = externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
152 FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE, tsFlowRef);
154 LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}"
155 ,NwConstants.INTERNAL_TUNNEL_TABLE, naptSwitch, routerId);
156 mdsalManager.removeFlow(tsNatFlowEntity);
158 //Remove the Outbound flow entry which forwards the packet to Outbound NAPT Table
159 String outboundNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
160 FlowEntity outboundNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
161 NwConstants.OUTBOUND_NAPT_TABLE, outboundNatFlowRef);
162 LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}"
163 ,NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
164 mdsalManager.removeFlow(outboundNatFlowEntity);
166 //Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for inbound traffic matching on the router ID.
167 String naptPFibflowRef = externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.NAPT_PFIB_TABLE, routerId);
168 FlowEntity naptPFibFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE, naptPFibflowRef);
169 LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}",
170 NwConstants.NAPT_PFIB_TABLE, naptSwitch, routerId);
171 mdsalManager.removeFlow(naptPFibFlowEntity);
173 //Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for outbound traffic matching on the vpn ID.
174 boolean switchSharedByRouters = false;
175 Uuid extNetworkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
176 if (extNetworkId != null) {
177 List<String> routerNamesAssociated = getRouterIdsForExtNetwork(extNetworkId);
178 if (routerNamesAssociated != null) {
179 for (String routerNameAssociated : routerNamesAssociated) {
180 if (!routerNameAssociated.equals(routerName)) {
181 Long routerIdAssociated = NatUtil.getVpnId(dataBroker,routerNameAssociated);
182 BigInteger naptDpn = NatUtil.getPrimaryNaptfromRouterId(dataBroker,routerIdAssociated);
183 if (naptDpn != null && naptDpn.equals(naptSwitch)) {
184 LOG.debug("Napt switch {} is also acting as primary for router {}",routerIdAssociated);
185 switchSharedByRouters = true;
190 if (!switchSharedByRouters) {
191 Long vpnId = getVpnIdForRouter(routerId);
192 if (vpnId != NatConstants.INVALID_ID) {
193 String naptFibflowRef = externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.NAPT_PFIB_TABLE, vpnId);
194 FlowEntity naptFibFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE,naptFibflowRef);
195 LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and vpnId {}",
196 NwConstants.NAPT_PFIB_TABLE, naptSwitch, vpnId);
197 mdsalManager.removeFlow(naptFibFlowEntity);
199 LOG.error("Invalid vpnId retrieved for routerId {}",routerId);
206 //Remove Fib entries,tables 20->44 ,36-> 44
207 String vpnName = getExtNetworkVpnName(routerId);
208 if (vpnName == null) {
209 LOG.debug("Vpn is not associated to externalN/w of router {}",routerName);
211 if (externalIpsLabel != null) {
212 for (String externalIp : externalIpsLabel.keySet()) {
213 Long label = externalIpsLabel.get(externalIp);
214 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerId, externalIp, vpnName,label);
215 LOG.debug("Successfully removed fib entries in old naptswitch {} for router {} and externalIps {} label {}",
216 naptSwitch, routerId,externalIp,label);
219 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
220 if (externalIps != null) {
221 Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
222 if (networkId != null) {
223 externalRouterListener.clearFibTsAndReverseTraffic(naptSwitch, routerId, networkId, externalIps, null);
224 LOG.debug("Successfully removed fib entries in old naptswitch {} for router {} with networkId {} and externalIps {}",
225 naptSwitch,routerId,networkId,externalIps);
227 LOG.debug("External network not associated to router {}", routerId);
230 LOG.debug("ExternalIps not found for router {}",routerName);
235 //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
236 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
237 if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
238 LOG.debug("No Internal Ip Port mapping associated to router {}, no flows need to be removed in" +
239 "oldNaptSwitch {}", routerId, naptSwitch);
242 BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
243 List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
244 for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
245 if (intextIpProtocolType.getIpPortMap() == null || intextIpProtocolType.getIpPortMap().isEmpty()) {
246 LOG.debug("No {} session associated to router {},no flows need to be removed in oldNaptSwitch {}",
247 intextIpProtocolType.getProtocol(),routerId,naptSwitch);
250 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
251 for(IpPortMap ipPortMap : ipPortMaps) {
252 String ipPortInternal = ipPortMap.getIpPortInternal();
253 String[] ipPortParts = ipPortInternal.split(":");
254 if(ipPortParts.length != 2) {
255 LOG.error("Unable to retrieve the Internal IP and port");
258 String internalIp = ipPortParts[0];
259 String internalPort = ipPortParts[1];
261 //Build and remove flow in outbound NAPT table
262 String switchFlowRef = NatUtil.getNaptFlowRef(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId),
263 internalIp, Integer.valueOf(internalPort));
264 FlowEntity outboundNaptFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
265 cookieSnatFlow, switchFlowRef);
267 LOG.info("Remove the flow in table {} for old napt switch with the DPN ID {} and router ID {}",
268 NwConstants.OUTBOUND_NAPT_TABLE,naptSwitch, routerId);
269 mdsalManager.removeFlow(outboundNaptFlowEntity);
271 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
272 if (ipPortExternal == null) {
273 LOG.debug("External Ipport mapping not found for internalIp {} with port {} for router", internalIp,
274 internalPort, routerId);
277 String externalIp = ipPortExternal.getIpAddress();
278 int externalPort = ipPortExternal.getPortNum();
280 //Build and remove flow in inbound NAPT table
281 switchFlowRef = NatUtil.getNaptFlowRef(naptSwitch, NwConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId),
282 externalIp, externalPort);
283 FlowEntity inboundNaptFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.INBOUND_NAPT_TABLE,
284 cookieSnatFlow, switchFlowRef);
286 LOG.info("Remove the flow in table {} for old napt switch with the DPN ID {} and router ID {}",
287 NwConstants.INBOUND_NAPT_TABLE,naptSwitch, routerId);
288 mdsalManager.removeFlow(inboundNaptFlowEntity);
294 private List<String> getRouterIdsForExtNetwork(Uuid extNetworkId) {
295 List<String> routerUuidsAsString = new ArrayList<>();
296 InstanceIdentifier<Networks> extNetwork = InstanceIdentifier.builder(ExternalNetworks.class).child
297 (Networks.class, new NetworksKey(extNetworkId)).build();
298 Optional<Networks> extNetworkData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, extNetwork);
299 if (extNetworkData.isPresent()) {
300 List<Uuid> routerUuids= extNetworkData.get().getRouterIds();
301 if (routerUuids != null){
302 for(Uuid routerUuid : routerUuids){
303 routerUuidsAsString.add(routerUuid.getValue());
307 return routerUuidsAsString;
310 public boolean isNaptSwitchDown(String routerName, BigInteger dpnId , BigInteger naptSwitch,Long routerVpnId,List<String> externalIpCache) {
311 externalIpsCache = externalIpCache;
312 if (!naptSwitch.equals(dpnId)) {
313 LOG.debug("DpnId {} is not a naptSwitch {} for Router {}",dpnId, naptSwitch, routerName);
316 LOG.debug("NaptSwitch {} is down for Router {}", naptSwitch, routerName);
317 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
318 if (routerId == NatConstants.INVALID_ID) {
319 LOG.error("Invalid routerId returned for routerName {}", routerName);
322 //elect a new NaptSwitch
323 naptSwitch = naptSwitchSelector.selectNewNAPTSwitch(routerName);
324 if (naptSwitch.equals(BigInteger.ZERO)) {
325 LOG.info("No napt switch is elected since all the switches for router {} are down",routerName);
326 boolean naptUpdatedStatus = updateNaptSwitch(routerName,naptSwitch);
327 if(!naptUpdatedStatus) {
328 LOG.debug("Failed to update naptSwitch {} for router {} in ds", naptSwitch,routerName);
331 if (externalIpsCache != null) {
332 String vpnName = getExtNetworkVpnName(routerId);
333 if (vpnName != null) {
334 //List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
335 //if (externalIps != null) {
336 for (String externalIp : externalIpsCache) {
337 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
340 LOG.debug("vpn is not associated to extn/w for router {}", routerName);
343 LOG.debug("No ExternalIps found for subnets under router {}, no bgp routes need to be cleared",routerName);
347 //checking elected switch health status
348 if (!getSwitchStatus(naptSwitch)) {
349 LOG.error("Newly elected Napt switch {} for router {} is down", naptSwitch, routerName);
352 LOG.debug("New NaptSwitch {} is up for Router {} and can proceed for flow installation",naptSwitch, routerName);
353 //update napt model for new napt switch
354 boolean naptUpdated = updateNaptSwitch(routerName, naptSwitch);
356 //update group of ordinary switch point to naptSwitch tunnel port
357 updateNaptSwitchBucketStatus(routerName, naptSwitch);
359 LOG.error("Failed to update naptSwitch model for newNaptSwitch {} for router {}",naptSwitch, routerName);
362 //update table26 forward packets to table46(outbound napt table)
363 FlowEntity flowEntity = buildSnatFlowEntityForNaptSwitch(naptSwitch, routerName, routerVpnId, NatConstants.ADD_FLOW);
364 if (flowEntity == null) {
365 LOG.debug("Failed to populate flowentity for router {} in naptSwitch {}", routerName, naptSwitch);
367 LOG.debug("Successfully installed flow in naptSwitch {} for router {}", naptSwitch, routerName);
368 mdsalManager.installFlow(flowEntity);
371 installSnatFlows(routerName,routerId,naptSwitch,routerVpnId);
373 boolean flowInstalledStatus = handleNatFlowsInNewNaptSwitch(routerId, dpnId, naptSwitch,routerVpnId);
374 if (flowInstalledStatus) {
375 LOG.debug("Installed all active session flows in newNaptSwitch {} for routerName {}", naptSwitch, routerName);
377 LOG.error("Failed to install flows in newNaptSwitch {} for routerId {}", naptSwitch, routerId);
380 //remove group in new naptswitch, coz this switch acted previously as ordinary switch
381 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
382 GroupEntity groupEntity = null;
384 groupEntity = MDSALUtil.buildGroupEntity(naptSwitch, groupId, routerName,
385 GroupTypes.GroupAll, null);
386 LOG.info("NAT Service : Removing NAPT Group in new naptSwitch {}", naptSwitch);
387 mdsalManager.removeGroup(groupEntity);
388 } catch (Exception ex) {
389 LOG.debug("NAT Service : Failed to remove group in new naptSwitch {} : {}",groupEntity,ex);
394 private String getExtNetworkVpnName(long routerId) {
395 Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
396 if(networkId == null) {
397 LOG.error("networkId is null for the router ID {}", routerId);
399 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
400 if (vpnName != null) {
401 LOG.debug("retrieved vpn name {} associated with ext nw {} in router {}",
402 vpnName,networkId,routerId);
405 LOG.error("No VPN associated with ext nw {} belonging to routerId {}",
406 networkId, routerId);
412 public void updateNaptSwitchBucketStatus(String routerName, BigInteger naptSwitch) {
413 LOG.debug("updateNaptSwitchBucketStatus method is called");
415 List<BigInteger> dpnList = naptSwitchSelector.getDpnsForVpn(routerName);
416 //List<BigInteger> dpnList = getDpnListForRouter(routerName);
417 if (dpnList == null || dpnList.isEmpty()) {
418 LOG.debug("No switches found for router {}",routerName);
421 for (BigInteger dpn : dpnList) {
422 if (!dpn.equals(naptSwitch)) {
423 LOG.debug("Updating SNAT_TABLE missentry for DpnId {} which is not naptSwitch for router {}",dpn,routerName);
424 List<BucketInfo> bucketInfoList = handleGroupInNeighborSwitches(dpn, routerName, naptSwitch);
425 if (bucketInfoList == null) {
426 LOG.debug("Failed to populate bucketInfo for orinaryswitch {} whose naptSwitch {} for router {} ",
427 dpn,naptSwitch,routerName);
430 modifySnatGroupEntry(dpn, bucketInfoList, routerName);
435 private boolean handleNatFlowsInNewNaptSwitch(Long routerId,BigInteger oldNaptSwitch, BigInteger newNaptSwitch,Long routerVpnId) {
436 LOG.debug("Proceeding to install flows in newNaptSwitch {} for routerId {}", newNaptSwitch,routerId);
437 IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker,routerId);
438 if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
439 LOG.debug("No Internal Ip Port mapping associated to router {}, no flows need to be installed in" +
440 "newNaptSwitch {}", routerId, newNaptSwitch);
444 Long vpnId = getVpnIdForRouter(routerId);
445 if (vpnId == NatConstants.INVALID_ID) {
446 LOG.error("Invalid vpnId for routerId {}",routerId);
450 if(routerId.equals(routerVpnId)) {
451 bgpVpnId = NatConstants.INVALID_ID;
453 bgpVpnId = routerVpnId;
455 LOG.debug("retrieved bgpVpnId {} for router {}",bgpVpnId,routerId);
456 for (IntextIpProtocolType protocolType : ipPortMapping.getIntextIpProtocolType()) {
457 if (protocolType.getIpPortMap() == null || protocolType.getIpPortMap().isEmpty()) {
458 LOG.debug("No {} session associated to router {}", protocolType.getProtocol(), routerId);
461 for (IpPortMap intIpPortMap : protocolType.getIpPortMap()) {
462 String internalIpAddress = intIpPortMap.getIpPortInternal().split(":")[0];
463 String intportnum = intIpPortMap.getIpPortInternal().split(":")[1];
465 //Get the external IP address and the port from the model
466 NAPTEntryEvent.Protocol proto = protocolType.getProtocol().toString().equals(ProtocolTypes.TCP.toString())
467 ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
468 IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
469 internalIpAddress, intportnum, proto);
470 if (ipPortExternal == null) {
471 LOG.debug("External Ipport mapping is not found for internalIp {} with port {}", internalIpAddress, intportnum);
474 String externalIpAddress = ipPortExternal.getIpAddress();
475 Integer extportNumber = ipPortExternal.getPortNum();
476 LOG.debug("ExternalIPport {}:{} mapping for internal ipport {}:{}",externalIpAddress,extportNumber,
477 internalIpAddress,intportnum);
479 SessionAddress sourceAddress = new SessionAddress(internalIpAddress,Integer.valueOf(intportnum));
480 SessionAddress externalAddress = new SessionAddress(externalIpAddress,extportNumber);
482 //checking naptSwitch status before installing flows
483 if(getSwitchStatus(newNaptSwitch)) {
484 //Install the flow in newNaptSwitch Outbound NAPT table.
486 NaptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
487 vpnId, routerId, bgpVpnId, sourceAddress, externalAddress, proto);
488 } catch (Exception ex) {
489 LOG.error("Failed to add flow in OUTBOUND_NAPT_TABLE for routerid {} dpnId {} ipport {}:{} proto {}" +
490 "extIpport {}:{} BgpVpnId {} - {}", routerId, newNaptSwitch, internalIpAddress
491 , intportnum, proto, externalAddress, extportNumber,bgpVpnId,ex);
494 LOG.debug("Successfully installed a flow in SecondarySwitch {} Outbound NAPT table for router {} " +
495 "ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}", newNaptSwitch,routerId, internalIpAddress
496 , intportnum, proto, externalAddress, extportNumber,bgpVpnId);
497 //Install the flow in newNaptSwitch Inbound NAPT table.
499 NaptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NwConstants.INBOUND_NAPT_TABLE,
500 vpnId, routerId, bgpVpnId, externalAddress, sourceAddress, proto);
501 } catch (Exception ex) {
502 LOG.error("Failed to add flow in INBOUND_NAPT_TABLE for routerid {} dpnId {} extIpport{}:{} proto {} " +
503 "ipport {}:{} BgpVpnId {}", routerId, newNaptSwitch, externalAddress, extportNumber, proto,
504 internalIpAddress, intportnum,bgpVpnId);
507 LOG.debug("Successfully installed a flow in SecondarySwitch {} Inbound NAPT table for router {} " +
508 "ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}", newNaptSwitch,routerId, internalIpAddress
509 , intportnum, proto, externalAddress, extportNumber,bgpVpnId);
512 LOG.error("NewNaptSwitch {} gone down while installing flows from oldNaptswitch {}",
513 newNaptSwitch,oldNaptSwitch);
521 private Long getVpnIdForRouter(Long routerId) {
524 Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
525 if (networkId == null) {
526 LOG.debug("network is not associated to router {}", routerId);
528 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
529 if (vpnUuid == null) {
530 LOG.debug("vpn is not associated for network {} in router {}", networkId, routerId);
532 Long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
534 LOG.debug("retrieved vpnId {} for router {}",vpnId,routerId);
537 LOG.debug("retrieved invalid vpn Id");
541 } catch (Exception ex){
542 LOG.debug("Exception while retrieving vpnId for router {} - {}", routerId, ex);
544 return NatConstants.INVALID_ID;
547 public boolean getSwitchStatus(BigInteger switchId){
548 NodeId nodeId = new NodeId("openflow:" + switchId);
549 LOG.debug("Querying switch with dpnId {} is up/down", nodeId);
550 InstanceIdentifier<Node> nodeInstanceId = InstanceIdentifier.builder(Nodes.class)
551 .child(Node.class, new NodeKey(nodeId)).build();
552 Optional<Node> nodeOptional = NatUtil.read(dataBroker,LogicalDatastoreType.OPERATIONAL,nodeInstanceId);
553 if (nodeOptional.isPresent()) {
554 LOG.debug("Switch {} is up", nodeId);
557 LOG.debug("Switch {} is down", nodeId);
561 public List<BucketInfo> handleGroupInPrimarySwitch() {
562 List<BucketInfo> listBucketInfo = new ArrayList<>();
563 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
564 listActionInfoPrimary.add(new ActionInfo(ActionType.nx_resubmit,
565 new String[]{String.valueOf(NwConstants.INTERNAL_TUNNEL_TABLE)}));
566 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
567 listBucketInfo.add(bucketPrimary);
568 return listBucketInfo;
571 public List<BucketInfo> handleGroupInNeighborSwitches(BigInteger dpnId, String routerName, BigInteger naptSwitch) {
572 List<BucketInfo> listBucketInfo = new ArrayList<>();
573 String ifNamePrimary;
574 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
575 if (routerId == NatConstants.INVALID_ID) {
576 LOG.error("Invalid routerId returned for routerName {}",routerName);
577 return listBucketInfo;
579 ifNamePrimary = getTunnelInterfaceName(dpnId, naptSwitch);
580 if (ifNamePrimary != null) {
581 LOG.debug("TunnelInterface {} between ordinary switch {} and naptSwitch {}",ifNamePrimary,dpnId,naptSwitch);
582 List<ActionInfo> listActionInfoPrimary = NatUtil.getEgressActionsForInterface(interfaceManager, ifNamePrimary, routerId);
583 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
584 listBucketInfo.add(bucketPrimary);
586 LOG.debug("No TunnelInterface between ordinary switch {} and naptSwitch {}",dpnId,naptSwitch);
588 return listBucketInfo;
591 protected void installSnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
592 GroupEntity groupEntity = null;
594 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
595 LOG.debug("install SnatMissEntry for groupId {} for dpnId {} for router {}", groupId, dpnId,routerName);
596 groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
597 GroupTypes.GroupAll, bucketInfo);
598 mdsalManager.installGroup(groupEntity);
599 LOG.debug("installed the SNAT to NAPT GroupEntity:{}", groupEntity);
600 } catch (Exception ex) {
601 LOG.error("Failed to install group for groupEntity {} : {}",groupEntity,ex);
605 private void modifySnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
606 installSnatGroupEntry(dpnId,bucketInfo,routerName);
607 LOG.debug("modified SnatMissEntry for dpnId {} of router {}",dpnId,routerName);
610 protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
611 Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
612 RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
615 Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager.getTunnelInterfaceName(
616 new GetTunnelInterfaceNameInputBuilder().setSourceDpid(srcDpId).setDestinationDpid(dstDpId)
617 .setTunnelType(tunType).build());
618 rpcResult = result.get();
619 if(!rpcResult.isSuccessful()) {
620 tunType = TunnelTypeGre.class;
621 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
622 .setSourceDpid(srcDpId)
623 .setDestinationDpid(dstDpId)
624 .setTunnelType(tunType)
626 rpcResult = result.get();
627 if(!rpcResult.isSuccessful()) {
628 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
630 return rpcResult.getResult().getInterfaceName();
632 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
634 return rpcResult.getResult().getInterfaceName();
636 } catch (InterruptedException | ExecutionException e) {
637 LOG.warn("Exception when getting tunnel interface Id for tunnel between {} and {} : {}",
638 srcDpId, dstDpId, e);
644 public boolean updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
645 RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().setKey(new RouterToNaptSwitchKey(routerName))
646 .setPrimarySwitchId(naptSwitchId).build();
648 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
649 NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
650 } catch (Exception ex) {
651 LOG.error("Failed to write naptSwitch {} for router {} in ds",
652 naptSwitchId,routerName);
655 LOG.debug("Successfully updated naptSwitch {} for router {} in ds",
656 naptSwitchId,routerName);
660 public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId, long routerVpnId, int addordel) {
662 FlowEntity flowEntity;
663 List<MatchInfo> matches = new ArrayList<MatchInfo>();
664 matches.add(new MatchInfo(MatchFieldType.eth_type,
665 new long[]{ 0x0800L }));
666 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
667 MetaDataUtil.getVpnIdMetadata(routerVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
669 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
671 if (addordel == NatConstants.ADD_FLOW) {
672 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
673 List<ActionInfo> actionsInfo = new ArrayList<ActionInfo>();
675 ActionInfo actionSetField = new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
676 BigInteger.valueOf(routerVpnId)}) ;
677 actionsInfo.add(actionSetField);
678 LOG.debug("Setting the tunnel to the list of action infos {}", actionsInfo);
679 actionsInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
680 instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfo));
682 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
683 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
684 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
686 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
687 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
688 NwConstants.COOKIE_SNAT_TABLE, matches, null);
693 public FlowEntity buildSnatFlowEntityForNaptSwitch(BigInteger dpId, String routerName, long routerVpnId, int addordel) {
695 FlowEntity flowEntity;
696 List<MatchInfo> matches = new ArrayList<>();
697 matches.add(new MatchInfo(MatchFieldType.eth_type,
698 new long[]{ 0x0800L }));
699 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
700 MetaDataUtil.getVpnIdMetadata(routerVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
702 String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
704 if (addordel == NatConstants.ADD_FLOW) {
705 List<InstructionInfo> instructions = new ArrayList<>();
707 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[]
708 { NwConstants.OUTBOUND_NAPT_TABLE }));
710 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
711 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
712 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
714 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
715 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
716 NwConstants.COOKIE_SNAT_TABLE, matches, null);
721 private String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
722 return new StringBuilder().append(NatConstants.SNAT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
723 append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
726 protected void installSnatFlows(String routerName,Long routerId,BigInteger naptSwitch,Long routerVpnId) {
728 if(routerId.equals(routerVpnId)) {
729 LOG.debug("Installing flows for router with internalvpnId");
730 //36 -> 46 ..Install flow forwarding packet to table46 from table36
731 LOG.debug("installTerminatingServiceTblEntry in naptswitch with dpnId {} for routerName {} with routerId {}",
732 naptSwitch, routerName,routerId);
733 externalRouterListener.installTerminatingServiceTblEntry(naptSwitch, routerName);
735 //Install default flows punting to controller in table 46(OutBoundNapt table)
736 LOG.debug("installOutboundMissEntry in naptswitch with dpnId {} for routerName {} with routerId {}",
737 naptSwitch, routerName, routerId);
738 externalRouterListener.createOutboundTblEntry(naptSwitch, routerId);
740 //Table 47 point to table 21 for inbound traffic
741 LOG.debug("installNaptPfibEntry in naptswitch with dpnId {} for router {}", naptSwitch, routerId);
742 externalRouterListener.installNaptPfibEntry(naptSwitch, routerId);
744 //36 -> 46 ..Install flow forwarding packet to table46 from table36
745 LOG.debug("installTerminatingServiceTblEntry in naptswitch with dpnId {} for routerName {} with BgpVpnId {}",
746 naptSwitch, routerName, routerVpnId);
747 externalRouterListener.installTerminatingServiceTblEntryWithUpdatedVpnId(naptSwitch, routerName, routerVpnId);
749 //Install default flows punting to controller in table 46(OutBoundNapt table)
750 LOG.debug("installOutboundMissEntry in naptswitch with dpnId {} for routerName {} with BgpVpnId {}",
751 naptSwitch, routerName, routerVpnId);
752 externalRouterListener.createOutboundTblEntryWithBgpVpn(naptSwitch, routerId, routerVpnId);
754 //Table 47 point to table 21 for inbound traffic
755 LOG.debug("installNaptPfibEntry in naptswitch with dpnId {} for router {} with BgpVpnId {}",
756 naptSwitch, routerId, routerVpnId);
757 externalRouterListener.installNaptPfibEntryWithBgpVpn(naptSwitch, routerId, routerVpnId);
760 String vpnName = getExtNetworkVpnName(routerId);
761 if(vpnName != null) {
762 //Table 47 point to table 21 for outbound traffic
763 long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
765 LOG.debug("installNaptPfibEntry fin naptswitch with dpnId {} for BgpVpnId {}", naptSwitch, vpnId);
766 externalRouterListener.installNaptPfibEntry(naptSwitch, vpnId);
768 LOG.debug("Associated BgpvpnId not found for router {}",routerId);
771 //Install Fib entries for ExternalIps & program 36 -> 44
772 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
773 if (externalIps != null) {
774 for (String externalIp : externalIps) {
775 LOG.debug("advToBgpAndInstallFibAndTsFlows in naptswitch id {} with vpnName {} and externalIp {}",
776 naptSwitch, vpnName, externalIp);
777 externalRouterListener.advToBgpAndInstallFibAndTsFlows(naptSwitch, NwConstants.INBOUND_NAPT_TABLE,
778 vpnName, routerId, externalIp, vpnService, fibService, bgpManager, dataBroker, LOG);
779 LOG.debug("Successfully added fib entries in naptswitch {} for router {} with external IP {}", naptSwitch,
780 routerId, externalIp);
783 LOG.debug("External Ip not found for routerId {}",routerId);
786 LOG.debug("Associated vpnName not found for router {}",routerId);
790 protected void bestEffortDeletion(long routerId,String routerName,HashMap<String,Long> externalIpLabel) {
791 List<String> newExternalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
792 if (newExternalIps != null && externalIpsCache != null) {
793 Set<String> originalSubnetIds = Sets.newHashSet(externalIpsCache);
794 Set<String> updatedSubnetIds = Sets.newHashSet(newExternalIps);
795 Sets.SetView<String> removeExternalIp = Sets.difference(originalSubnetIds, updatedSubnetIds);
796 if (removeExternalIp.isEmpty()) {
797 LOG.debug("No external Ip needed to be removed in bestEffortDeletion method for router {}",routerName);
800 String vpnName = getExtNetworkVpnName(routerId);
801 if (vpnName == null) {
802 LOG.debug("Vpn is not associated to externalN/w of router {}",routerName);
805 if (externalIpLabel == null || externalIpLabel.size() == 0) {
806 LOG.debug("ExternalIpLabel map is empty for router {}",routerName);
809 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
810 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
811 LOG.debug("No naptSwitch is selected for router {}", routerName);
815 for (String externalIp : removeExternalIp) {
816 if (externalIpLabel.containsKey(externalIp)) {
817 label = externalIpLabel.get(externalIp);
818 LOG.debug("Label {} for ExternalIp {} for router {}",label,externalIp,routerName);
820 LOG.debug("Label for ExternalIp {} is not found for router {}",externalIp,routerName);
823 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
824 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerId, externalIp, vpnName,label);
825 LOG.debug("Successfully removed fib entries in switch {} for router {} and externalIps {}",
826 naptSwitch, routerId, externalIp);
829 LOG.debug("No external IP found for router {}",routerId);