More NxMatchInfo re-design
[netvirt.git] / vpnservice / natservice / natservice-impl / src / main / java / org / opendaylight / netvirt / natservice / internal / ConntrackBasedSnatService.java
1 /*
2  * Copyright (c) 2017 Red Hat, Inc. and others. All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netvirt.natservice.internal;
9
10 import java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.List;
13
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;
49
50 public class ConntrackBasedSnatService extends AbstractSnatService {
51
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);
59
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,
64                 vpnManager);
65     }
66
67     @Override
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 */
76
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);
84
85         //Install Inbound NAT entries
86
87         installInboundEntry(dpnId, routerId, extNetId, externalIps, elanId, addOrRemove);
88         installNaptPfibEntry(dpnId, routerId, addOrRemove);
89
90     }
91
92     @Override
93     protected void installSnatSpecificEntriesForNonNaptSwitch(Routers routers, BigInteger dpnId, int addOrRemove) {
94         // Nothing to to do here.
95
96     }
97
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);
111
112         actionsInfos.add(actionNxConntrack);
113         instructions.add(new InstructionApplyActions(actionsInfos));
114
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);
118     }
119
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 {}",
122                 dpnId, routerId);
123         List<MatchInfo> matches = new ArrayList<>();
124         matches.add(MatchEthernetType.IPV4);
125         matches.add(new MatchTunnelId(BigInteger.valueOf(routerId)));
126
127
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);
143
144     }
145
146     protected void createOutboundTblTrackEntry(BigInteger dpnId, Long routerId, long extNetId, int addOrRemove) {
147         LOG.info("ConntrackBasedSnatService : createOutboundTblTrackEntry for switch {}, routerId {}",
148                 dpnId, 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));
160
161         String flowRef = getFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
162         flowRef += "trkest";
163         syncFlow(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef, NatConstants.SNAT_TRK_FLOW_PRIORITY, flowRef,
164                 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo, addOrRemove);
165
166     }
167
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 {}",
171                 dpnId, 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 {}",
183                     routerId);
184             return;
185         }
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(),
192                 null,0, 0);
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);
203     }
204
205     protected void installNaptPfibExternalOutputFlow(Routers routers, BigInteger dpnId, List<ExternalIps> externalIps,
206             int addOrRemove) {
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());
216             return;
217         }
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));
229         }
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);
234     }
235
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 {}",
239                 dpnId, 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);
253
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);
260     }
261
262     protected void installNaptPfibEntry(BigInteger dpnId, long routerId, int addOrRemove) {
263         LOG.info("ConntrackBasedSnatService : installNaptPfibEntry called for dpnId {} and routerId {} ",
264                 dpnId, routerId);
265         List<MatchInfoBase> matches = new ArrayList<>();
266         matches.add(MatchEthernetType.IPV4);
267         matches.add(new NxMatchCtState(dnatCtState, dnatCtStateMask));
268
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));
273
274
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);
278     }
279
280     private Uuid getSubnetIdOfIp(String ip) {
281         if (ip != null) {
282             IpAddress externalIpv4Address = new IpAddress(new Ipv4Address(ip));
283             Port port = NatUtil.getNeutronPortForRouterGetewayIp(dataBroker, externalIpv4Address);
284             return NatUtil.getSubnetIdForFloatingIp(port, externalIpv4Address);
285         }
286         return null;
287     }
288 }