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 edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
11 import java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.Collections;
14 import java.util.List;
15 import java.util.Objects;
16 import java.util.concurrent.ExecutionException;
17 import java.util.concurrent.Future;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
21 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
22 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
23 import org.opendaylight.genius.infra.Datastore.Configuration;
24 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
25 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
26 import org.opendaylight.genius.infra.TransactionAdapter;
27 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
28 import org.opendaylight.genius.infra.TypedWriteTransaction;
29 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
30 import org.opendaylight.genius.mdsalutil.ActionInfo;
31 import org.opendaylight.genius.mdsalutil.BucketInfo;
32 import org.opendaylight.genius.mdsalutil.FlowEntity;
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.MatchInfoBase;
38 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
39 import org.opendaylight.genius.mdsalutil.NWUtil;
40 import org.opendaylight.genius.mdsalutil.NwConstants;
41 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
42 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadMetadata;
43 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
44 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
45 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
46 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
47 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
48 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
49 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
50 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
51 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
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.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortData;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortDataBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
84 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
85 import org.opendaylight.yangtools.yang.common.RpcResult;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
89 public abstract class AbstractSnatService implements SnatServiceListener {
90 private static final Logger LOG = LoggerFactory.getLogger(AbstractSnatService.class);
92 static final int LOAD_START = mostSignificantBit(MetaDataUtil.METADATA_MASK_SH_FLAG.intValue());
93 static final int LOAD_END = mostSignificantBit(MetaDataUtil.METADATA_MASK_VRFID.intValue() | MetaDataUtil
94 .METADATA_MASK_SH_FLAG.intValue());
96 protected final DataBroker dataBroker;
97 protected final ManagedNewTransactionRunner txRunner;
98 protected final IMdsalApiManager mdsalManager;
99 protected final IdManagerService idManager;
100 protected final NAPTSwitchSelector naptSwitchSelector;
101 protected final ItmRpcService itmManager;
102 protected final OdlInterfaceRpcService odlInterfaceRpcService;
103 protected final IInterfaceManager interfaceManager;
104 protected final IVpnFootprintService vpnFootprintService;
105 protected final IFibManager fibManager;
106 protected final NatDataUtil natDataUtil;
108 protected AbstractSnatService(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
109 final ItmRpcService itmManager, final OdlInterfaceRpcService odlInterfaceRpcService,
110 final IdManagerService idManager, final NAPTSwitchSelector naptSwitchSelector,
111 final IInterfaceManager interfaceManager,
112 final IVpnFootprintService vpnFootprintService,
113 final IFibManager fibManager, final NatDataUtil natDataUtil) {
114 this.dataBroker = dataBroker;
115 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
116 this.mdsalManager = mdsalManager;
117 this.itmManager = itmManager;
118 this.interfaceManager = interfaceManager;
119 this.idManager = idManager;
120 this.naptSwitchSelector = naptSwitchSelector;
121 this.odlInterfaceRpcService = odlInterfaceRpcService;
122 this.vpnFootprintService = vpnFootprintService;
123 this.fibManager = fibManager;
124 this.natDataUtil = natDataUtil;
127 protected DataBroker getDataBroker() {
132 LOG.info("{} init", getClass().getSimpleName());
135 public void close() {
136 LOG.debug("AbstractSnatService Closed");
140 public boolean addSnatAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
141 BigInteger primarySwitchId) {
142 LOG.info("handleSnatAllSwitch : Handle Snat in all switches for router {}", routers.getRouterName());
143 String routerName = routers.getRouterName();
144 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
146 * Primary switch handled separately since the pseudo port created may
147 * not be present in the switch list on delete.
149 addSnat(confTx, routers, primarySwitchId, primarySwitchId);
150 for (BigInteger dpnId : switches) {
151 if (!Objects.equals(primarySwitchId, dpnId)) {
152 addSnat(confTx, routers, primarySwitchId, dpnId);
159 public boolean removeSnatAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
160 BigInteger primarySwitchId) {
161 LOG.info("handleSnatAllSwitch : Handle Snat in all switches for router {}", routers.getRouterName());
162 String routerName = routers.getRouterName();
163 List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
165 * Primary switch handled separately since the pseudo port created may
166 * not be present in the switch list on delete.
168 boolean isLastRouterDelete =
169 NatUtil.isLastExternalRouter(routers.getNetworkId().getValue(), routers.getRouterName(), natDataUtil);
170 LOG.info("handleSnatAllSwitch : action is delete for router {} and isLastRouterDelete is {}",
171 routers.getRouterName(), isLastRouterDelete);
172 removeSnat(confTx, routers, primarySwitchId, primarySwitchId);
173 for (BigInteger dpnId : switches) {
174 if (!Objects.equals(primarySwitchId, dpnId)) {
175 removeSnat(confTx, routers, primarySwitchId, dpnId);
178 if (isLastRouterDelete) {
179 removeLearntIpPorts(routers);
180 removeMipAdjacencies(routers);
186 public boolean addSnat(TypedReadWriteTransaction<Configuration> confTx, Routers routers, BigInteger primarySwitchId,
189 // Handle non NAPT switches and NAPT switches separately
190 if (!dpnId.equals(primarySwitchId)) {
191 LOG.info("handleSnat : Handle non NAPT switch {} for router {}", dpnId, routers.getRouterName());
192 addSnatCommonEntriesForNonNaptSwitch(confTx, routers, primarySwitchId, dpnId);
193 addSnatSpecificEntriesForNonNaptSwitch(confTx, routers, dpnId);
195 LOG.info("handleSnat : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
196 addSnatCommonEntriesForNaptSwitch(confTx, routers, dpnId);
197 addSnatSpecificEntriesForNaptSwitch(confTx, routers, dpnId);
203 public boolean removeSnat(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
204 BigInteger primarySwitchId, BigInteger dpnId) {
206 // Handle non NAPT switches and NAPT switches separately
207 if (!dpnId.equals(primarySwitchId)) {
208 LOG.info("handleSnat : Handle non NAPT switch {} for router {}", dpnId, routers.getRouterName());
209 removeSnatCommonEntriesForNonNaptSwitch(confTx, routers, dpnId);
210 removeSnatSpecificEntriesForNonNaptSwitch(confTx, routers, dpnId);
212 LOG.info("handleSnat : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
213 removeSnatCommonEntriesForNaptSwitch(confTx, routers, dpnId);
214 removeSnatSpecificEntriesForNaptSwitch(confTx, routers, dpnId);
220 protected void addSnatCommonEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
222 String routerName = routers.getRouterName();
223 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
224 addDefaultFibRouteForSNAT(confTx, dpnId, routerId);
225 String externalGwMac = routers.getExtGwMacAddress();
226 for (ExternalIps externalIp : routers.getExternalIps()) {
227 if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
228 // In this class we handle only IPv4 use-cases.
231 //The logic now handle only one external IP per router, others if present will be ignored.
232 long extSubnetId = NatUtil.getExternalSubnetVpnId(dataBroker, externalIp.getSubnetId());
233 addInboundFibEntry(confTx, dpnId, externalIp.getIpAddress(), routerId, extSubnetId,
234 routers.getNetworkId().getValue(), externalIp.getSubnetId().getValue(), externalGwMac);
235 addInboundTerminatingServiceTblEntry(confTx, dpnId, routerId, extSubnetId);
240 protected void removeSnatCommonEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
241 Routers routers, BigInteger dpnId) {
242 String routerName = routers.getRouterName();
243 Long routerId = NatUtil.getVpnId(confTx, routerName);
244 removeDefaultFibRouteForSNAT(confTx, dpnId, routerId);
245 for (ExternalIps externalIp : routers.getExternalIps()) {
246 if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
247 // In this class we handle only IPv4 use-cases.
250 //The logic now handle only one external IP per router, others if present will be ignored.
251 removeInboundFibEntry(confTx, dpnId, externalIp.getIpAddress(), routerId,
252 externalIp.getSubnetId().getValue());
253 removeInboundTerminatingServiceTblEntry(confTx, dpnId, routerId);
258 protected void addSnatCommonEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
259 Routers routers, BigInteger primarySwitchId, BigInteger dpnId) {
260 String routerName = routers.getRouterName();
261 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
262 addDefaultFibRouteForSNAT(confTx, dpnId, routerId);
263 addSnatMissEntry(confTx, dpnId, routerId, routerName, primarySwitchId);
266 protected void removeSnatCommonEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
267 Routers routers, BigInteger dpnId) {
268 String routerName = routers.getRouterName();
269 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
270 removeDefaultFibRouteForSNAT(confTx, dpnId, routerId);
271 removeSnatMissEntry(confTx, dpnId, routerId, routerName);
274 protected abstract void addSnatSpecificEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
275 Routers routers, BigInteger dpnId);
277 protected abstract void removeSnatSpecificEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
278 Routers routers, BigInteger dpnId);
280 protected abstract void addSnatSpecificEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
281 Routers routers, BigInteger dpnId);
283 protected abstract void removeSnatSpecificEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
284 Routers routers, BigInteger dpnId);
286 protected void addInboundFibEntry(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId, String externalIp,
287 Long routerId, long extSubnetId, String externalNetId, String subNetId, String routerMac) {
289 List<MatchInfo> matches = new ArrayList<>();
290 matches.add(MatchEthernetType.IPV4);
291 if (extSubnetId == NatConstants.INVALID_ID) {
292 LOG.error("ConntrackBasedSnatService : installInboundFibEntry : external subnet id is invalid.");
295 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(extSubnetId),
296 MetaDataUtil.METADATA_MASK_VRFID));
297 matches.add(new MatchIpv4Destination(externalIp, "32"));
299 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
300 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
301 listActionInfo.add(new ActionNxResubmit(NwConstants.INBOUND_NAPT_TABLE));
302 instructionInfo.add(new InstructionApplyActions(listActionInfo));
304 String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, routerId);
305 flowRef = flowRef + "inbound" + externalIp;
306 addFlow(confTx, dpnId, NwConstants.L3_FIB_TABLE, flowRef, NatConstants.SNAT_FIB_FLOW_PRIORITY, flowRef,
307 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
308 String rd = NatUtil.getVpnRd(dataBroker, subNetId);
309 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
310 String ipPrefix = externalIp + "/32";
311 NatUtil.addPrefixToInterface(dataBroker, NatUtil.getVpnId(dataBroker, subNetId),
312 null, ipPrefix, dpnId, new Uuid(subNetId), Prefixes.PrefixCue.Nat);
314 fibManager.addOrUpdateFibEntry(rd, routerMac, ipPrefix,
315 Collections.singletonList(nextHopIp), VrfEntry.EncapType.Mplsgre, extSubnetId,
316 0, null, externalNetId, RouteOrigin.STATIC, null);
319 protected void removeInboundFibEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
320 String externalIp, Long routerId, String subNetId) {
322 String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, routerId);
323 flowRef = flowRef + "inbound" + externalIp;
324 removeFlow(confTx, dpnId, NwConstants.L3_FIB_TABLE, flowRef);
325 String rd = NatUtil.getVpnRd(dataBroker, subNetId);
326 String ipPrefix = externalIp + "/32";
327 fibManager.removeFibEntry(rd, ipPrefix, TransactionAdapter.toWriteTransaction(confTx));
328 NatUtil.deletePrefixToInterface(dataBroker, NatUtil.getVpnId(dataBroker, subNetId), ipPrefix);
331 protected void addSnatMissEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
332 Long routerId, String routerName, BigInteger primarySwitchId) {
333 LOG.debug("installSnatMissEntry : Installing SNAT miss entry in switch {}", dpnId);
334 List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
335 String ifNamePrimary = getTunnelInterfaceName(dpnId, primarySwitchId);
336 List<BucketInfo> listBucketInfo = new ArrayList<>();
337 if (ifNamePrimary != null) {
338 LOG.debug("installSnatMissEntry : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
339 listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager,
340 interfaceManager, ifNamePrimary, routerId, true);
342 BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
343 listBucketInfo.add(0, bucketPrimary);
344 LOG.debug("installSnatMissEntry : installSnatMissEntry called for dpnId {} with primaryBucket {} ", dpnId,
345 listBucketInfo.get(0));
346 // Install the select group
347 long groupId = createGroupId(getGroupIdKey(routerName));
349 GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll,
351 LOG.debug("installing the PSNAT to NAPTSwitch GroupEntity:{} with GroupId: {}", groupEntity, groupId);
352 mdsalManager.addGroup(confTx, groupEntity);
354 // Install miss entry pointing to group
355 LOG.debug("installSnatMissEntry : buildSnatFlowEntity is called for dpId {}, routerName {} and groupId {}",
356 dpnId, routerName, groupId);
357 List<MatchInfo> matches = new ArrayList<>();
358 matches.add(new MatchEthernetType(0x0800L));
359 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
362 List<ActionInfo> actionsInfo = new ArrayList<>();
363 actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(routerId)));
364 LOG.debug("installSnatMissEntry : Setting the tunnel to the list of action infos {}", actionsInfo);
365 actionsInfo.add(new ActionGroup(groupId));
366 List<InstructionInfo> instructions = new ArrayList<>();
367 instructions.add(new InstructionApplyActions(actionsInfo));
368 String flowRef = getFlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
369 addFlow(confTx, dpnId, NwConstants.PSNAT_TABLE, flowRef, NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef,
370 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
373 // TODO skitt Fix the exception handling here
374 @SuppressWarnings("checkstyle:IllegalCatch")
375 @SuppressFBWarnings("REC_CATCH_EXCEPTION")
376 protected void removeSnatMissEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
377 Long routerId, String routerName) {
378 LOG.debug("installSnatMissEntry : Removing SNAT miss entry from switch {}", dpnId);
379 // Install the select group
380 long groupId = createGroupId(getGroupIdKey(routerName));
382 LOG.debug("removing the PSNAT to NAPTSwitch on DPN {} with GroupId: {}", dpnId, groupId);
384 mdsalManager.removeGroup(confTx, dpnId, groupId);
385 } catch (Exception e) {
386 LOG.error("Error removing flow", e);
387 throw new RuntimeException("Error removing flow", e);
390 // Install miss entry pointing to group
391 LOG.debug("installSnatMissEntry : buildSnatFlowEntity is called for dpId {}, routerName {} and groupId {}",
392 dpnId, routerName, groupId);
394 String flowRef = getFlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
395 removeFlow(confTx, dpnId, NwConstants.PSNAT_TABLE, flowRef);
398 protected void addInboundTerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx,
399 BigInteger dpnId, Long routerId, long extSubnetId) {
401 //Install the tunnel table entry in NAPT switch for inbound traffic to SNAP IP from a non a NAPT switch.
402 LOG.info("installInboundTerminatingServiceTblEntry : creating entry for Terminating Service Table "
403 + "for switch {}, routerId {}", dpnId, routerId);
404 List<MatchInfo> matches = new ArrayList<>();
405 matches.add(MatchEthernetType.IPV4);
406 List<ActionInfo> actionsInfos = new ArrayList<>();
407 if (extSubnetId == NatConstants.INVALID_ID) {
408 LOG.error("installInboundTerminatingServiceTblEntry : external subnet id is invalid.");
411 matches.add(new MatchTunnelId(BigInteger.valueOf(extSubnetId)));
412 ActionNxLoadMetadata actionLoadMeta = new ActionNxLoadMetadata(MetaDataUtil
413 .getVpnIdMetadata(extSubnetId), LOAD_START, LOAD_END);
414 actionsInfos.add(actionLoadMeta);
415 actionsInfos.add(new ActionNxResubmit(NwConstants.INBOUND_NAPT_TABLE));
416 List<InstructionInfo> instructions = new ArrayList<>();
417 instructions.add(new InstructionApplyActions(actionsInfos));
418 String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue()) + "INBOUND";
419 addFlow(confTx, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef, NatConstants.SNAT_FIB_FLOW_PRIORITY, flowRef,
420 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
423 protected void removeInboundTerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx,
424 BigInteger dpnId, Long routerId) {
426 //Install the tunnel table entry in NAPT switch for inbound traffic to SNAP IP from a non a NAPT switch.
427 LOG.info("installInboundTerminatingServiceTblEntry : creating entry for Terminating Service Table "
428 + "for switch {}, routerId {}", dpnId, routerId);
429 String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue()) + "INBOUND";
430 removeFlow(confTx, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef);
433 protected void addDefaultFibRouteForSNAT(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
436 List<MatchInfo> matches = new ArrayList<>();
437 matches.add(MatchEthernetType.IPV4);
438 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(extNetId),
439 MetaDataUtil.METADATA_MASK_VRFID));
441 List<InstructionInfo> instructions = new ArrayList<>();
442 instructions.add(new InstructionGotoTable(NwConstants.PSNAT_TABLE));
444 String flowRef = "DefaultFibRouteForSNAT" + getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, extNetId);
445 addFlow(confTx, dpnId, NwConstants.L3_FIB_TABLE, flowRef, NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef,
446 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
449 protected void removeDefaultFibRouteForSNAT(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
452 String flowRef = "DefaultFibRouteForSNAT" + getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, extNetId);
453 removeFlow(confTx, dpnId, NwConstants.L3_FIB_TABLE, flowRef);
456 protected String getFlowRef(BigInteger dpnId, short tableId, long routerID) {
457 return new StringBuilder().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId).append(NatConstants
458 .FLOWID_SEPARATOR).append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
461 protected void syncFlow(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpId, short tableId,
462 String flowId, int priority, String flowName, BigInteger cookie, List<? extends MatchInfoBase> matches,
463 List<InstructionInfo> instructions, int addOrRemove) {
464 if (addOrRemove == NwConstants.DEL_FLOW) {
465 removeFlow(confTx, dpId, tableId, flowId);
467 addFlow(confTx, dpId, tableId, flowId, priority, flowName, cookie, matches, instructions);
471 protected void addFlow(TypedWriteTransaction<Configuration> confTx, BigInteger dpId, short tableId,
472 String flowId, int priority, String flowName, BigInteger cookie, List<? extends MatchInfoBase> matches,
473 List<InstructionInfo> instructions) {
474 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, flowId, priority, flowName,
475 NatConstants.DEFAULT_IDLE_TIMEOUT, NatConstants.DEFAULT_IDLE_TIMEOUT, cookie, matches,
477 LOG.trace("syncFlow : Installing DpnId {}, flowId {}", dpId, flowId);
478 mdsalManager.addFlow(confTx, flowEntity);
481 // TODO skitt Fix the exception handling here
482 @SuppressWarnings("checkstyle:IllegalCatch")
483 @SuppressFBWarnings("REC_CATCH_EXCEPTION")
484 protected void removeFlow(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpId, short tableId,
486 LOG.trace("syncFlow : Removing Acl Flow DpnId {}, flowId {}", dpId, flowId);
488 mdsalManager.removeFlow(confTx, dpId, flowId, tableId);
489 } catch (Exception e) {
490 LOG.error("Error removing flow", e);
491 throw new RuntimeException("Error removing flow", e);
495 protected long createGroupId(String groupIdKey) {
496 AllocateIdInput getIdInput = new AllocateIdInputBuilder()
497 .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
500 Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
501 RpcResult<AllocateIdOutput> rpcResult = result.get();
502 return rpcResult.getResult().getIdValue();
503 } catch (NullPointerException | InterruptedException | ExecutionException e) {
504 LOG.error("createGroupId: Exception while creating group with key : {}",groupIdKey, e);
509 protected String getGroupIdKey(String routerName) {
510 return "snatmiss." + routerName;
513 protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
514 Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
515 RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
517 Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager
518 .getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder().setSourceDpid(srcDpId)
519 .setDestinationDpid(dstDpId).setTunnelType(tunType).build());
520 rpcResult = result.get();
521 if (!rpcResult.isSuccessful()) {
522 tunType = TunnelTypeGre.class ;
523 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
524 .setSourceDpid(srcDpId)
525 .setDestinationDpid(dstDpId)
526 .setTunnelType(tunType)
528 rpcResult = result.get();
529 if (!rpcResult.isSuccessful()) {
530 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
531 rpcResult.getErrors());
533 return rpcResult.getResult().getInterfaceName();
535 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
536 rpcResult.getErrors());
538 return rpcResult.getResult().getInterfaceName();
540 } catch (InterruptedException | ExecutionException | NullPointerException e) {
541 LOG.error("getTunnelInterfaceName : Exception when getting tunnel interface Id for tunnel "
542 + "between {} and {}", srcDpId, dstDpId);
547 protected void removeMipAdjacencies(Routers routers) {
548 LOG.info("removeMipAdjacencies for router {}", routers.getRouterName());
549 String externalSubNetId = null;
550 for (ExternalIps externalIp : routers.getExternalIps()) {
551 if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
552 // In this class we handle only IPv4 use-cases.
555 externalSubNetId = externalIp.getSubnetId().getValue();
558 if (externalSubNetId == null) {
559 LOG.info("removeMipAdjacencies no external Ipv4 address present on router {}",
560 routers.getRouterName());
563 InstanceIdentifier<VpnInterfaces> vpnInterfacesId =
564 InstanceIdentifier.builder(VpnInterfaces.class).build();
566 VpnInterfaces vpnInterfaces = SingleTransactionDataBroker.syncRead(dataBroker,
567 LogicalDatastoreType.CONFIGURATION, vpnInterfacesId);
568 List<VpnInterface> updatedVpnInterface = new ArrayList<>();
569 for (VpnInterface vpnInterface : vpnInterfaces.getVpnInterface()) {
570 List<Adjacency> updatedAdjacencies = new ArrayList<>();
571 Adjacencies adjacencies = vpnInterface.augmentation(Adjacencies.class);
572 if (null != adjacencies) {
573 for (Adjacency adjacency : adjacencies.getAdjacency()) {
574 if (!adjacency.getSubnetId().getValue().equals(externalSubNetId)) {
575 updatedAdjacencies.add(adjacency);
579 AdjacenciesBuilder adjacenciesBuilder = new AdjacenciesBuilder();
580 adjacenciesBuilder.setAdjacency(updatedAdjacencies);
581 VpnInterfaceBuilder vpnInterfaceBuilder = new VpnInterfaceBuilder(vpnInterface);
582 vpnInterfaceBuilder.addAugmentation(Adjacencies.class, adjacenciesBuilder.build());
583 updatedVpnInterface.add(vpnInterfaceBuilder.build());
585 VpnInterfacesBuilder vpnInterfacesBuilder = new VpnInterfacesBuilder();
586 vpnInterfacesBuilder.setVpnInterface(updatedVpnInterface);
588 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
589 vpnInterfacesId, vpnInterfacesBuilder.build());
590 } catch (ReadFailedException e) {
591 LOG.warn("Failed to read removeMipAdjacencies with error {}", e.getMessage());
592 } catch (TransactionCommitFailedException e) {
593 LOG.warn("Failed to remove removeMipAdjacencies with error {}", e.getMessage());
597 private void removeLearntIpPorts(Routers routers) {
598 LOG.info("removeLearntIpPorts for router {} and network {}", routers.getRouterName(), routers.getNetworkId());
599 String networkId = routers.getNetworkId().getValue();
600 LearntVpnVipToPortData learntVpnVipToPortData = NatUtil.getLearntVpnVipToPortData(dataBroker);
601 if (learntVpnVipToPortData == null) {
602 LOG.info("removeLearntIpPorts, no learned ports present");
605 LearntVpnVipToPortDataBuilder learntVpnVipToPortDataBuilder = new LearntVpnVipToPortDataBuilder();
606 List<LearntVpnVipToPort> learntVpnVipToPortList = new ArrayList<>();
607 for (LearntVpnVipToPort learntVpnVipToPort : learntVpnVipToPortData.getLearntVpnVipToPort()) {
608 if (!learntVpnVipToPort.getVpnName().equals(networkId)) {
609 LOG.info("The learned port belongs to Vpn {} hence not removing", learntVpnVipToPort.getVpnName());
610 learntVpnVipToPortList.add(learntVpnVipToPort);
612 String externalSubNetId = null;
613 for (ExternalIps externalIp : routers.getExternalIps()) {
614 if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
615 // In this class we handle only IPv4 use-cases.
618 externalSubNetId = externalIp.getSubnetId().getValue();
621 if (externalSubNetId == null) {
622 LOG.info("removeLearntIpPorts no external Ipv4 address present on router {}",
623 routers.getRouterName());
626 String prefix = learntVpnVipToPort.getPortFixedip() + "/32";
627 NatUtil.deletePrefixToInterface(dataBroker, NatUtil.getVpnId(dataBroker,
628 externalSubNetId), prefix);
633 learntVpnVipToPortDataBuilder.setLearntVpnVipToPort(learntVpnVipToPortList);
634 InstanceIdentifier<LearntVpnVipToPortData> learntVpnVipToPortDataId = NatUtil
635 .getLearntVpnVipToPortDataId();
636 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
637 learntVpnVipToPortDataId, learntVpnVipToPortDataBuilder.build());
639 } catch (TransactionCommitFailedException e) {
640 LOG.warn("Failed to remove removeLearntIpPorts with error {}", e.getMessage());
644 static int mostSignificantBit(int value) {
645 return 31 - Integer.numberOfLeadingZeros(value);