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 com.google.common.base.Optional;
11 import java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.List;
14 import org.apache.commons.lang3.tuple.ImmutablePair;
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
17 import org.opendaylight.genius.mdsalutil.ActionInfo;
18 import org.opendaylight.genius.mdsalutil.InstructionInfo;
19 import org.opendaylight.genius.mdsalutil.MatchInfo;
20 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
21 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
22 import org.opendaylight.genius.mdsalutil.NWUtil;
23 import org.opendaylight.genius.mdsalutil.NwConstants;
24 import org.opendaylight.genius.mdsalutil.actions.ActionNxConntrack;
25 import org.opendaylight.genius.mdsalutil.actions.ActionNxConntrack.NxCtAction;
26 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
27 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadMetadata;
28 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
29 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetSource;
30 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
31 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
32 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
33 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
34 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
35 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
36 import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchCtState;
37 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
38 import org.opendaylight.netvirt.vpnmanager.api.IVpnFootprintService;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.types.rev160517.IpPrefixOrAddress;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.NxActionNatFlags;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.NxActionNatRangePresent;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
53 public abstract class ConntrackBasedSnatService extends AbstractSnatService {
54 private static final Logger LOG = LoggerFactory.getLogger(ConntrackBasedSnatService.class);
56 protected static final int TRACKED_NEW_CT_STATE = 0x21;
57 protected static final int TRACKED_NEW_CT_MASK = 0x21;
58 protected static final int SNAT_CT_STATE = 0x40;
59 protected static final int SNAT_CT_STATE_MASK = 0x40;
60 protected static final int DNAT_CT_STATE = 0x80;
61 protected static final int DNAT_CT_STATE_MASK = 0x80;
63 public ConntrackBasedSnatService(DataBroker dataBroker, IMdsalApiManager mdsalManager, ItmRpcService itmManager,
64 IdManagerService idManager, NAPTSwitchSelector naptSwitchSelector,
65 OdlInterfaceRpcService odlInterfaceRpcService,
66 IInterfaceManager interfaceManager, IVpnFootprintService vpnFootprintService,
67 IFibManager fibManager) {
68 super(dataBroker, mdsalManager, itmManager, odlInterfaceRpcService, idManager, naptSwitchSelector,
69 interfaceManager, vpnFootprintService, fibManager);
73 protected void installSnatSpecificEntriesForNaptSwitch(Routers routers, BigInteger dpnId, int addOrRemove) {
74 LOG.info("installSnatSpecificEntriesForNaptSwitch: called for router {}",
75 routers.getRouterName());
76 String routerName = routers.getRouterName();
77 Long routerId = NatUtil.getVpnId(getDataBroker(), routerName);
78 int elanId = NatUtil.getElanInstanceByName(routers.getNetworkId().getValue(), getDataBroker())
79 .getElanTag().intValue();
80 /* Install Outbound NAT entries */
82 installSnatMissEntryForPrimrySwch(dpnId, routerId, elanId, addOrRemove);
83 installTerminatingServiceTblEntry(dpnId, routerId, elanId, addOrRemove);
85 String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(getDataBroker(), routerName);
86 createOutboundTblTrackEntry(dpnId, routerId, extGwMacAddress, addOrRemove);
87 for (ExternalIps externalIp : routers.getExternalIps()) {
88 if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
89 // In this class we handle only IPv4 use-cases.
92 //The logic now handle only one external IP per router, others if present will be ignored.
93 long extSubnetId = NatConstants.INVALID_ID;
94 if (addOrRemove == NwConstants.ADD_FLOW) {
95 extSubnetId = NatUtil.getExternalSubnetVpnId(getDataBroker(), externalIp.getSubnetId());
97 createOutboundTblEntry(dpnId, routerId, externalIp.getIpAddress(), elanId, extGwMacAddress, addOrRemove);
98 installNaptPfibFlow(routers, dpnId, routerId, extSubnetId, addOrRemove);
100 //Install Inbound NAT entries
101 installInboundEntry(dpnId, routerId, externalIp.getIpAddress(), elanId, extSubnetId, addOrRemove);
102 installNaptPfibEntry(dpnId, routerId, addOrRemove);
104 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp.getIpAddress());
105 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker, externalIp.getSubnetId());
106 if (externalSubnet.isPresent()) {
107 String externalVpn = externalIp.getSubnetId().getValue();
108 String vpnRd = NatUtil.getVpnRd(dataBroker, externalVpn);
109 vpnFootprintService.updateVpnToDpnMapping(dpnId, externalVpn, vpnRd, null /* interfaceName*/,
110 new ImmutablePair<>(IpAddresses.IpAddressSource.ExternalFixedIP, fibExternalIp),
111 addOrRemove == NwConstants.ADD_FLOW);
118 protected void installSnatSpecificEntriesForNonNaptSwitch(Routers routers, BigInteger dpnId, int addOrRemove) {
119 // Nothing to to do here.
123 protected void installSnatMissEntryForPrimrySwch(BigInteger dpnId, Long routerId, int elanId, int addOrRemove) {
124 LOG.info("installSnatSpecificEntriesForNaptSwitch : called for the primary NAPT switch dpnId {}", dpnId);
125 List<MatchInfo> matches = new ArrayList<>();
126 matches.add(MatchEthernetType.IPV4);
127 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
128 List<InstructionInfo> instructions = new ArrayList<>();
129 List<ActionInfo> actionsInfos = new ArrayList<>();
130 List<NxCtAction> ctActionsList = new ArrayList<>();
131 NxCtAction nxCtAction = new ActionNxConntrack.NxNat(0, 0, 0,null, null,0, 0);
132 ctActionsList.add(nxCtAction);
133 ActionNxConntrack actionNxConntrack = new ActionNxConntrack(0, 0, elanId,
134 NwConstants.OUTBOUND_NAPT_TABLE,ctActionsList);
136 actionsInfos.add(actionNxConntrack);
137 instructions.add(new InstructionApplyActions(actionsInfos));
139 String flowRef = getFlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
140 syncFlow(dpnId, NwConstants.PSNAT_TABLE, flowRef, NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef,
141 NwConstants.COOKIE_SNAT_TABLE, matches, instructions, addOrRemove);
144 protected void installTerminatingServiceTblEntry(BigInteger dpnId, Long routerId, int elanId, int addOrRemove) {
145 LOG.info("installTerminatingServiceTblEntry : creating entry for Terminating Service Table "
146 + "for switch {}, routerId {}", dpnId, routerId);
147 List<MatchInfo> matches = new ArrayList<>();
148 matches.add(MatchEthernetType.IPV4);
149 matches.add(new MatchTunnelId(BigInteger.valueOf(routerId)));
152 List<ActionInfo> actionsInfos = new ArrayList<>();
153 List<NxCtAction> ctActionsList = new ArrayList<>();
154 NxCtAction nxCtAction = new ActionNxConntrack.NxNat(0, 0, 0,null, null,0, 0);
155 ctActionsList.add(nxCtAction);
156 ActionNxConntrack actionNxConntrack = new ActionNxConntrack(0, 0, elanId, NwConstants
157 .OUTBOUND_NAPT_TABLE,ctActionsList);
158 ActionNxLoadMetadata actionLoadMeta = new ActionNxLoadMetadata(MetaDataUtil
159 .getVpnIdMetadata(routerId.longValue()), LOAD_START, LOAD_END);
160 actionsInfos.add(actionLoadMeta);
161 actionsInfos.add(actionNxConntrack);
162 List<InstructionInfo> instructions = new ArrayList<>();
163 instructions.add(new InstructionApplyActions(actionsInfos));
164 String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue());
165 syncFlow(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef, NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef,
166 NwConstants.COOKIE_SNAT_TABLE, matches, instructions, addOrRemove);
170 protected void createOutboundTblTrackEntry(BigInteger dpnId, Long routerId, String extGwMacAddress,
172 LOG.info("createOutboundTblTrackEntry : called for switch {}, routerId {}", dpnId, routerId);
173 List<MatchInfoBase> matches = new ArrayList<>();
174 matches.add(MatchEthernetType.IPV4);
175 matches.add(new NxMatchCtState(SNAT_CT_STATE, SNAT_CT_STATE_MASK));
176 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
177 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
178 if (addOrRemove == NwConstants.ADD_FLOW) {
179 listActionInfo.add(new ActionSetFieldEthernetSource(new MacAddress(extGwMacAddress)));
181 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
182 listActionInfo.add(new ActionNxResubmit(NwConstants.NAPT_PFIB_TABLE));
183 instructionInfo.add(new InstructionApplyActions(listActionInfo));
185 String flowRef = getFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
187 syncFlow(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef, NatConstants.SNAT_TRK_FLOW_PRIORITY, flowRef,
188 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo, addOrRemove);
192 protected void createOutboundTblEntry(BigInteger dpnId, long routerId, String externalIp,
193 int elanId, String extGwMacAddress, int addOrRemove) {
194 LOG.info("createOutboundTblEntry : dpId {} and routerId {}", dpnId, routerId);
195 List<MatchInfoBase> matches = new ArrayList<>();
196 matches.add(MatchEthernetType.IPV4);
197 matches.add(new NxMatchCtState(TRACKED_NEW_CT_STATE, TRACKED_NEW_CT_MASK));
198 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
199 List<ActionInfo> actionsInfos = new ArrayList<>();
200 if (addOrRemove == NwConstants.ADD_FLOW) {
201 actionsInfos.add(new ActionSetFieldEthernetSource(new MacAddress(extGwMacAddress)));
203 List<NxCtAction> ctActionsListCommit = new ArrayList<>();
204 int rangePresent = NxActionNatRangePresent.NXNATRANGEIPV4MIN.getIntValue();
205 int flags = NxActionNatFlags.NXNATFSRC.getIntValue();
206 NxCtAction nxCtActionCommit = new ActionNxConntrack.NxNat(0, flags, rangePresent,
207 new IpPrefixOrAddress(externalIp.toCharArray()).getIpAddress(),
209 ctActionsListCommit.add(nxCtActionCommit);
210 int ctCommitFlag = 1;
211 ActionNxConntrack actionNxConntrackSubmit = new ActionNxConntrack(ctCommitFlag, 0, elanId,
212 NwConstants.NAPT_PFIB_TABLE, ctActionsListCommit);
213 actionsInfos.add(actionNxConntrackSubmit);
214 List<InstructionInfo> instructions = new ArrayList<>();
215 instructions.add(new InstructionApplyActions(actionsInfos));
216 String flowRef = getFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
217 syncFlow(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef, NatConstants.SNAT_NEW_FLOW_PRIORITY,
218 flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions, addOrRemove);
221 protected void installNaptPfibFlow(Routers routers, BigInteger dpnId, long routerId,
222 long extSubnetId, int addOrRemove) {
223 Long extNetId = NatUtil.getVpnId(getDataBroker(), routers.getNetworkId().getValue());
224 LOG.info("installNaptPfibFlow : dpId {}, extNetId {}", dpnId, extNetId);
225 List<MatchInfoBase> matches = new ArrayList<>();
226 matches.add(MatchEthernetType.IPV4);
227 matches.add(new NxMatchCtState(SNAT_CT_STATE, SNAT_CT_STATE_MASK));
228 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
229 List<ActionInfo> listActionInfo = new ArrayList<>();
230 if (addOrRemove == NwConstants.ADD_FLOW) {
231 if (extSubnetId == NatConstants.INVALID_ID) {
232 LOG.error("installNaptPfibFlow : external subnet id is invalid.");
235 ActionNxLoadMetadata actionLoadMeta = new ActionNxLoadMetadata(MetaDataUtil
236 .getVpnIdMetadata(extSubnetId), LOAD_START, LOAD_END);
237 listActionInfo.add(actionLoadMeta);
239 ArrayList<InstructionInfo> instructions = new ArrayList<>();
240 listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
241 listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
242 instructions.add(new InstructionApplyActions(listActionInfo));
243 String flowRef = getFlowRef(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
244 flowRef = flowRef + "OUTBOUND";
245 syncFlow(dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef, NatConstants.SNAT_TRK_FLOW_PRIORITY,
246 flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions, addOrRemove);
249 protected void installInboundEntry(BigInteger dpnId, long routerId, String externalIp, int elanId, long extSubnetId,
251 LOG.info("installInboundEntry : dpId {} and routerId {}", dpnId, routerId);
252 List<MatchInfoBase> matches = new ArrayList<>();
253 matches.add(MatchEthernetType.IPV4);
254 matches.add(new MatchIpv4Destination(externalIp,"32"));
255 if (addOrRemove == NwConstants.ADD_FLOW) {
256 if (extSubnetId == NatConstants.INVALID_ID) {
257 LOG.error("installInboundEntry : external subnet id is invalid.");
260 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(extSubnetId),
261 MetaDataUtil.METADATA_MASK_VRFID));
263 List<ActionInfo> actionsInfos = new ArrayList<>();
264 List<NxCtAction> ctActionsList = new ArrayList<>();
265 NxCtAction nxCtAction = new ActionNxConntrack.NxNat(0, 0, 0,null, null,0, 0);
266 ActionNxLoadMetadata actionLoadMeta = new ActionNxLoadMetadata(MetaDataUtil
267 .getVpnIdMetadata(routerId), LOAD_START, LOAD_END);
268 actionsInfos.add(actionLoadMeta);
269 ctActionsList.add(nxCtAction);
270 ActionNxConntrack actionNxConntrack = new ActionNxConntrack(0, 0, elanId, NwConstants
271 .NAPT_PFIB_TABLE,ctActionsList);
273 actionsInfos.add(actionNxConntrack);
274 List<InstructionInfo> instructions = new ArrayList<>();
275 instructions.add(new InstructionApplyActions(actionsInfos));
276 String flowRef = getFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE, routerId);
277 flowRef = flowRef + "OUTBOUND";
278 syncFlow(dpnId, NwConstants.INBOUND_NAPT_TABLE, flowRef, NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef,
279 NwConstants.COOKIE_SNAT_TABLE, matches, instructions, addOrRemove);
282 protected void installNaptPfibEntry(BigInteger dpnId, long routerId, int addOrRemove) {
283 LOG.info("installNaptPfibEntry : called for dpnId {} and routerId {} ", dpnId, routerId);
284 List<MatchInfoBase> matches = new ArrayList<>();
285 matches.add(MatchEthernetType.IPV4);
286 matches.add(new NxMatchCtState(DNAT_CT_STATE, DNAT_CT_STATE_MASK));
287 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
289 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
290 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
291 listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
292 listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
293 instructionInfo.add(new InstructionApplyActions(listActionInfo));
296 String flowRef = getFlowRef(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
297 flowRef = flowRef + "INBOUND";
298 syncFlow(dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef, NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef,
299 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo, addOrRemove);