blob: 610066f88f231e24e2d360ff580f2027048b671e [file] [log] [blame]
Jian Li543fe852021-02-04 17:25:01 +09001/*
2 * Copyright 2021-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.kubevirtnetworking.util;
17
18import org.onlab.packet.Ip4Address;
Daniel Park4063f402021-02-25 09:14:22 +090019import org.onlab.packet.IpAddress;
20import org.onlab.packet.TpPort;
Jian Li543fe852021-02-04 17:25:01 +090021import org.onosproject.net.Device;
22import org.onosproject.net.DeviceId;
23import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
24import org.onosproject.net.device.DeviceService;
Daniel Park4063f402021-02-25 09:14:22 +090025import org.onosproject.net.driver.DriverHandler;
26import org.onosproject.net.driver.DriverService;
Jian Li543fe852021-02-04 17:25:01 +090027import org.onosproject.net.flow.instructions.ExtensionPropertyException;
28import org.onosproject.net.flow.instructions.ExtensionTreatment;
Daniel Park4063f402021-02-25 09:14:22 +090029import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
Jian Li543fe852021-02-04 17:25:01 +090030import org.slf4j.Logger;
31
Daniel Park4063f402021-02-25 09:14:22 +090032import java.util.ArrayList;
33import java.util.List;
34
Jian Li543fe852021-02-04 17:25:01 +090035import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_LOAD;
36import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_ARP_SHA_TO_THA;
37import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_ARP_SPA_TO_TPA;
38import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_ETH_SRC_TO_DST;
39import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_IP_SRC_TO_DST;
40import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
41import static org.slf4j.LoggerFactory.getLogger;
42
43/**
44 * Provides common methods to help populating flow rules for SONA applications.
45 */
46public final class RulePopulatorUtil {
47
48 private static final Logger log = getLogger(RulePopulatorUtil.class);
49
50 private static final int OFF_SET_BIT = 0;
51 private static final int REMAINDER_BIT = 8;
52
53 private static final String OFF_SET_N_BITS = "ofsNbits";
54 private static final String DESTINATION = "dst";
55 private static final String VALUE = "value";
56 private static final String TUNNEL_DST = "tunnelDst";
57
Daniel Park4063f402021-02-25 09:14:22 +090058 private static final String CT_FLAGS = "flags";
59 private static final String CT_ZONE = "zone";
60 private static final String CT_TABLE = "recircTable";
61 private static final String CT_STATE = "ctState";
62 private static final String CT_STATE_MASK = "ctStateMask";
63 private static final String CT_PRESENT_FLAGS = "presentFlags";
64 private static final String CT_IPADDRESS_MIN = "ipAddressMin";
65 private static final String CT_IPADDRESS_MAX = "ipAddressMax";
66 private static final String CT_PORT_MIN = "portMin";
67 private static final String CT_PORT_MAX = "portMax";
68 private static final String CT_NESTED_ACTIONS = "nestedActions";
69
70 public static final int CT_NAT_SRC_FLAG = 0;
71 public static final int CT_NAT_DST_FLAG = 1;
72 public static final int CT_NAT_PERSISTENT_FLAG = 2;
73 public static final int CT_NAT_PROTO_HASH_FLAG = 3;
74 public static final int CT_NAT_PROTO_RANDOM_FLAG = 4;
75
76 private static final int ADDRESS_V4_MIN_FLAG = 0;
77 private static final int ADDRESS_V4_MAX_FLAG = 1;
78 private static final int ADDRESS_V6_MIN_FLAG = 2;
79 private static final int ADDRESS_V6_MAX_FLAG = 3;
80 private static final int PORT_MIN_FLAG = 4;
81 private static final int PORT_MAX_FLAG = 5;
82
83 private static final String STR_ZERO = "0";
84 private static final String STR_ONE = "1";
85 private static final String STR_PADDING = "0000000000000000";
86 private static final int MASK_BEGIN_IDX = 0;
87 private static final int MASK_MAX_IDX = 16;
88 private static final int MASK_RADIX = 2;
89 private static final int PORT_RADIX = 16;
90
91 // Refer to http://openvswitch.org/support/dist-docs/ovs-fields.7.txt for the values
92 public static final long CT_STATE_NONE = 0;
93 public static final long CT_STATE_NEW = 0x01;
94 public static final long CT_STATE_EST = 0x02;
95 public static final long CT_STATE_NOT_TRK = 0x20;
96 public static final long CT_STATE_TRK = 0x20;
97
Jian Li543fe852021-02-04 17:25:01 +090098 // layer 3 nicira fields
99 private static final int NXM_OF_IP_SRC = 0x00000e04;
100 private static final int NXM_OF_IP_DST = 0x00001004;
101 private static final int NXM_OF_IP_PROT = 0x00000c01;
102
103 public static final int NXM_NX_IP_TTL = 0x00013a01;
104 public static final int NXM_NX_IP_FRAG = 0x00013401;
105 public static final int NXM_OF_ARP_OP = 0x00001e02;
106 public static final int NXM_OF_ARP_SPA = 0x00002004;
107 public static final int NXM_OF_ARP_TPA = 0x00002204;
108 public static final int NXM_NX_ARP_SHA = 0x00012206;
109 public static final int NXM_NX_ARP_THA = 0x00012406;
110
111 // layer 4 nicira fields
112 public static final int NXM_OF_TCP_SRC = 0x00001202;
113 public static final int NXM_OF_TCP_DST = 0x00001402;
114 public static final int NXM_NX_TCP_FLAGS = 0x00014402;
115 public static final int NXM_OF_UDP_SRC = 0x00001602;
116 public static final int NXM_OF_UDP_DST = 0x00001802;
117
118 public static final int NXM_OF_ICMP_TYPE = 0x00001a01;
119 public static final int NXM_OF_ICMP_CODE = 0x00001c01;
120
Daniel Park4063f402021-02-25 09:14:22 +0900121
Jian Li543fe852021-02-04 17:25:01 +0900122 private RulePopulatorUtil() {
123 }
124
125 /**
126 * Returns the nicira load extension treatment.
127 *
128 * @param device device instance
129 * @param field field code
130 * @param value value to load
131 * @return load extension treatment
132 */
133 public static ExtensionTreatment buildLoadExtension(Device device,
134 long field,
135 long value) {
136 if (!checkTreatmentResolver(device)) {
137 return null;
138 }
139
140 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
141 ExtensionTreatment treatment =
142 resolver.getExtensionInstruction(NICIRA_LOAD.type());
143
144 int ofsNbits = OFF_SET_BIT << 6 | (REMAINDER_BIT - 1);
145
146 try {
147 treatment.setPropertyValue(OFF_SET_N_BITS, ofsNbits);
148 treatment.setPropertyValue(DESTINATION, field);
149 treatment.setPropertyValue(VALUE, value);
150 return treatment;
151 } catch (ExtensionPropertyException e) {
152 log.error("Failed to set nicira load extension treatment for {}",
153 device.id());
154 return null;
155 }
156 }
157
158 /**
159 * Returns the nicira move source MAC to destination MAC extension treatment.
160 *
161 * @param device device instance
162 * @return move extension treatment
163 */
164 public static ExtensionTreatment buildMoveEthSrcToDstExtension(Device device) {
165 if (!checkTreatmentResolver(device)) {
166 return null;
167 }
168
169 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
170 return resolver.getExtensionInstruction(NICIRA_MOV_ETH_SRC_TO_DST.type());
171 }
172
173 /**
174 * Returns the nicira move source IP to destination IP extension treatment.
175 *
176 * @param device device instance
177 * @return move extension treatment
178 */
179 public static ExtensionTreatment buildMoveIpSrcToDstExtension(Device device) {
180 if (!checkTreatmentResolver(device)) {
181 return null;
182 }
183
184 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
185 return resolver.getExtensionInstruction(NICIRA_MOV_IP_SRC_TO_DST.type());
186 }
187
188 /**
189 * Returns the nicira move ARP SHA to THA extension treatment.
190 *
191 * @param device device instance
192 * @return move extension treatment
193 */
194 public static ExtensionTreatment buildMoveArpShaToThaExtension(Device device) {
195 if (!checkTreatmentResolver(device)) {
196 return null;
197 }
198
199 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
200 return resolver.getExtensionInstruction(NICIRA_MOV_ARP_SHA_TO_THA.type());
201 }
202
203 /**
204 * Returns the nicira move ARP SPA to TPA extension treatment.
205 *
206 * @param device device instance
207 * @return move extension treatment
208 */
209 public static ExtensionTreatment buildMoveArpSpaToTpaExtension(Device device) {
210 if (!checkTreatmentResolver(device)) {
211 return null;
212 }
213
214 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
215 return resolver.getExtensionInstruction(NICIRA_MOV_ARP_SPA_TO_TPA.type());
216 }
217
218 private static boolean checkTreatmentResolver(Device device) {
219 if (device == null || !device.is(ExtensionTreatmentResolver.class)) {
220 log.warn("Nicira extension treatment is not supported");
221 return false;
222 }
223
224 return true;
225 }
226
227 /**
228 * Returns tunnel destination extension treatment object.
229 *
230 * @param deviceService driver service
231 * @param deviceId device id to apply this treatment
232 * @param remoteIp tunnel destination ip address
233 * @return extension treatment
234 */
235 public static ExtensionTreatment buildExtension(DeviceService deviceService,
236 DeviceId deviceId,
237 Ip4Address remoteIp) {
238 Device device = deviceService.getDevice(deviceId);
239 if (!checkTreatmentResolver(device)) {
240 return null;
241 }
242
243 if (device == null) {
244 return null;
245 }
246
247 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
248 ExtensionTreatment treatment =
249 resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
250 try {
251 treatment.setPropertyValue(TUNNEL_DST, remoteIp);
252 return treatment;
253 } catch (ExtensionPropertyException e) {
254 log.warn("Failed to get tunnelDst extension treatment for {} " +
255 "because of {}", deviceId, e);
256 return null;
257 }
258 }
Daniel Park4063f402021-02-25 09:14:22 +0900259
260 public static NiciraConnTrackTreatmentBuilder niciraConnTrackTreatmentBuilder(DriverService ds, DeviceId id) {
261 return new NiciraConnTrackTreatmentBuilder(ds, id);
262 }
263 /**
264 * Builder class for OVS Connection Tracking feature actions.
265 */
266 public static final class NiciraConnTrackTreatmentBuilder {
267
268 private DriverService driverService;
269 private DeviceId deviceId;
270 private IpAddress natAddress = null;
271 private TpPort natPortMin = null;
272 private TpPort natPortMax = null;
273 private int zone;
274 private boolean commit;
275 private short table = -1;
276 private boolean natAction;
277 private int natFlag;
278
279 // private constructor
280 private NiciraConnTrackTreatmentBuilder(DriverService driverService,
281 DeviceId deviceId) {
282 this.driverService = driverService;
283 this.deviceId = deviceId;
284 }
285
286 /**
287 * Sets commit flag.
288 *
289 * @param c true if commit, false if not.
290 * @return NiriraConnTrackTreatmentBuilder object
291 */
292 public NiciraConnTrackTreatmentBuilder commit(boolean c) {
293 this.commit = c;
294 return this;
295 }
296
297 /**
298 * Sets zone number.
299 *
300 * @param z zone number
301 * @return NiriraConnTrackTreatmentBuilder object
302 */
303 public NiciraConnTrackTreatmentBuilder zone(int z) {
304 this.zone = z;
305 return this;
306 }
307
308 /**
309 * Sets recirculation table number.
310 *
311 * @param t table number to restart
312 * @return NiriraConnTrackTreatmentBuilder object
313 */
314 public NiciraConnTrackTreatmentBuilder table(short t) {
315 this.table = t;
316 return this;
317 }
318
319 /**
320 * Sets IP address for NAT.
321 *
322 * @param ip NAT IP address
323 * @return NiriraConnTrackTreatmentBuilder object
324 */
325 public NiciraConnTrackTreatmentBuilder natIp(IpAddress ip) {
326 this.natAddress = ip;
327 return this;
328 }
329
330 /**
331 * Sets min port for NAT.
332 *
333 * @param port port number
334 * @return NiciraConnTrackTreatmentBuilder object
335 */
336 public NiciraConnTrackTreatmentBuilder natPortMin(TpPort port) {
337 this.natPortMin = port;
338 return this;
339 }
340
341 /**
342 * Sets max port for NAT.
343 *
344 * @param port port number
345 * @return NiciraConnTrackTreatmentBuilder object
346 */
347 public NiciraConnTrackTreatmentBuilder natPortMax(TpPort port) {
348 this.natPortMax = port;
349 return this;
350 }
351
352 /**
353 * Sets NAT flags.
354 * SRC NAT: 1 << 0
355 * DST NAT: 1 << 1
356 * PERSISTENT NAT: 1 << 2
357 * PROTO_HASH NAT: 1 << 3
358 * PROTO_RANDOM NAT : 1 << 4
359 *
360 * @param flag flag value
361 * @return NiciraConnTrackTreatmentBuilder object
362 */
363 public NiciraConnTrackTreatmentBuilder natFlag(int flag) {
364 this.natFlag = 1 << flag;
365 return this;
366 }
367
368 /**
369 * Sets the flag for NAT action.
370 *
371 * @param nat nat action is included if true, no nat action otherwise
372 * @return NiriraConnTrackTreatmentBuilder object
373 */
374 public NiciraConnTrackTreatmentBuilder natAction(boolean nat) {
375 this.natAction = nat;
376 return this;
377 }
378
379 /**
380 * Builds extension treatment for OVS ConnTack and NAT feature.
381 *
382 * @return ExtensionTreatment object
383 */
384 public ExtensionTreatment build() {
385 DriverHandler handler = driverService.createHandler(deviceId);
386 ExtensionTreatmentResolver etr =
387 handler.behaviour(ExtensionTreatmentResolver.class);
388
389 ExtensionTreatment natTreatment = etr.getExtensionInstruction(
390 ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_NAT.type());
391 try {
392
393 if (natAddress == null && natPortMin == null && natPortMax == null) {
394 natTreatment.setPropertyValue(CT_FLAGS, 0);
395 natTreatment.setPropertyValue(CT_PRESENT_FLAGS, 0);
396 } else {
397 natTreatment.setPropertyValue(CT_FLAGS, this.natFlag);
398
399 natTreatment.setPropertyValue(CT_PRESENT_FLAGS,
400 buildPresentFlag((natPortMin != null && natPortMax != null),
401 natAddress != null));
402 }
403
404 if (natAddress != null) {
405 natTreatment.setPropertyValue(CT_IPADDRESS_MIN, natAddress);
406 natTreatment.setPropertyValue(CT_IPADDRESS_MAX, natAddress);
407 }
408
409 if (natPortMin != null) {
410 natTreatment.setPropertyValue(CT_PORT_MIN, natPortMin.toInt());
411 }
412
413 if (natPortMax != null) {
414 natTreatment.setPropertyValue(CT_PORT_MAX, natPortMax.toInt());
415 }
416
417 } catch (Exception e) {
418 log.error("Failed to set NAT due to error : {}", e);
419 return null;
420 }
421
422 ExtensionTreatment ctTreatment = etr.getExtensionInstruction(
423 ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_CT.type());
424 try {
425 List<ExtensionTreatment> nat = new ArrayList<>();
426 if (natAction) {
427 nat.add(natTreatment);
428 }
429 ctTreatment.setPropertyValue(CT_FLAGS, commit ? 1 : 0);
430 ctTreatment.setPropertyValue(CT_ZONE, zone);
431 ctTreatment.setPropertyValue(CT_TABLE, table > -1 ? table : 0xff);
432 ctTreatment.setPropertyValue(CT_NESTED_ACTIONS, nat);
433 } catch (Exception e) {
434 log.error("Failed to set CT due to error : {}", e);
435 return null;
436 }
437
438 return ctTreatment;
439 }
440
441 private int buildPresentFlag(boolean isPortPresent, boolean isAddressPresent) {
442
443 int presentFlag = 0;
444
445 if (isPortPresent) {
446 presentFlag = 1 << PORT_MIN_FLAG | 1 << PORT_MAX_FLAG;
447 }
448
449 if (isAddressPresent) {
450 // TODO: need to support IPv6 address
451 presentFlag = presentFlag | 1 << ADDRESS_V4_MIN_FLAG | 1 << ADDRESS_V4_MAX_FLAG;
452 }
453
454 return presentFlag;
455 }
456 }
Jian Li543fe852021-02-04 17:25:01 +0900457}