2 * Copyright (c) 2017 Red Hat, Inc. 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 static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
12 import java.math.BigInteger;
13 import java.time.Duration;
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.List;
17 import java.util.Objects;
18 import java.util.concurrent.ExecutionException;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
22 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
23 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
24 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
25 import org.opendaylight.genius.infra.Datastore.Configuration;
26 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
27 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
28 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
29 import org.opendaylight.genius.infra.TypedWriteTransaction;
30 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
31 import org.opendaylight.genius.mdsalutil.ActionInfo;
32 import org.opendaylight.genius.mdsalutil.BucketInfo;
33 import org.opendaylight.genius.mdsalutil.GroupEntity;
34 import org.opendaylight.genius.mdsalutil.InstructionInfo;
35 import org.opendaylight.genius.mdsalutil.MDSALUtil;
36 import org.opendaylight.genius.mdsalutil.MatchInfo;
37 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
38 import org.opendaylight.genius.mdsalutil.NWUtil;
39 import org.opendaylight.genius.mdsalutil.NwConstants;
40 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
41 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadMetadata;
42 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
43 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
44 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
45 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
46 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
47 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
48 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
49 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
50 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
51 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
52 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
53 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
54 import org.opendaylight.netvirt.natservice.api.SnatServiceListener;
55 import org.opendaylight.netvirt.natservice.ha.NatDataUtil;
56 import org.opendaylight.netvirt.vpnmanager.api.IVpnFootprintService;
57 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
58 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfacesBuilder;
59 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
60 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortData;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortDataBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
75 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
76 import org.slf4j.Logger;
77 import org.slf4j.LoggerFactory;
79 public abstract class AbstractSnatService implements SnatServiceListener {
80 private static final Logger LOG = LoggerFactory.getLogger(AbstractSnatService.class);
82 static final int LOAD_START = mostSignificantBit(MetaDataUtil.METADATA_MASK_SH_FLAG.intValue());
83 static final int LOAD_END = mostSignificantBit(MetaDataUtil.METADATA_MASK_VRFID.intValue() | MetaDataUtil
84 .METADATA_MASK_SH_FLAG.intValue());
86 protected final DataBroker dataBroker;
87 protected final ManagedNewTransactionRunner txRunner;
88 protected final IMdsalApiManager mdsalManager;
89 protected final IdManagerService idManager;
90 private final NAPTSwitchSelector naptSwitchSelector;
91 final ItmRpcService itmManager;
92 protected final OdlInterfaceRpcService odlInterfaceRpcService;
93 protected final IInterfaceManager interfaceManager;
94 final IVpnFootprintService vpnFootprintService;
95 protected final IFibManager fibManager;
96 private final NatDataUtil natDataUtil;
97 private final DataTreeEventCallbackRegistrar eventCallbacks;
99 AbstractSnatService(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
100 final ItmRpcService itmManager, final OdlInterfaceRpcService odlInterfaceRpcService,
101 final IdManagerService idManager, final NAPTSwitchSelector naptSwitchSelector,
102 final IInterfaceManager interfaceManager,
103 final IVpnFootprintService vpnFootprintService,
104 final IFibManager fibManager, final NatDataUtil natDataUtil,
105 final DataTreeEventCallbackRegistrar eventCallbacks) {
106 this.dataBroker = dataBroker;
107 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
108 this.mdsalManager = mdsalManager;
109 this.itmManager = itmManager;
110 this.interfaceManager = interfaceManager;
111 this.idManager = idManager;
112 this.naptSwitchSelector = naptSwitchSelector;
113 this.odlInterfaceRpcService = odlInterfaceRpcService;
114 this.vpnFootprintService = vpnFootprintService;
115 this.fibManager = fibManager;
116 this.natDataUtil = natDataUtil;
117 this.eventCallbacks = eventCallbacks;
120 protected DataBroker getDataBroker() {
125 public boolean addSnatAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
126 BigInteger primarySwitchId) {
127 LOG.info("addSnatAllSwitch : Handle Snat in all switches for router {}", routers.getRouterName());
128 String routerName = routers.getRouterName();
129 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
131 * Primary switch handled separately since the pseudo port created may
132 * not be present in the switch list on delete.
134 addSnat(confTx, routers, primarySwitchId, primarySwitchId);
135 for (BigInteger dpnId : switches) {
136 if (!Objects.equals(primarySwitchId, dpnId)) {
137 addSnat(confTx, routers, primarySwitchId, dpnId);
144 public boolean removeSnatAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
145 BigInteger primarySwitchId) throws ExecutionException, InterruptedException {
146 LOG.info("removeSnatAllSwitch : Handle Snat in all switches for router {}", routers.getRouterName());
147 String routerName = routers.getRouterName();
148 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
150 * Primary switch handled separately since the pseudo port created may
151 * not be present in the switch list on delete.
153 removeSnat(confTx, routers, primarySwitchId, primarySwitchId);
154 for (BigInteger dpnId : switches) {
155 if (!Objects.equals(primarySwitchId, dpnId)) {
156 removeSnat(confTx, routers, primarySwitchId, dpnId);
163 public boolean addSnat(TypedReadWriteTransaction<Configuration> confTx, Routers routers, BigInteger primarySwitchId,
166 // Handle non NAPT switches and NAPT switches separately
167 if (!dpnId.equals(primarySwitchId)) {
168 LOG.info("addSnat : Handle non NAPT switch {} for router {}", dpnId, routers.getRouterName());
169 addSnatCommonEntriesForNonNaptSwitch();
170 addSnatSpecificEntriesForNonNaptSwitch();
172 LOG.info("addSnat : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
173 addSnatCommonEntriesForNaptSwitch(confTx, routers, dpnId);
174 addSnatSpecificEntriesForNaptSwitch(confTx, routers, dpnId);
180 public boolean removeSnat(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
181 BigInteger primarySwitchId, BigInteger dpnId) throws ExecutionException, InterruptedException {
183 // Handle non NAPT switches and NAPT switches separately
184 if (!dpnId.equals(primarySwitchId)) {
185 LOG.info("removeSnat : Handle non NAPT switch {} for router {}", dpnId, routers.getRouterName());
186 removeSnatCommonEntriesForNonNaptSwitch();
187 removeSnatSpecificEntriesForNonNaptSwitch();
189 LOG.info("removeSnat : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
190 removeSnatCommonEntriesForNaptSwitch(confTx, routers, dpnId);
191 removeSnatSpecificEntriesForNaptSwitch(confTx, routers, dpnId);
198 public boolean addCentralizedRouterAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
199 BigInteger primarySwitchId) {
200 LOG.info("addCentralizedRouterAllSwitch : Handle Snat in all switches for router {}",
201 routers.getRouterName());
202 String routerName = routers.getRouterName();
203 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
204 addCentralizedRouter(confTx, routers, primarySwitchId, primarySwitchId);
205 for (BigInteger dpnId : switches) {
206 if (!Objects.equals(primarySwitchId, dpnId)) {
207 addCentralizedRouter(confTx, routers, primarySwitchId, dpnId);
214 public boolean removeCentralizedRouterAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
215 BigInteger primarySwitchId) throws ExecutionException, InterruptedException {
216 LOG.info("removeCentralizedRouterAllSwitch : Handle Snat in all switches for router {}",
217 routers.getRouterName());
218 boolean isLastRouterDelete = false;
219 isLastRouterDelete = NatUtil.isLastExternalRouter(routers.getNetworkId()
220 .getValue(), routers.getRouterName(), natDataUtil);
221 LOG.info("removeCentralizedRouterAllSwitch : action is delete for router {} and isLastRouterDelete is {}",
222 routers.getRouterName(), isLastRouterDelete);
223 removeCentralizedRouter(confTx, routers, primarySwitchId, primarySwitchId);
224 String routerName = routers.getRouterName();
225 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
226 for (BigInteger dpnId : switches) {
227 if (!Objects.equals(primarySwitchId, dpnId)) {
228 removeCentralizedRouter(confTx, routers, primarySwitchId, dpnId);
231 if (isLastRouterDelete) {
232 removeLearntIpPorts(routers);
233 removeMipAdjacencies(routers);
239 public boolean addCentralizedRouter(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
240 BigInteger primarySwitchId, BigInteger dpnId) {
241 if (!dpnId.equals(primarySwitchId)) {
242 LOG.info("addCentralizedRouter : Handle non NAPT switch {} for router {}",
243 dpnId, routers.getRouterName());
244 addCommonEntriesForNonNaptSwitch(confTx, routers, primarySwitchId, dpnId);
246 LOG.info("addCentralizedRouter : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
247 addCommonEntriesForNaptSwitch(confTx, routers, dpnId);
253 public boolean removeCentralizedRouter(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
254 BigInteger primarySwitchId, BigInteger dpnId) throws ExecutionException, InterruptedException {
255 if (!dpnId.equals(primarySwitchId)) {
256 LOG.info("removeCentralizedRouter : Handle non NAPT switch {} for router {}",
257 dpnId, routers.getRouterName());
258 removeCommonEntriesForNonNaptSwitch(confTx, routers, dpnId);
260 LOG.info("removeCentralizedRouter : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
261 removeCommonEntriesForNaptSwitch(confTx, routers, dpnId);
267 public boolean handleRouterUpdate(TypedReadWriteTransaction<Configuration> confTx,
268 Routers origRouter, Routers updatedRouter) throws ExecutionException, InterruptedException {
272 private void addCommonEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
274 String routerName = routers.getRouterName();
275 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
276 addDefaultFibRouteForSNAT(confTx, dpnId, routerId);
277 for (ExternalIps externalIp : routers.nonnullExternalIps()) {
278 if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
279 // In this class we handle only IPv4 use-cases.
282 //The logic now handle only one external IP per router, others if present will be ignored.
283 long extSubnetId = NatUtil.getExternalSubnetVpnId(dataBroker, externalIp.getSubnetId());
284 addInboundTerminatingServiceTblEntry(confTx, dpnId, routerId, extSubnetId);
285 addTerminatingServiceTblEntry(confTx, dpnId, routerId);
290 private void removeCommonEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
291 BigInteger dpnId) throws ExecutionException, InterruptedException {
292 String routerName = routers.getRouterName();
293 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
294 removeDefaultFibRouteForSNAT(confTx, dpnId, routerId);
295 for (ExternalIps externalIp : routers.nonnullExternalIps()) {
296 if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
297 // In this class we handle only IPv4 use-cases.
300 removeInboundTerminatingServiceTblEntry(confTx, dpnId, routerId);
301 removeTerminatingServiceTblEntry(confTx, dpnId, routerId);
306 private void addSnatCommonEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
308 String routerName = routers.getRouterName();
309 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
310 String externalGwMac = routers.getExtGwMacAddress();
311 for (ExternalIps externalIp : routers.nonnullExternalIps()) {
312 if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
313 // In this class we handle only IPv4 use-cases.
316 //The logic now handle only one external IP per router, others if present will be ignored.
317 long extSubnetId = NatUtil.getExternalSubnetVpnId(dataBroker, externalIp.getSubnetId());
318 addInboundFibEntry(confTx, dpnId, externalIp.getIpAddress(), routerId, extSubnetId,
319 routers.getNetworkId().getValue(), externalIp.getSubnetId().getValue(), externalGwMac);
324 private void removeSnatCommonEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
325 Routers routers, BigInteger dpnId) throws ExecutionException, InterruptedException {
326 String routerName = routers.getRouterName();
327 Long routerId = NatUtil.getVpnId(confTx, routerName);
328 for (ExternalIps externalIp : routers.nonnullExternalIps()) {
329 if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
330 // In this class we handle only IPv4 use-cases.
333 //The logic now handle only one external IP per router, others if present will be ignored.
334 removeInboundFibEntry(confTx, dpnId, externalIp.getIpAddress(), routerId,
335 externalIp.getSubnetId().getValue());
341 private void addCommonEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
342 BigInteger primarySwitchId, BigInteger dpnId) {
343 String routerName = routers.getRouterName();
344 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
345 addSnatMissEntry(confTx, dpnId, routerId, routerName, primarySwitchId);
346 addDefaultFibRouteForSNAT(confTx, dpnId, routerId);
349 private void removeCommonEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
350 BigInteger dpnId) throws ExecutionException, InterruptedException {
351 String routerName = routers.getRouterName();
352 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
353 removeSnatMissEntry(confTx, dpnId, routerId, routerName);
354 removeDefaultFibRouteForSNAT(confTx, dpnId, routerId);
357 private void addSnatCommonEntriesForNonNaptSwitch() {
358 /* Nothing to do here*/
361 private void removeSnatCommonEntriesForNonNaptSwitch() {
362 /* Nothing to do here*/
365 protected abstract void addSnatSpecificEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
366 Routers routers, BigInteger dpnId);
368 protected abstract void removeSnatSpecificEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
369 Routers routers, BigInteger dpnId) throws ExecutionException, InterruptedException;
371 protected abstract void addSnatSpecificEntriesForNonNaptSwitch();
373 protected abstract void removeSnatSpecificEntriesForNonNaptSwitch();
375 private void addInboundFibEntry(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId, String externalIp,
376 Long routerId, long extSubnetId, String externalNetId, String subNetId, String routerMac) {
378 List<MatchInfo> matches = new ArrayList<>();
379 matches.add(MatchEthernetType.IPV4);
380 if (extSubnetId == NatConstants.INVALID_ID) {
381 LOG.error("ConntrackBasedSnatService : installInboundFibEntry : external subnet id is invalid.");
384 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(extSubnetId),
385 MetaDataUtil.METADATA_MASK_VRFID));
386 matches.add(new MatchIpv4Destination(externalIp, "32"));
388 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
389 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
390 listActionInfo.add(new ActionNxResubmit(NwConstants.INBOUND_NAPT_TABLE));
391 instructionInfo.add(new InstructionApplyActions(listActionInfo));
393 String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, routerId);
394 flowRef = flowRef + "inbound" + externalIp;
395 NatUtil.addFlow(confTx, mdsalManager,dpnId, NwConstants.L3_FIB_TABLE, flowRef,
396 NatConstants.SNAT_FIB_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches,
398 String rd = NatUtil.getVpnRd(dataBroker, subNetId);
399 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
400 String ipPrefix = externalIp + "/32";
401 NatUtil.addPrefixToInterface(dataBroker, NatUtil.getVpnId(dataBroker, subNetId),
402 null, ipPrefix, externalNetId, dpnId, Prefixes.PrefixCue.Nat);
404 fibManager.addOrUpdateFibEntry(rd, routerMac, ipPrefix,
405 Collections.singletonList(nextHopIp), VrfEntry.EncapType.Mplsgre, extSubnetId,
406 0, null, externalNetId, RouteOrigin.STATIC, null);
409 private void removeInboundFibEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
410 String externalIp, Long routerId, String subNetId) throws ExecutionException, InterruptedException {
411 String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, routerId);
412 flowRef = flowRef + "inbound" + externalIp;
413 NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.L3_FIB_TABLE, flowRef);
414 String rd = NatUtil.getVpnRd(dataBroker, subNetId);
415 String ipPrefix = externalIp + "/32";
416 fibManager.removeFibEntry(rd, ipPrefix, confTx);
417 NatUtil.deletePrefixToInterface(dataBroker, NatUtil.getVpnId(dataBroker, subNetId), ipPrefix);
421 private void addTerminatingServiceTblEntry(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId,
423 LOG.info("addTerminatingServiceTblEntry : creating entry for Terminating Service Table "
424 + "for switch {}, routerId {}", dpnId, routerId);
425 List<MatchInfo> matches = new ArrayList<>();
426 matches.add(MatchEthernetType.IPV4);
427 matches.add(new MatchTunnelId(BigInteger.valueOf(routerId)));
429 List<ActionInfo> actionsInfos = new ArrayList<>();
430 ActionNxLoadMetadata actionLoadMeta = new ActionNxLoadMetadata(MetaDataUtil
431 .getVpnIdMetadata(routerId), LOAD_START, LOAD_END);
432 actionsInfos.add(actionLoadMeta);
433 actionsInfos.add(new ActionNxResubmit(NwConstants.PSNAT_TABLE));
434 List<InstructionInfo> instructions = new ArrayList<>();
435 instructions.add(new InstructionApplyActions(actionsInfos));
436 String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
437 NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
438 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
441 private void removeTerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
442 Long routerId) throws ExecutionException, InterruptedException {
443 LOG.info("removeTerminatingServiceTblEntry : creating entry for Terminating Service Table "
444 + "for switch {}, routerId {}", dpnId, routerId);
446 String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
447 NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef);
450 protected void addSnatMissEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
451 Long routerId, String routerName, BigInteger primarySwitchId) {
452 LOG.debug("installSnatMissEntry : Installing SNAT miss entry in switch {}", dpnId);
453 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
454 String ifNamePrimary = NatUtil.getTunnelInterfaceName(dpnId, primarySwitchId, itmManager);
455 List<BucketInfo> listBucketInfo = new ArrayList<>();
456 if (ifNamePrimary != null) {
457 LOG.debug("installSnatMissEntry : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
458 listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager,
459 interfaceManager, ifNamePrimary, routerId, true);
461 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
462 listBucketInfo.add(0, bucketPrimary);
463 LOG.debug("installSnatMissEntry : installSnatMissEntry called for dpnId {} with primaryBucket {} ", dpnId,
464 listBucketInfo.get(0));
465 // Install the select group
466 long groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME, getGroupIdKey(routerName));
467 if (groupId != NatConstants.INVALID_ID) {
468 GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll,
470 LOG.debug("installing the PSNAT to NAPTSwitch GroupEntity:{} with GroupId: {}", groupEntity, groupId);
471 mdsalManager.addGroup(confTx, groupEntity);
473 // Add the flow to send the packet to the group only after group is available in Config datastore
474 eventCallbacks.onAddOrUpdate(LogicalDatastoreType.CONFIGURATION,
475 NatUtil.getGroupInstanceId(dpnId, groupId), (unused, newGroupId) -> {
476 LOG.info("group {} is created in the config", groupId);
477 ListenableFutures.addErrorLogging(
478 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
479 innerConfTx -> addSnatMissFlowForGroup(innerConfTx, dpnId, routerId, groupId)),
480 LOG, "Error adding flow for the group {}",groupId);
481 return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
482 }, Duration.ofSeconds(5), iid -> LOG.error("groupId {} not found in config datastore", groupId));
484 LOG.error("installSnatMissEntry: Unable to get groupId for routerName:{}", routerName);
488 private void addSnatMissFlowForGroup(TypedReadWriteTransaction<Configuration> confTx,
489 BigInteger dpnId, Long routerId, long groupId) {
490 // Install miss entry pointing to group
491 LOG.debug("installSnatMissEntry : buildSnatFlowEntity is called for dpId {}, routerId {} and groupId {}",
492 dpnId, routerId, groupId);
493 List<MatchInfo> matches = new ArrayList<>();
494 matches.add(new MatchEthernetType(0x0800L));
495 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
498 List<ActionInfo> actionsInfo = new ArrayList<>();
499 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(routerId)));
500 LOG.debug("installSnatMissEntry : Setting the tunnel to the list of action infos {}", actionsInfo);
501 actionsInfo.add(new ActionGroup(groupId));
502 List<InstructionInfo> instructions = new ArrayList<>();
503 instructions.add(new InstructionApplyActions(actionsInfo));
504 String flowRef = getFlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
505 NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef,
506 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches,
510 protected void removeSnatMissEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
511 Long routerId, String routerName) throws ExecutionException, InterruptedException {
512 LOG.debug("removeSnatMissEntry : Removing SNAT miss entry from switch {}", dpnId);
513 // Install the select group
514 long groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME, getGroupIdKey(routerName));
515 if (groupId != NatConstants.INVALID_ID) {
516 LOG.debug("removeSnatMissEntry : removing the PSNAT to NAPTSwitch on DPN {} with GroupId: {}", dpnId,
518 mdsalManager.removeGroup(confTx, dpnId, groupId);
520 LOG.error("removeSnatMissEntry: Unable to get groupId for routerName:{}", routerName);
522 // Install miss entry pointing to group
523 LOG.debug("removeSnatMissEntry : buildSnatFlowEntity is called for dpId {}, routerName {} and groupId {}",
524 dpnId, routerName, groupId);
526 String flowRef = getFlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
527 NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef);
530 private void addInboundTerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx,
531 BigInteger dpnId, Long routerId, long extSubnetId) {
533 //Install the tunnel table entry in NAPT switch for inbound traffic to SNAT IP from a non a NAPT switch.
534 LOG.info("installInboundTerminatingServiceTblEntry : creating entry for Terminating Service Table "
535 + "for switch {}, routerId {}", dpnId, routerId);
536 List<MatchInfo> matches = new ArrayList<>();
537 matches.add(MatchEthernetType.IPV4);
538 List<ActionInfo> actionsInfos = new ArrayList<>();
539 if (extSubnetId == NatConstants.INVALID_ID) {
540 LOG.error("installInboundTerminatingServiceTblEntry : external subnet id is invalid.");
543 matches.add(new MatchTunnelId(BigInteger.valueOf(extSubnetId)));
544 ActionNxLoadMetadata actionLoadMeta = new ActionNxLoadMetadata(MetaDataUtil
545 .getVpnIdMetadata(extSubnetId), LOAD_START, LOAD_END);
546 actionsInfos.add(actionLoadMeta);
547 actionsInfos.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
548 List<InstructionInfo> instructions = new ArrayList<>();
549 instructions.add(new InstructionApplyActions(actionsInfos));
550 String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue()) + "INBOUND";
551 NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
552 NatConstants.SNAT_FIB_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
555 private void removeInboundTerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx,
556 BigInteger dpnId, Long routerId) throws ExecutionException, InterruptedException {
557 //Install the tunnel table entry in NAPT switch for inbound traffic to SNAT IP from a non a NAPT switch.
558 LOG.info("installInboundTerminatingServiceTblEntry : creating entry for Terminating Service Table "
559 + "for switch {}, routerId {}", dpnId, routerId);
560 String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue()) + "INBOUND";
561 NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef);
564 private void addDefaultFibRouteForSNAT(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
567 List<MatchInfo> matches = new ArrayList<>();
568 matches.add(MatchEthernetType.IPV4);
569 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(extNetId),
570 MetaDataUtil.METADATA_MASK_VRFID));
572 List<InstructionInfo> instructions = new ArrayList<>();
573 instructions.add(new InstructionGotoTable(NwConstants.PSNAT_TABLE));
575 String flowRef = "DefaultFibRouteForSNAT" + getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, extNetId);
576 NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.L3_FIB_TABLE, flowRef,
577 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches,
581 private void removeDefaultFibRouteForSNAT(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
582 Long extNetId) throws ExecutionException, InterruptedException {
583 String flowRef = "DefaultFibRouteForSNAT" + getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, extNetId);
584 NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.L3_FIB_TABLE, flowRef);
587 protected String getFlowRef(BigInteger dpnId, short tableId, long routerID) {
588 return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR
589 + tableId + NatConstants.FLOWID_SEPARATOR + routerID;
592 protected String getGroupIdKey(String routerName) {
593 return "snatmiss." + routerName;
596 private void removeMipAdjacencies(Routers routers) {
597 LOG.info("removeMipAdjacencies for router {}", routers.getRouterName());
598 String externalSubNetId = null;
599 for (ExternalIps externalIp : routers.nonnullExternalIps()) {
600 if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
601 // In this class we handle only IPv4 use-cases.
604 externalSubNetId = externalIp.getSubnetId().getValue();
607 if (externalSubNetId == null) {
608 LOG.info("removeMipAdjacencies no external Ipv4 address present on router {}",
609 routers.getRouterName());
612 InstanceIdentifier<VpnInterfaces> vpnInterfacesId =
613 InstanceIdentifier.builder(VpnInterfaces.class).build();
615 VpnInterfaces vpnInterfaces = SingleTransactionDataBroker.syncRead(dataBroker,
616 LogicalDatastoreType.CONFIGURATION, vpnInterfacesId);
617 List<VpnInterface> updatedVpnInterface = new ArrayList<>();
618 for (VpnInterface vpnInterface : vpnInterfaces.nonnullVpnInterface()) {
619 List<Adjacency> updatedAdjacencies = new ArrayList<>();
620 Adjacencies adjacencies = vpnInterface.augmentation(Adjacencies.class);
621 if (null != adjacencies) {
622 for (Adjacency adjacency : adjacencies.nonnullAdjacency()) {
623 if (!adjacency.getSubnetId().getValue().equals(externalSubNetId)) {
624 updatedAdjacencies.add(adjacency);
628 AdjacenciesBuilder adjacenciesBuilder = new AdjacenciesBuilder();
629 adjacenciesBuilder.setAdjacency(updatedAdjacencies);
630 VpnInterfaceBuilder vpnInterfaceBuilder = new VpnInterfaceBuilder(vpnInterface);
631 vpnInterfaceBuilder.addAugmentation(Adjacencies.class, adjacenciesBuilder.build());
632 updatedVpnInterface.add(vpnInterfaceBuilder.build());
634 VpnInterfacesBuilder vpnInterfacesBuilder = new VpnInterfacesBuilder();
635 vpnInterfacesBuilder.setVpnInterface(updatedVpnInterface);
637 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
638 vpnInterfacesId, vpnInterfacesBuilder.build());
639 } catch (ReadFailedException e) {
640 LOG.warn("Failed to read removeMipAdjacencies with error {}", e.getMessage());
641 } catch (TransactionCommitFailedException e) {
642 LOG.warn("Failed to remove removeMipAdjacencies with error {}", e.getMessage());
646 private void removeLearntIpPorts(Routers routers) {
647 LOG.info("removeLearntIpPorts for router {} and network {}", routers.getRouterName(), routers.getNetworkId());
648 String networkId = routers.getNetworkId().getValue();
649 LearntVpnVipToPortData learntVpnVipToPortData = NatUtil.getLearntVpnVipToPortData(dataBroker);
650 if (learntVpnVipToPortData == null) {
651 LOG.info("removeLearntIpPorts, no learned ports present");
654 LearntVpnVipToPortDataBuilder learntVpnVipToPortDataBuilder = new LearntVpnVipToPortDataBuilder();
655 List<LearntVpnVipToPort> learntVpnVipToPortList = new ArrayList<>();
656 for (LearntVpnVipToPort learntVpnVipToPort : learntVpnVipToPortData.nonnullLearntVpnVipToPort()) {
657 if (!networkId.equals(learntVpnVipToPort.getVpnName())) {
658 LOG.info("The learned port belongs to Vpn {} hence not removing", learntVpnVipToPort.getVpnName());
659 learntVpnVipToPortList.add(learntVpnVipToPort);
661 String externalSubNetId = null;
662 for (ExternalIps externalIp : routers.nonnullExternalIps()) {
663 if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
664 // In this class we handle only IPv4 use-cases.
667 externalSubNetId = externalIp.getSubnetId().getValue();
670 if (externalSubNetId == null) {
671 LOG.info("removeLearntIpPorts no external Ipv4 address present on router {}",
672 routers.getRouterName());
675 String prefix = learntVpnVipToPort.getPortFixedip() + "/32";
676 NatUtil.deletePrefixToInterface(dataBroker, NatUtil.getVpnId(dataBroker,
677 externalSubNetId), prefix);
682 learntVpnVipToPortDataBuilder.setLearntVpnVipToPort(learntVpnVipToPortList);
683 InstanceIdentifier<LearntVpnVipToPortData> learntVpnVipToPortDataId = NatUtil
684 .getLearntVpnVipToPortDataId();
685 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
686 learntVpnVipToPortDataId, learntVpnVipToPortDataBuilder.build());
688 } catch (TransactionCommitFailedException e) {
689 LOG.warn("Failed to remove removeLearntIpPorts with error {}", e.getMessage());
693 static int mostSignificantBit(int value) {
694 return 31 - Integer.numberOfLeadingZeros(value);