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 java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.List;
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.genius.mdsalutil.ActionInfo;
16 import org.opendaylight.genius.mdsalutil.InstructionInfo;
17 import org.opendaylight.genius.mdsalutil.MatchInfo;
18 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
19 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
20 import org.opendaylight.genius.mdsalutil.NwConstants;
21 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
22 import org.opendaylight.genius.mdsalutil.actions.ActionNxConntrack;
23 import org.opendaylight.genius.mdsalutil.actions.ActionNxConntrack.NxCtAction;
24 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
25 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldMeta;
26 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
27 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
28 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
29 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
30 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Source;
31 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
32 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
33 import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchCtState;
34 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.types.rev160517.IpPrefixOrAddress;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.NxActionNatFlags;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.NxActionNatRangePresent;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
50 public class ConntrackBasedSnatService extends AbstractSnatService {
52 protected final int trackedNewCtState = 0x21;
53 protected final int trackedNewCtMask = 0x21;
54 protected final int snatCtState = 0x40;
55 protected final int snatCtStateMask = 0x40;
56 protected final int dnatCtState = 0x80;
57 protected final int dnatCtStateMask = 0x80;
58 private static final Logger LOG = LoggerFactory.getLogger(ConntrackBasedSnatService.class);
60 public ConntrackBasedSnatService(DataBroker dataBroker, IMdsalApiManager mdsalManager, ItmRpcService itmManager,
61 OdlInterfaceRpcService interfaceManager, IdManagerService idManager, NaptManager naptManager,
62 NAPTSwitchSelector naptSwitchSelector, IVpnManager vpnManager) {
63 super(dataBroker, mdsalManager, itmManager, interfaceManager, idManager, naptManager, naptSwitchSelector,
68 protected void installSnatSpecificEntriesForNaptSwitch(Routers routers, BigInteger dpnId, int addOrRemove) {
69 LOG.info("ConntrackBasedSnatService: installSnatSpecificEntriesForNaptSwitch for router {}",
70 routers.getRouterName());
71 String routerName = routers.getRouterName();
72 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
73 int elanId = NatUtil.getElanInstanceByName(routers.getNetworkId().getValue(), dataBroker)
74 .getElanTag().intValue();
75 /* Install Outbound NAT entries */
77 installSnatMissEntryForPrimrySwch(dpnId, routerId, elanId, addOrRemove);
78 installTerminatingServiceTblEntry(dpnId, routerId, elanId, addOrRemove);
79 Long extNetId = NatUtil.getVpnId(dataBroker, routers.getNetworkId().getValue());
80 List<ExternalIps> externalIps = routers.getExternalIps();
81 createOutboundTblTrackEntry(dpnId, routerId, extNetId,addOrRemove);
82 createOutboundTblEntry(dpnId, routerId, extNetId, externalIps, elanId, addOrRemove);
83 installNaptPfibExternalOutputFlow(routers, dpnId, externalIps, addOrRemove);
85 //Install Inbound NAT entries
87 installInboundEntry(dpnId, routerId, extNetId, externalIps, elanId, addOrRemove);
88 installNaptPfibEntry(dpnId, routerId, addOrRemove);
93 protected void installSnatSpecificEntriesForNonNaptSwitch(Routers routers, BigInteger dpnId, int addOrRemove) {
94 // Nothing to to do here.
98 protected void installSnatMissEntryForPrimrySwch(BigInteger dpnId, Long routerId, int elanId, int addOrRemove) {
99 LOG.info("ConntrackBasedSnatService : installSnatMissEntryForPrimrySwch for for the primary"
100 + " NAPT switch dpnId {} ", dpnId);
101 List<MatchInfo> matches = new ArrayList<>();
102 matches.add(MatchEthernetType.IPV4);
103 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
104 List<InstructionInfo> instructions = new ArrayList<>();
105 List<ActionInfo> actionsInfos = new ArrayList<>();
106 List<NxCtAction> ctActionsList = new ArrayList<>();
107 NxCtAction nxCtAction = new ActionNxConntrack.NxNat(0, 0, 0,null, null,0, 0);
108 ctActionsList.add(nxCtAction);
109 ActionNxConntrack actionNxConntrack = new ActionNxConntrack(0, 0, elanId,
110 NwConstants.OUTBOUND_NAPT_TABLE,ctActionsList);
112 actionsInfos.add(actionNxConntrack);
113 instructions.add(new InstructionApplyActions(actionsInfos));
115 String flowRef = getFlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId);
116 syncFlow(dpnId, NwConstants.PSNAT_TABLE, flowRef, NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef,
117 NwConstants.COOKIE_SNAT_TABLE, matches, instructions, addOrRemove);
120 protected void installTerminatingServiceTblEntry(BigInteger dpnId, Long routerId, int elanId, int addOrRemove) {
121 LOG.info("ConntrackBasedSnatService : creating entry for Terminating Service Table for switch {}, routerId {}",
123 List<MatchInfo> matches = new ArrayList<>();
124 matches.add(MatchEthernetType.IPV4);
125 matches.add(new MatchTunnelId(BigInteger.valueOf(routerId)));
128 List<ActionInfo> actionsInfos = new ArrayList<>();
129 List<NxCtAction> ctActionsList = new ArrayList<>();
130 NxCtAction nxCtAction = new ActionNxConntrack.NxNat(0, 0, 0,null, null,0, 0);
131 ctActionsList.add(nxCtAction);
132 ActionNxConntrack actionNxConntrack = new ActionNxConntrack(0, 0, elanId, NwConstants
133 .OUTBOUND_NAPT_TABLE,ctActionsList);
134 ActionSetFieldMeta actionSetFieldMeta = new ActionSetFieldMeta(MetaDataUtil
135 .getVpnIdMetadata(routerId.longValue()));
136 actionsInfos.add(actionSetFieldMeta);
137 actionsInfos.add(actionNxConntrack);
138 List<InstructionInfo> instructions = new ArrayList<>();
139 instructions.add(new InstructionApplyActions(actionsInfos));
140 String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue());
141 syncFlow(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef, NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef,
142 NwConstants.COOKIE_SNAT_TABLE, matches, instructions, addOrRemove);
146 protected void createOutboundTblTrackEntry(BigInteger dpnId, Long routerId, long extNetId, int addOrRemove) {
147 LOG.info("ConntrackBasedSnatService : createOutboundTblTrackEntry for switch {}, routerId {}",
149 List<MatchInfoBase> matches = new ArrayList<>();
150 matches.add(MatchEthernetType.IPV4);
151 matches.add(new NxMatchCtState(snatCtState, snatCtStateMask));
152 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
153 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
154 ActionSetFieldMeta actionSetFieldMeta = new ActionSetFieldMeta(MetaDataUtil
155 .getVpnIdMetadata(extNetId));
156 listActionInfo.add(actionSetFieldMeta);
157 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
158 listActionInfo.add(new ActionNxResubmit(NwConstants.NAPT_PFIB_TABLE));
159 instructionInfo.add(new InstructionApplyActions(listActionInfo));
161 String flowRef = getFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
163 syncFlow(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef, NatConstants.SNAT_TRK_FLOW_PRIORITY, flowRef,
164 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo, addOrRemove);
168 protected void createOutboundTblEntry(BigInteger dpnId, long routerId, long extNetId, List<ExternalIps> externalIps,
169 int elanId, int addOrRemove) {
170 LOG.info("ConntrackBasedSnatService : createOutboundTblEntry dpId {} and routerId {}",
172 List<MatchInfoBase> matches = new ArrayList<>();
173 matches.add(MatchEthernetType.IPV4);
174 matches.add(new NxMatchCtState(trackedNewCtState, trackedNewCtMask));
175 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
176 List<ActionInfo> actionsInfos = new ArrayList<>();
177 ActionSetFieldMeta actionSetFieldMeta = new ActionSetFieldMeta(MetaDataUtil
178 .getVpnIdMetadata(extNetId));
179 actionsInfos.add(actionSetFieldMeta);
180 List<NxCtAction> ctActionsListCommit = new ArrayList<>();
181 if (externalIps.isEmpty()) {
182 LOG.error("ConntrackBasedSnatService : createOutboundTblEntry no externalIP present for routerId {}",
186 //The logic now handle only one external IP per router, others if present will be ignored.
187 String externalIp = externalIps.get(0).getIpAddress();
188 int rangePresent = NxActionNatRangePresent.NXNATRANGEIPV4MIN.getIntValue();
189 int flags = NxActionNatFlags.NXNATFSRC.getIntValue();
190 NxCtAction nxCtActionCommit = new ActionNxConntrack.NxNat(0, flags, rangePresent,
191 new IpPrefixOrAddress(externalIp.toCharArray()).getIpAddress(),
193 ctActionsListCommit.add(nxCtActionCommit);
194 int ctCommitFlag = 1;
195 ActionNxConntrack actionNxConntrackSubmit = new ActionNxConntrack(ctCommitFlag, 0, elanId,
196 NwConstants.NAPT_PFIB_TABLE, ctActionsListCommit);
197 actionsInfos.add(actionNxConntrackSubmit);
198 List<InstructionInfo> instructions = new ArrayList<>();
199 instructions.add(new InstructionApplyActions(actionsInfos));
200 String flowRef = getFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
201 syncFlow(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef, NatConstants.SNAT_NEW_FLOW_PRIORITY,
202 flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions, addOrRemove);
205 protected void installNaptPfibExternalOutputFlow(Routers routers, BigInteger dpnId, List<ExternalIps> externalIps,
207 Long extNetId = NatUtil.getVpnId(dataBroker, routers.getNetworkId().getValue());
208 LOG.info("ConntrackBasedSnatService : buildPostSnatFlowEntity dpId {}, extNetId {}, srcIp {}",
209 dpnId, extNetId, externalIps);
210 List<MatchInfoBase> matches = new ArrayList<>();
211 matches.add(MatchEthernetType.IPV4);
212 matches.add(new NxMatchCtState(snatCtState, snatCtStateMask));
213 if (externalIps.isEmpty()) {
214 LOG.error("ConntrackBasedSnatService : installNaptPfibExternalOutputFlow no externalIP present for "
215 + "routerId {}", routers.getRouterName());
218 //The logic now handle only one external IP per router, others if present will be ignored.
219 String externalIp = externalIps.get(0).getIpAddress();
220 matches.add(new MatchIpv4Source(externalIp , "32"));
221 List<InstructionInfo> instructions = null;
222 Uuid subnetId = getSubnetIdOfIp(externalIp);
223 if (addOrRemove == NwConstants.ADD_FLOW && subnetId != null) {
224 instructions = new ArrayList<>();
225 List<ActionInfo> actionsInfos = new ArrayList<>();
226 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(subnetId.getValue()), idManager);
227 actionsInfos.add(new ActionGroup(groupId));
228 instructions.add(new InstructionApplyActions(actionsInfos));
230 String flowRef = getFlowRef(dpnId, NwConstants.NAPT_PFIB_TABLE, extNetId);
231 flowRef += externalIp;
232 syncFlow(dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef, NatConstants.SNAT_TRK_FLOW_PRIORITY,
233 flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions, addOrRemove);
236 protected void installInboundEntry(BigInteger dpnId, long routerId, Long extNetId, List<ExternalIps> externalIps,
237 int elanId, int addOrRemove) {
238 LOG.info("ConntrackBasedSnatService : installInboundEntry dpId {} and routerId {}",
240 List<MatchInfoBase> matches = new ArrayList<>();
241 matches.add(MatchEthernetType.IPV4);
242 matches.add(new MatchIpv4Destination(externalIps.get(0).getIpAddress(),"32"));
243 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(extNetId), MetaDataUtil.METADATA_MASK_VRFID));
244 List<ActionInfo> actionsInfos = new ArrayList<>();
245 List<NxCtAction> ctActionsList = new ArrayList<>();
246 NxCtAction nxCtAction = new ActionNxConntrack.NxNat(0, 0, 0,null, null,0, 0);
247 ActionSetFieldMeta actionSetFieldMeta = new ActionSetFieldMeta(MetaDataUtil
248 .getVpnIdMetadata(routerId));
249 actionsInfos.add(actionSetFieldMeta);
250 ctActionsList.add(nxCtAction);
251 ActionNxConntrack actionNxConntrack = new ActionNxConntrack(0, 0, elanId, NwConstants
252 .NAPT_PFIB_TABLE,ctActionsList);
254 actionsInfos.add(actionNxConntrack);
255 List<InstructionInfo> instructions = new ArrayList<>();
256 instructions.add(new InstructionApplyActions(actionsInfos));
257 String flowRef = getFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE, routerId);
258 syncFlow(dpnId, NwConstants.INBOUND_NAPT_TABLE, flowRef, NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef,
259 NwConstants.COOKIE_SNAT_TABLE, matches, instructions, addOrRemove);
262 protected void installNaptPfibEntry(BigInteger dpnId, long routerId, int addOrRemove) {
263 LOG.info("ConntrackBasedSnatService : installNaptPfibEntry called for dpnId {} and routerId {} ",
265 List<MatchInfoBase> matches = new ArrayList<>();
266 matches.add(MatchEthernetType.IPV4);
267 matches.add(new NxMatchCtState(dnatCtState, dnatCtStateMask));
269 ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
270 ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
271 listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
272 instructionInfo.add(new InstructionApplyActions(listActionInfo));
275 String flowRef = getFlowRef(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
276 syncFlow(dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef, NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef,
277 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo, addOrRemove);
280 private Uuid getSubnetIdOfIp(String ip) {
282 IpAddress externalIpv4Address = new IpAddress(new Ipv4Address(ip));
283 Port port = NatUtil.getNeutronPortForRouterGetewayIp(dataBroker, externalIpv4Address);
284 return NatUtil.getSubnetIdForFloatingIp(port, externalIpv4Address);