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.vpnservice.natservice.internal;
10 import com.google.common.base.Optional;
11 import org.opendaylight.bgpmanager.api.IBgpManager;
12 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
13 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
14 import org.opendaylight.vpnservice.mdsalutil.*;
15 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
16 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetFieldCase;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.FibRpcService;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetTunnelInterfaceNameInputBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetTunnelInterfaceNameOutput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.*;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.RoutersKey;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMapping;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
45 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;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.VpnRpcService;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.opendaylight.yangtools.yang.common.RpcResult;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
55 import java.math.BigInteger;
56 import java.util.ArrayList;
57 import java.util.List;
58 import java.util.concurrent.ExecutionException;
59 import java.util.concurrent.Future;
61 public class NaptSwitchHA {
62 private static final Logger LOG = LoggerFactory.getLogger(NaptSwitchHA.class);
63 private final DataBroker dataBroker;
64 private IMdsalApiManager mdsalManager;
65 private ItmRpcService itmManager;
66 private OdlInterfaceRpcService interfaceManager;
67 private IdManagerService idManager;
68 private NAPTSwitchSelector naptSwitchSelector;
69 private ExternalRoutersListener externalRouterListener;
70 private IBgpManager bgpManager;
71 private VpnRpcService vpnService;
72 private FibRpcService fibService;
74 public NaptSwitchHA(DataBroker broker,NAPTSwitchSelector selector){
76 naptSwitchSelector = selector;
79 public void setItmManager(ItmRpcService itmManager) {
80 this.itmManager = itmManager;
83 public void setMdsalManager(IMdsalApiManager mdsalManager) {
84 this.mdsalManager = mdsalManager;
87 public void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {
88 this.interfaceManager = interfaceManager;
91 public void setIdManager(IdManagerService idManager) {
92 this.idManager = idManager;
95 void setExternalRoutersListener(ExternalRoutersListener externalRoutersListener) {
96 this.externalRouterListener = externalRoutersListener;
99 public void setBgpManager(IBgpManager bgpManager) {
100 this.bgpManager = bgpManager;
103 public void setVpnService(VpnRpcService vpnService) {
104 this.vpnService = vpnService;
107 public void setFibService(FibRpcService fibService) {
108 this.fibService = fibService;
111 /* This method checks the switch that gone down is a NaptSwitch for a router.
112 If it is a NaptSwitch
113 1) selects new NAPT switch
114 2) installs nat flows in new NAPT switch
115 table 21(FIB)->26(PSNAT)->group(resubmit/napttunnel)->36(Terminating)->46(outbound)->47(resubmit)->21
116 3) modify the group and miss entry flow in other vSwitches pointing to newNaptSwitch
117 4) Remove nat flows in oldNaptSwitch
119 public void handleNaptSwitchDown(BigInteger dpnId){
121 LOG.debug("handleNaptSwitchDown method is called with dpnId {}",dpnId);
122 BigInteger naptSwitch;
124 NaptSwitches naptSwitches = NatUtil.getNaptSwitch(dataBroker);
125 if (naptSwitches == null || naptSwitches.getRouterToNaptSwitch() == null || naptSwitches.getRouterToNaptSwitch().isEmpty()) {
126 LOG.debug("NaptSwitchDown: NaptSwitch is not allocated for none of the routers");
129 for (RouterToNaptSwitch routerToNaptSwitch : naptSwitches.getRouterToNaptSwitch()) {
130 String routerName = routerToNaptSwitch.getRouterName();
131 naptSwitch = routerToNaptSwitch.getPrimarySwitchId();
132 boolean naptStatus = isNaptSwitchDown(routerName,dpnId,naptSwitch);
134 LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
137 removeSnatFlowsInOldNaptSwitch(routerName,naptSwitch);
141 } catch (Exception ex) {
142 LOG.error("Exception in handleNaptSwitchDown method {}",ex);
146 private void removeSnatFlowsInOldNaptSwitch(String routerName, BigInteger naptSwitch) {
147 //remove SNAT flows in old NAPT SWITCH
148 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
149 if (routerId == NatConstants.INVALID_ID) {
150 LOG.error("Invalid routerId returned for routerName {}",routerName);
153 BigInteger cookieSnatFlow = NatUtil.getCookieSnatFlow(routerId);
155 //Build and remove flows in outbound NAPT table
157 FlowEntity outboundNaptFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow);
158 mdsalManager.removeFlow(outboundNaptFlowEntity);
159 LOG.info("Removed all flows for router {} in the table {} for oldNaptswitch {}"
160 ,routerName, NatConstants.OUTBOUND_NAPT_TABLE, naptSwitch);
161 } catch (Exception ex) {
162 LOG.info("Failed to remove all flows for router {} in the table {} for oldNaptswitch {}"
163 ,routerName, NatConstants.OUTBOUND_NAPT_TABLE, naptSwitch);
166 //Build and remove flows in inbound NAPT table
168 FlowEntity inboundNaptFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.INBOUND_NAPT_TABLE,
170 mdsalManager.removeFlow(inboundNaptFlowEntity);
171 LOG.info("Removed all flows for router {} in the table {} for oldNaptswitch {}"
172 ,routerName, NatConstants.INBOUND_NAPT_TABLE, naptSwitch);
173 } catch (Exception ex) {
174 LOG.info("Failed to remove all flows for router {} in the table {} for oldNaptswitch {}"
175 ,routerName, NatConstants.INBOUND_NAPT_TABLE, naptSwitch);
178 //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table
179 String tsFlowRef = externalRouterListener.getFlowRefTs(naptSwitch, NatConstants.TERMINATING_SERVICE_TABLE, routerId);
180 FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.TERMINATING_SERVICE_TABLE, tsFlowRef);
182 LOG.info("Remove the flow in table {} for the active switch with the DPN ID {} and router ID {}"
183 ,NatConstants.TERMINATING_SERVICE_TABLE, naptSwitch, routerId);
184 mdsalManager.removeFlow(tsNatFlowEntity);
186 //Remove the Outbound flow entry which forwards the packet to Outbound NAPT Table
187 String outboundNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch, NatConstants.OUTBOUND_NAPT_TABLE, routerId);
188 FlowEntity outboundNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
189 NatConstants.OUTBOUND_NAPT_TABLE, outboundNatFlowRef);
190 LOG.info("Remove the flow in the for the active switch with the DPN ID {} and router ID {}"
191 ,NatConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
192 mdsalManager.removeFlow(outboundNatFlowEntity);
194 //Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table
195 String naptPFibflowRef = externalRouterListener.getFlowRefTs(naptSwitch, NatConstants.NAPT_PFIB_TABLE, routerId);
196 FlowEntity naptPFibFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.NAPT_PFIB_TABLE,naptPFibflowRef);
197 LOG.info("Remove the flow in the for the active switch with the DPN ID {} and router ID {}",
198 NatConstants.NAPT_PFIB_TABLE, naptSwitch, routerId);
199 mdsalManager.removeFlow(naptPFibFlowEntity);
201 //Remove Fib entries and 36-> 44
202 Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
203 if (networkId == null) {
204 LOG.debug("network is not associated to router {}", routerId);
206 Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
207 NatUtil.buildRouterIdentifier(routerName));
208 if(routerData.isPresent()){
209 List<String> externalIps = routerData.get().getExternalIps();
210 if (externalIps != null) {
211 externalRouterListener.advToBgpAndRemoveFibAndTsFlows(naptSwitch, routerId, networkId, externalIps);
212 LOG.debug("Successfully removed fib entries in naptswitch {} for router {} with external IP {}", naptSwitch,
213 routerId, externalIps);
215 LOG.debug("ExternalIps not found for router {} with networkId {}",routerName,networkId);
220 public boolean isNaptSwitchDown(String routerName, BigInteger dpnId , BigInteger naptSwitch) {
221 if (!naptSwitch.equals(dpnId)) {
222 LOG.debug("DpnId {} is not a naptSwitch {} for Router {}",dpnId, naptSwitch, routerName);
225 LOG.debug("NaptSwitch {} is down for Router {}", naptSwitch, routerName);
226 //elect a new NaptSwitch
227 naptSwitch = naptSwitchSelector.selectNewNAPTSwitch(routerName);
228 if (naptSwitch.equals("0")) {
229 LOG.info("No napt switch is elected since all the switches for router {} are down",routerName);
232 //checking elected switch health status
233 if (!getSwitchStatus(naptSwitch)) {
234 LOG.error("Newly elected Napt switch {} for router {} is down", naptSwitch, routerName);
237 LOG.debug("New NaptSwitch {} is up for Router {} and can proceed for flow installation",naptSwitch, routerName);
238 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
239 if (routerId == NatConstants.INVALID_ID) {
240 LOG.error("Invalid routerId returned for routerName {}", routerName);
243 //update napt model for new napt switch
244 boolean naptUpdated = updateNaptSwitch(routerName, naptSwitch);
246 //update group of naptswitch point to table36/ordinary switch point to naptswitchtunnelport
247 updateNaptSwitchBucketStatus(routerName, naptSwitch);
249 LOG.error("Failed to update naptSwitch model for newNaptSwitch {} for router {}",naptSwitch, routerName);
251 //36 -> 46 ..Install flow going to 46 from table36
252 externalRouterListener.installTerminatingServiceTblEntry(naptSwitch, routerName);
254 //Install default flows punting to controller in table 46(OutBoundNapt table)
255 externalRouterListener.installOutboundMissEntry(routerName, naptSwitch);
257 //Table 47 point to table 21 for inbound traffic
258 LOG.debug("installNaptPfibEntry for dpnId {} and routerId {}", naptSwitch, routerId);
259 externalRouterListener.installNaptPfibEntry(naptSwitch, routerId);
261 //Table 47 point to table 21 for outbound traffic
262 String vpnName = getVpnName(routerId);
263 if(vpnName != null) {
264 long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
266 LOG.debug("installNaptPfibEntry for dpnId {} and vpnId {}", naptSwitch, vpnId);
267 externalRouterListener.installNaptPfibEntry(naptSwitch, vpnId);
269 LOG.debug("Associated vpnId not found for router {}",routerId);
272 LOG.debug("Associated vpnName not found for router {}",routerId);
275 //Install Fib entries for ExternalIps & program 36 -> 44
277 Optional<IpMapping> ipMappingOptional = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
278 getIpMappingBuilder(routerId));
279 if (vpnName != null) {
280 if (ipMappingOptional.isPresent()) {
281 List<IpMap> ipMaps = ipMappingOptional.get().getIpMap();
282 for (IpMap ipMap : ipMaps) {
283 String externalIp = ipMap.getExternalIp();
284 LOG.debug("advToBgpAndInstallFibAndTsFlows for naptswitch {}, vpnName {} and externalIp {}",
285 naptSwitch, vpnName, externalIp);
286 externalRouterListener.advToBgpAndInstallFibAndTsFlows(naptSwitch, NatConstants.INBOUND_NAPT_TABLE,
287 vpnName, routerId, externalIp, vpnService, fibService, bgpManager, dataBroker, LOG);
288 LOG.debug("Successfully added fib entries in naptswitch {} for router {} with external IP {}", naptSwitch,
289 routerId, externalIp);
293 LOG.debug("Vpn is not associated to the network of router {}",routerName);
296 boolean flowInstalledStatus = handleFlowsInNewNaptSwitch(routerId, dpnId, naptSwitch);
297 if (flowInstalledStatus) {
298 LOG.debug("Installed all activesession flows in newNaptSwitch {} for routerName {}", routerName);
300 LOG.error("Failed to install flows in newNaptSwitch {} for routerId {}", naptSwitch, routerId);
305 private InstanceIdentifier<IpMapping> getIpMappingBuilder(Long routerId) {
306 InstanceIdentifier<IpMapping> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
307 .child(IpMapping.class, new IpMappingKey(routerId)).build();
311 private String getVpnName(long routerId) {
312 Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
313 if(networkId == null) {
314 LOG.error("networkId is null for the router ID {}", routerId);
316 final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
317 if (vpnName != null) {
318 LOG.debug("retreived vpnname {} associated with ext nw {} in router {}",
319 vpnName,networkId,routerId);
322 LOG.error("No VPN associated with ext nw {} belonging to routerId {}",
323 networkId, routerId);
329 public void updateNaptSwitchBucketStatus(String routerName, BigInteger naptSwitch) {
330 LOG.debug("updateNaptSwitchBucketStatus method is called");
332 List<BigInteger> dpnList = getDpnListForRouter(routerName);
333 for (BigInteger dpn : dpnList) {
334 if (dpn.equals(naptSwitch)) {
335 LOG.debug("Updating SNAT_TABLE missentry for DpnId {} which is naptSwitch for router {}",dpn,routerName);
336 List<BucketInfo> bucketInfoList = handleGroupInPrimarySwitch();
337 modifySnatGroupEntry(naptSwitch, bucketInfoList, routerName);
339 LOG.debug("Updating SNAT_TABLE missentry for DpnId {} which is not naptSwitch for router {}"
341 List<BucketInfo> bucketInfoList = handleGroupInNeighborSwitches(dpn, routerName, naptSwitch);
342 if (bucketInfoList == null) {
343 LOG.debug("bucketInfo is not populated for orinaryswitch {} whose naptSwitch {} with router {} ",
344 dpn,routerName,naptSwitch);
347 modifySnatGroupEntry(naptSwitch, bucketInfoList, routerName);
352 private boolean handleFlowsInNewNaptSwitch(Long routerId,BigInteger oldNaptSwitch, BigInteger newNaptSwitch) {
354 LOG.debug("Proceeding to install flows in newNaptSwitch {} for routerId {}", routerId);
355 IpPortMapping ipPortMapping = getIpPortMapping(routerId);
356 if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
357 LOG.debug("No Internal Ip Port mapping associated to router {}, no flows need to be installed in" +
358 "newNaptSwitch ", routerId, newNaptSwitch);
364 vpnId = getVpnIdForRouter(routerId);
365 }catch (Exception ex) {
366 LOG.error("Failed to retreive vpnID for router {} : {}", routerId,ex);
369 for (IntextIpProtocolType protocolType : ipPortMapping.getIntextIpProtocolType()) {
370 if (protocolType.getIpPortMap() == null || protocolType.getIpPortMap().isEmpty()) {
371 LOG.debug("No {} session associated to router {}", protocolType.getProtocol(), routerId);
374 for (IpPortMap intIpPortMap : protocolType.getIpPortMap()) {
375 String internalIpAddress = intIpPortMap.getIpPortInternal().split(":")[0];
376 String intportnum = intIpPortMap.getIpPortInternal().split(":")[1];
378 //Get the external IP address and the port from the model
379 NAPTEntryEvent.Protocol proto = protocolType.getProtocol().toString().equals(ProtocolTypes.TCP.toString())
380 ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
381 IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
382 internalIpAddress, intportnum, proto);
383 if (ipPortExternal == null) {
384 LOG.debug("External Ipport mapping is not found for internalIp {} with port {}", internalIpAddress, intportnum);
387 String externalIpAddress = ipPortExternal.getIpAddress();
388 Integer extportNumber = ipPortExternal.getPortNum();
389 LOG.debug("ExternalIPport {}:{} mapping for internal ipport {}:{}",externalIpAddress,extportNumber,
390 internalIpAddress,intportnum);
392 SessionAddress sourceAddress = new SessionAddress(internalIpAddress,Integer.valueOf(intportnum));
393 SessionAddress externalAddress = new SessionAddress(externalIpAddress,extportNumber);
395 //checking naptSwitch status before installing flows
396 if(getSwitchStatus(newNaptSwitch)) {
397 //Install the flow in newNaptSwitch Outbound NAPT table.
399 NaptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NatConstants.OUTBOUND_NAPT_TABLE,
400 vpnId, routerId, sourceAddress, externalAddress, proto);
401 } catch (Exception ex) {
402 LOG.error("Failed to add flow in OUTBOUND_NAPT_TABLE for routerid {} dpnId {} ipport {}:{} proto {}" +
403 "extIpport {}:{}", routerId, newNaptSwitch, internalIpAddress
404 , intportnum, proto, externalAddress, extportNumber);
407 LOG.debug("Succesfully installed a flow in SecondarySwitch {} Outbound NAPT table for router {} " +
408 "ipport {}:{} proto {} extIpport {}:{}", newNaptSwitch,routerId, internalIpAddress
409 , intportnum, proto, externalAddress, extportNumber);
410 //Install the flow in newNaptSwitch Inbound NAPT table.
412 NaptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NatConstants.INBOUND_NAPT_TABLE,
413 vpnId, routerId, externalAddress, sourceAddress, proto);
414 } catch (Exception ex) {
415 LOG.error("Failed to add flow in INBOUND_NAPT_TABLE for routerid {} dpnId {} extIpport{}:{} proto {} ipport {}:{}",
416 routerId, newNaptSwitch, externalAddress, extportNumber,
417 proto, internalIpAddress, intportnum);
420 LOG.debug("Succesfully installed a flow in SecondarySwitch {} Inbound NAPT table for router {} " +
421 "ipport {}:{} proto {} extIpport {}:{}", newNaptSwitch,routerId, internalIpAddress
422 , intportnum, proto, externalAddress, extportNumber);
425 LOG.error("NewNaptSwitch {} gone down while installing flows from oldNaptswitch {}",
426 newNaptSwitch,oldNaptSwitch);
434 private Long getVpnIdForRouter(Long routerId) {
437 Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
438 if (networkId == null) {
439 LOG.debug("network is not associated to router {}", routerId);
441 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
442 if (vpnUuid == null) {
443 LOG.debug("vpn is not associated for network {} in router {}", networkId, routerId);
445 Long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
447 LOG.debug("retrieved vpnId {} for router {}",vpnId,routerId);
450 LOG.debug("retrieved invalid vpn Id");
454 } catch (Exception ex){
455 LOG.debug("Exception while retreiving vpnId for router {} - {}", routerId, ex);
460 private List<BigInteger> getDpnListForRouter(String routerName) {
461 List<BigInteger> dpnList = new ArrayList<BigInteger>();
462 List<VpnToDpnList> vpnDpnList = NatUtil.getVpnToDpnList(dataBroker, routerName);
463 for (VpnToDpnList vpnToDpn : vpnDpnList) {
464 dpnList.add(vpnToDpn.getDpnId());
469 public boolean getSwitchStatus(BigInteger switchId){
470 NodeId nodeId = new NodeId("openflow:" + switchId);
471 LOG.debug("Querying switch with dpnId {} is up/down", nodeId);
472 InstanceIdentifier<Node> nodeInstanceId = InstanceIdentifier.builder(Nodes.class)
473 .child(Node.class, new NodeKey(nodeId)).build();
474 Optional<Node> nodeOptional = NatUtil.read(dataBroker,LogicalDatastoreType.OPERATIONAL,nodeInstanceId);
475 if (nodeOptional.isPresent()) {
476 LOG.debug("Switch {} is up", nodeId);
479 LOG.debug("Switch {} is down", nodeId);
483 public List<BucketInfo> handleGroupInPrimarySwitch() {
484 List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
485 List<ActionInfo> listActionInfoPrimary = new ArrayList<ActionInfo>();
486 listActionInfoPrimary.add(new ActionInfo(ActionType.nx_resubmit,
487 new String[]{String.valueOf(NatConstants.TERMINATING_SERVICE_TABLE)}));
488 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
489 listBucketInfo.add(bucketPrimary);
490 return listBucketInfo;
493 public List<BucketInfo> handleGroupInNeighborSwitches(BigInteger dpnId, String routerName, BigInteger naptSwitch) {
494 List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
495 String ifNamePrimary;
496 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
497 if (routerId == NatConstants.INVALID_ID) {
498 LOG.error("Invalid routerId returned for routerName {}",routerName);
499 return listBucketInfo;
501 ifNamePrimary = getTunnelInterfaceName(dpnId, naptSwitch);
502 if (ifNamePrimary != null) {
503 LOG.debug("TunnelInterface {} between ordinary switch {} and naptSwitch {}",ifNamePrimary,dpnId,naptSwitch);
504 List<ActionInfo> listActionInfoPrimary = getEgressActionsForInterface(ifNamePrimary, routerId);
505 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
506 listBucketInfo.add(bucketPrimary);
508 LOG.debug("No TunnelInterface between ordinary switch {} and naptSwitch {}",dpnId,naptSwitch);
510 return listBucketInfo;
513 protected void installSnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
514 GroupEntity groupEntity = null;
516 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
517 LOG.debug("install SnatMissEntry for groupId {} for dpnId {} for router {}", groupId, dpnId,routerName);
518 groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
519 GroupTypes.GroupAll, bucketInfo);
520 mdsalManager.installGroup(groupEntity);
521 LOG.debug("installed the SNAT to NAPT GroupEntity:{}", groupEntity);
522 } catch (Exception ex) {
523 LOG.error("Failed to install group for groupEntity {} : {}",groupEntity,ex);
527 private void modifySnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
528 installSnatGroupEntry(dpnId,bucketInfo,routerName);
529 LOG.debug("modified SnatMissEntry for dpnId {} of router {}",dpnId,routerName);
532 protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
534 Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager.getTunnelInterfaceName(
535 new GetTunnelInterfaceNameInputBuilder().setSourceDpid(srcDpId).setDestinationDpid(dstDpId).build());
536 RpcResult<GetTunnelInterfaceNameOutput> rpcResult = result.get();
537 if(!rpcResult.isSuccessful()) {
538 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
540 return rpcResult.getResult().getInterfaceName();
542 } catch (InterruptedException | ExecutionException e) {
543 LOG.warn("Exception when getting tunnel interface Id for tunnel between {} and {} : {}",
544 srcDpId, dstDpId, e);
550 protected List<ActionInfo> getEgressActionsForInterface(String ifName, long routerId) {
551 LOG.debug("getEgressActionsForInterface called for interface {}", ifName);
552 List<ActionInfo> listActionInfo = new ArrayList<ActionInfo>();
554 Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
555 interfaceManager.getEgressActionsForInterface(
556 new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).setTunnelKey(routerId).build());
557 RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
558 if(!rpcResult.isSuccessful()) {
559 LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}"
560 , ifName, rpcResult.getErrors());
562 List<Action> actions =
563 rpcResult.getResult().getAction();
564 for (Action action : actions) {
565 org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionClass = action.getAction();
566 if (actionClass instanceof OutputActionCase) {
567 listActionInfo.add(new ActionInfo(ActionType.output,
568 new String[] {((OutputActionCase)actionClass).getOutputAction()
569 .getOutputNodeConnector().getValue()}));
570 } else if (actionClass instanceof PushVlanActionCase) {
571 listActionInfo.add(new ActionInfo(ActionType.push_vlan, new String[] {}));
572 } else if (actionClass instanceof SetFieldCase) {
573 if (((SetFieldCase)actionClass).getSetField().getVlanMatch() != null) {
574 int vlanVid = ((SetFieldCase)actionClass).getSetField().getVlanMatch()
575 .getVlanId().getVlanId().getValue();
576 listActionInfo.add(new ActionInfo(ActionType.set_field_vlan_vid,
577 new String[] { Long.toString(vlanVid) }));
582 } catch (InterruptedException | ExecutionException e) {
583 LOG.warn("Exception when egress actions for interface {}", ifName, e);
585 return listActionInfo;
588 private IpPortMapping getIpPortMapping(Long routerId) {
589 Optional<IpPortMapping> ipPortMapData = NatUtil.read(this.dataBroker, LogicalDatastoreType.CONFIGURATION,
590 buildIpToPortMapIdentifier(routerId));
591 if (ipPortMapData.isPresent()) {
592 return ipPortMapData.get();
597 public boolean updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
598 RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().setKey(new RouterToNaptSwitchKey(routerName))
599 .setPrimarySwitchId(naptSwitchId).build();
601 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
602 NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
603 } catch (Exception ex) {
604 LOG.error("Failed to write naptSwitch {} for router {} in ds",
605 naptSwitchId,routerName);
608 LOG.debug("Successfully updated naptSwitch {} for router {} in ds",
609 naptSwitchId,routerName);
613 private InstanceIdentifier<IpPortMapping> buildIpToPortMapIdentifier(Long routerId) {
614 InstanceIdentifier<IpPortMapping> ipPortMapId = InstanceIdentifier.builder(IntextIpPortMap.class).child
615 (IpPortMapping.class, new IpPortMappingKey(routerId)).build();
619 public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId, int addordel) {
621 FlowEntity flowEntity = null;
622 long routerId = NatUtil.getVpnId(dataBroker, routerName);
623 if (routerId == NatConstants.INVALID_ID) {
624 LOG.error("Invalid routerId returned for routerName {}",routerName);
627 List<MatchInfo> matches = new ArrayList<MatchInfo>();
628 matches.add(new MatchInfo(MatchFieldType.eth_type,
629 new long[]{ 0x0800L }));
630 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
631 BigInteger.valueOf(routerId), MetaDataUtil.METADATA_MASK_VRFID }));
633 String flowRef = getFlowRefSnat(dpId, NatConstants.PSNAT_TABLE, routerName);
635 if (addordel == NatConstants.ADD_FLOW) {
636 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
637 List<ActionInfo> actionsInfo = new ArrayList<ActionInfo>();
639 ActionInfo actionSetField = new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
640 BigInteger.valueOf(routerId)}) ;
641 actionsInfo.add(actionSetField);
642 LOG.debug("Setting the tunnel to the list of action infos {}", actionsInfo);
643 actionsInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
644 instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfo));
646 flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
647 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
648 NatConstants.COOKIE_SNAT_TABLE, matches, instructions);
650 flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
651 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
652 NatConstants.COOKIE_SNAT_TABLE, matches, null);
657 private String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
658 return new StringBuilder().append(NatConstants.SNAT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
659 append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();