blob: aca49deaa7377aec99754741bfede0431a03a920 [file] [log] [blame]
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -07003 *
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 */
Jian Li26949762018-03-30 15:46:37 +090016package org.onosproject.openstacknetworking.util;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070017
Jian Li6d2ffbf2020-11-04 15:58:18 +090018import com.google.common.collect.Maps;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070019import org.onlab.packet.Ip4Address;
sangho072c4dd2017-05-17 10:45:21 +090020import org.onlab.packet.IpAddress;
Jian Li5a26ab32019-03-21 15:20:01 +090021import org.onlab.packet.TpPort;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070022import org.onosproject.net.Device;
23import org.onosproject.net.DeviceId;
sangho072c4dd2017-05-17 10:45:21 +090024import org.onosproject.net.behaviour.ExtensionSelectorResolver;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070025import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
26import org.onosproject.net.device.DeviceService;
sangho072c4dd2017-05-17 10:45:21 +090027import org.onosproject.net.driver.DriverHandler;
28import org.onosproject.net.driver.DriverService;
Jian Lie87c2712019-09-11 11:15:16 +090029import org.onosproject.net.flow.TrafficTreatment;
sangho072c4dd2017-05-17 10:45:21 +090030import org.onosproject.net.flow.criteria.ExtensionSelector;
31import org.onosproject.net.flow.criteria.ExtensionSelectorType;
sangho1aaa7882017-05-31 13:22:47 +090032import org.onosproject.net.flow.instructions.ExtensionPropertyException;
33import org.onosproject.net.flow.instructions.ExtensionTreatment;
sangho072c4dd2017-05-17 10:45:21 +090034import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
Jian Lie87c2712019-09-11 11:15:16 +090035import org.onosproject.net.group.DefaultGroupBucket;
36import org.onosproject.net.group.GroupBucket;
37import org.onosproject.net.group.GroupDescription;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070038import org.slf4j.Logger;
39
sangho072c4dd2017-05-17 10:45:21 +090040import java.util.ArrayList;
41import java.util.List;
Jian Li6d2ffbf2020-11-04 15:58:18 +090042import java.util.Map;
43import java.util.Objects;
sangho072c4dd2017-05-17 10:45:21 +090044
Jian Li25257212019-03-26 13:31:14 +090045import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_LOAD;
Jian Li4910c4b2019-04-01 18:06:40 +090046import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_ARP_SHA_TO_THA;
47import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_ARP_SPA_TO_TPA;
Jian Li25257212019-03-26 13:31:14 +090048import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_ETH_SRC_TO_DST;
49import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_IP_SRC_TO_DST;
50import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_POP_NSH;
51import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_PUSH_NSH;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070052import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
53import static org.slf4j.LoggerFactory.getLogger;
54
55/**
56 * Provides common methods to help populating flow rules for SONA applications.
57 */
58public final class RulePopulatorUtil {
59
Ray Milkey9c9cde42018-01-12 14:22:06 -080060 private static final Logger log = getLogger(RulePopulatorUtil.class);
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070061
62 private static final String TUNNEL_DST = "tunnelDst";
sangho072c4dd2017-05-17 10:45:21 +090063 private static final String CT_FLAGS = "flags";
64 private static final String CT_ZONE = "zone";
65 private static final String CT_TABLE = "recircTable";
sangho072c4dd2017-05-17 10:45:21 +090066 private static final String CT_STATE = "ctState";
67 private static final String CT_STATE_MASK = "ctStateMask";
68 private static final String CT_PRESENT_FLAGS = "presentFlags";
69 private static final String CT_IPADDRESS_MIN = "ipAddressMin";
70 private static final String CT_IPADDRESS_MAX = "ipAddressMax";
Jian Li5a26ab32019-03-21 15:20:01 +090071 private static final String CT_PORT_MIN = "portMin";
72 private static final String CT_PORT_MAX = "portMax";
73 private static final String CT_NESTED_ACTIONS = "nestedActions";
sangho072c4dd2017-05-17 10:45:21 +090074
Jian Li5a26ab32019-03-21 15:20:01 +090075 public static final int CT_NAT_SRC_FLAG = 0;
76 public static final int CT_NAT_DST_FLAG = 1;
77 public static final int CT_NAT_PERSISTENT_FLAG = 2;
78 public static final int CT_NAT_PROTO_HASH_FLAG = 3;
79 public static final int CT_NAT_PROTO_RANDOM_FLAG = 4;
80
81 private static final int ADDRESS_V4_MIN_FLAG = 0;
82 private static final int ADDRESS_V4_MAX_FLAG = 1;
83 private static final int ADDRESS_V6_MIN_FLAG = 2;
84 private static final int ADDRESS_V6_MAX_FLAG = 3;
85 private static final int PORT_MIN_FLAG = 4;
86 private static final int PORT_MAX_FLAG = 5;
sangho072c4dd2017-05-17 10:45:21 +090087
Jian Li6d2ffbf2020-11-04 15:58:18 +090088 private static final String STR_ZERO = "0";
89 private static final String STR_ONE = "1";
90 private static final String STR_PADDING = "0000000000000000";
91 private static final int MASK_BEGIN_IDX = 0;
92 private static final int MASK_MAX_IDX = 16;
93 private static final int MASK_RADIX = 2;
94 private static final int PORT_RADIX = 16;
95
sangho072c4dd2017-05-17 10:45:21 +090096 // Refer to http://openvswitch.org/support/dist-docs/ovs-fields.7.txt for the values
97 public static final long CT_STATE_NONE = 0;
98 public static final long CT_STATE_NEW = 0x01;
99 public static final long CT_STATE_EST = 0x02;
100 public static final long CT_STATE_NOT_TRK = 0x20;
101 public static final long CT_STATE_TRK = 0x20;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700102
Jian Li25257212019-03-26 13:31:14 +0900103 private static final String OFF_SET_N_BITS = "ofsNbits";
104 private static final String DESTINATION = "dst";
105 private static final String VALUE = "value";
106
107 private static final int OFF_SET_BIT = 0;
108 private static final int REMAINDER_BIT = 8;
109
110 // layer 3 nicira fields
111 public static final int NXM_OF_IP_SRC = 0x00000e04;
112 public static final int NXM_OF_IP_DST = 0x00001004;
113 public static final int NXM_OF_IP_PROT = 0x00000c01;
114
115 public static final int NXM_NX_IP_TTL = 0x00013a01;
116 public static final int NXM_NX_IP_FRAG = 0x00013401;
117 public static final int NXM_OF_ARP_OP = 0x00001e02;
118 public static final int NXM_OF_ARP_SPA = 0x00002004;
119 public static final int NXM_OF_ARP_TPA = 0x00002204;
120 public static final int NXM_NX_ARP_SHA = 0x00012206;
121 public static final int NXM_NX_ARP_THA = 0x00012406;
122
123 // layer 4 nicira fields
124 public static final int NXM_OF_TCP_SRC = 0x00001202;
125 public static final int NXM_OF_TCP_DST = 0x00001402;
126 public static final int NXM_NX_TCP_FLAGS = 0x00014402;
127 public static final int NXM_OF_UDP_SRC = 0x00001602;
128 public static final int NXM_OF_UDP_DST = 0x00001802;
129
130 public static final int NXM_OF_ICMP_TYPE = 0x00001a01;
131 public static final int NXM_OF_ICMP_CODE = 0x00001c01;
132
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700133 private RulePopulatorUtil() {
134 }
135
136 /**
sangho072c4dd2017-05-17 10:45:21 +0900137 * Returns a builder for OVS Connection Tracking feature actions.
138 *
139 * @param ds DriverService
140 * @param id DeviceId
141 * @return a builder for OVS Connection Tracking feature actions
142 */
Jian Li5a26ab32019-03-21 15:20:01 +0900143 public static NiciraConnTrackTreatmentBuilder
Jian Li5ecfd1a2018-12-10 11:41:03 +0900144 niciraConnTrackTreatmentBuilder(DriverService ds, DeviceId id) {
Jian Li5a26ab32019-03-21 15:20:01 +0900145 return new NiciraConnTrackTreatmentBuilder(ds, id);
sangho072c4dd2017-05-17 10:45:21 +0900146 }
147
148 /**
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700149 * Returns tunnel destination extension treatment object.
150 *
151 * @param deviceService driver service
152 * @param deviceId device id to apply this treatment
153 * @param remoteIp tunnel destination ip address
154 * @return extension treatment
155 */
156 public static ExtensionTreatment buildExtension(DeviceService deviceService,
157 DeviceId deviceId,
158 Ip4Address remoteIp) {
159 Device device = deviceService.getDevice(deviceId);
Jian Li4910c4b2019-04-01 18:06:40 +0900160 if (!checkTreatmentResolver(device)) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700161 return null;
162 }
sangho072c4dd2017-05-17 10:45:21 +0900163
Ray Milkey74e59132018-01-17 15:24:52 -0800164 if (device == null) {
165 return null;
166 }
167
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700168 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
Jian Li5ecfd1a2018-12-10 11:41:03 +0900169 ExtensionTreatment treatment =
170 resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700171 try {
172 treatment.setPropertyValue(TUNNEL_DST, remoteIp);
173 return treatment;
174 } catch (ExtensionPropertyException e) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900175 log.warn("Failed to get tunnelDst extension treatment for {} " +
176 "because of {}", deviceId, e);
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700177 return null;
178 }
179 }
sangho072c4dd2017-05-17 10:45:21 +0900180
181 /**
182 * Builds OVS ConnTrack matches.
183 *
184 * @param driverService driver service
185 * @param deviceId device ID
186 * @param ctState connection tracking sate masking value
187 * @param ctSateMask connection tracking sate masking value
188 * @return OVS ConnTrack extension match
189 */
Jian Li5ecfd1a2018-12-10 11:41:03 +0900190 public static ExtensionSelector buildCtExtensionSelector(DriverService driverService,
191 DeviceId deviceId,
192 long ctState,
193 long ctSateMask) {
sangho072c4dd2017-05-17 10:45:21 +0900194 DriverHandler handler = driverService.createHandler(deviceId);
195 ExtensionSelectorResolver esr = handler.behaviour(ExtensionSelectorResolver.class);
196
197 ExtensionSelector extensionSelector = esr.getExtensionSelector(
198 ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_CONNTRACK_STATE.type());
199 try {
200 extensionSelector.setPropertyValue(CT_STATE, ctState);
201 extensionSelector.setPropertyValue(CT_STATE_MASK, ctSateMask);
202 } catch (Exception e) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900203 log.error("Failed to set nicira match CT state because of {}", e);
sangho072c4dd2017-05-17 10:45:21 +0900204 return null;
205 }
206
207 return extensionSelector;
208 }
209
210 /**
Jian Li25257212019-03-26 13:31:14 +0900211 * Returns the nicira load extension treatment.
212 *
213 * @param device device instance
214 * @param field field code
215 * @param value value to load
216 * @return load extension treatment
217 */
218 public static ExtensionTreatment buildLoadExtension(Device device,
219 long field,
220 long value) {
Jian Li4910c4b2019-04-01 18:06:40 +0900221 if (!checkTreatmentResolver(device)) {
Jian Li25257212019-03-26 13:31:14 +0900222 return null;
223 }
224
225 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
226 ExtensionTreatment treatment =
227 resolver.getExtensionInstruction(NICIRA_LOAD.type());
228
229 int ofsNbits = OFF_SET_BIT << 6 | (REMAINDER_BIT - 1);
230
231 try {
232 treatment.setPropertyValue(OFF_SET_N_BITS, ofsNbits);
233 treatment.setPropertyValue(DESTINATION, field);
234 treatment.setPropertyValue(VALUE, value);
235 return treatment;
236 } catch (ExtensionPropertyException e) {
237 log.error("Failed to set nicira load extension treatment for {}",
238 device.id());
239 return null;
240 }
241 }
242
243 /**
Jian Lie87c2712019-09-11 11:15:16 +0900244 * Returns the group bucket with given traffic treatment and group type.
245 *
246 * @param treatment traffic treatment
247 * @param type group type
248 * @param weight weight (only for select type)
249 * @return group bucket
250 */
251 public static GroupBucket buildGroupBucket(TrafficTreatment treatment,
252 GroupDescription.Type type, short weight) {
253 switch (type) {
254 case ALL:
255 return DefaultGroupBucket.createAllGroupBucket(treatment);
256 case SELECT:
257 if (weight == -1) {
258 return DefaultGroupBucket.createSelectGroupBucket(treatment);
259 } else {
260 return DefaultGroupBucket.createSelectGroupBucket(treatment, weight);
261 }
262 case INDIRECT:
263 return DefaultGroupBucket.createIndirectGroupBucket(treatment);
264 default:
265 return null;
266 }
267 }
268
269 /**
Jian Li25257212019-03-26 13:31:14 +0900270 * Returns the nicira push extension treatment.
271 *
272 * @param device device instance
273 * @return push extension treatment
274 */
275 public static ExtensionTreatment buildPushExtension(Device device) {
Jian Li4910c4b2019-04-01 18:06:40 +0900276 if (!checkTreatmentResolver(device)) {
Jian Li25257212019-03-26 13:31:14 +0900277 return null;
278 }
279
280 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
281 return resolver.getExtensionInstruction(NICIRA_PUSH_NSH.type());
282 }
283
284 /**
285 * Returns the nicira pop extension treatment.
286 *
287 * @param device device instance
288 * @return pop extension treatment
289 */
290 public static ExtensionTreatment buildPopExtension(Device device) {
Jian Li4910c4b2019-04-01 18:06:40 +0900291 if (!checkTreatmentResolver(device)) {
Jian Li25257212019-03-26 13:31:14 +0900292 return null;
293 }
294
295 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
296 return resolver.getExtensionInstruction(NICIRA_POP_NSH.type());
297 }
298
299 /**
300 * Returns the nicira move source MAC to destination MAC extension treatment.
301 *
302 * @param device device instance
303 * @return move extension treatment
304 */
305 public static ExtensionTreatment buildMoveEthSrcToDstExtension(Device device) {
Jian Li4910c4b2019-04-01 18:06:40 +0900306 if (!checkTreatmentResolver(device)) {
Jian Li25257212019-03-26 13:31:14 +0900307 return null;
308 }
309
310 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
311 return resolver.getExtensionInstruction(NICIRA_MOV_ETH_SRC_TO_DST.type());
312 }
313
314 /**
315 * Returns the nicira move source IP to destination IP extension treatment.
316 *
317 * @param device device instance
318 * @return move extension treatment
319 */
320 public static ExtensionTreatment buildMoveIpSrcToDstExtension(Device device) {
Jian Li4910c4b2019-04-01 18:06:40 +0900321 if (!checkTreatmentResolver(device)) {
Jian Li25257212019-03-26 13:31:14 +0900322 return null;
323 }
324
325 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
326 return resolver.getExtensionInstruction(NICIRA_MOV_IP_SRC_TO_DST.type());
327 }
328
329 /**
Jian Li4910c4b2019-04-01 18:06:40 +0900330 * Returns the nicira move ARP SHA to THA extension treatment.
331 *
332 * @param device device instance
333 * @return move extension treatment
334 */
335 public static ExtensionTreatment buildMoveArpShaToThaExtension(Device device) {
336 if (!checkTreatmentResolver(device)) {
337 return null;
338 }
339
340 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
341 return resolver.getExtensionInstruction(NICIRA_MOV_ARP_SHA_TO_THA.type());
342 }
343
344 /**
345 * Returns the nicira move ARP SPA to TPA extension treatment.
346 *
347 * @param device device instance
348 * @return move extension treatment
349 */
350 public static ExtensionTreatment buildMoveArpSpaToTpaExtension(Device device) {
351 if (!checkTreatmentResolver(device)) {
352 return null;
353 }
354
355 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
356 return resolver.getExtensionInstruction(NICIRA_MOV_ARP_SPA_TO_TPA.type());
357 }
358
359 /**
sangho072c4dd2017-05-17 10:45:21 +0900360 * Computes ConnTack State flag values.
361 *
362 * @param isTracking true for +trk, false for -trk
363 * @param isNew true for +new, false for nothing
364 * @param isEstablished true for +est, false for nothing
365 * @return ConnTrack State flags
366 */
Jian Li5ecfd1a2018-12-10 11:41:03 +0900367 public static long computeCtStateFlag(boolean isTracking,
368 boolean isNew,
369 boolean isEstablished) {
sangho072c4dd2017-05-17 10:45:21 +0900370 long ctMaskFlag = 0x00;
371
372 if (isTracking) {
373 ctMaskFlag = ctMaskFlag | CT_STATE_TRK;
374 }
375
376 if (isNew) {
377 ctMaskFlag = ctMaskFlag | CT_STATE_TRK;
378 ctMaskFlag = ctMaskFlag | CT_STATE_NEW;
379 }
380
381 if (isEstablished) {
382 ctMaskFlag = ctMaskFlag | CT_STATE_TRK;
383 ctMaskFlag = ctMaskFlag | CT_STATE_EST;
384 }
385
386 return ctMaskFlag;
387 }
388
389 /**
390 * Computes ConnTrack State mask values.
391 *
392 * @param isTracking true for setting +trk/-trk value, false for otherwise
393 * @param isNew true for setting +new value, false for otherwise
394 * @param isEstablished true for setting +est value, false for otherwise
395 * @return ConnTrack State Mask value
396 */
Jian Li5ecfd1a2018-12-10 11:41:03 +0900397 public static long computeCtMaskFlag(boolean isTracking,
398 boolean isNew,
399 boolean isEstablished) {
sangho072c4dd2017-05-17 10:45:21 +0900400 long ctMaskFlag = 0x00;
401
402 if (isTracking) {
403 ctMaskFlag = ctMaskFlag | CT_STATE_TRK;
404 }
405
406 if (isNew) {
407 ctMaskFlag = ctMaskFlag | CT_STATE_TRK;
408 ctMaskFlag = ctMaskFlag | CT_STATE_NEW;
409 }
410
411 if (isEstablished) {
412 ctMaskFlag = ctMaskFlag | CT_STATE_TRK;
413 ctMaskFlag = ctMaskFlag | CT_STATE_EST;
414 }
415
416 return ctMaskFlag;
417 }
418
Jian Li6d2ffbf2020-11-04 15:58:18 +0900419 /**
420 * Computes port and port mask value from port min/max values.
421 *
422 * @param portMin port min value
423 * @param portMax port max value
424 * @return Port Mask value
425 */
426 public static Map<TpPort, TpPort> buildPortRangeMatches(int portMin, int portMax) {
427
428 boolean processing = true;
429 int start = portMin;
430 Map<TpPort, TpPort> portMaskMap = Maps.newHashMap();
431 while (processing) {
432 String minStr = Integer.toBinaryString(start);
433 String binStrMinPadded = STR_PADDING.substring(minStr.length()) + minStr;
434
435 int mask = testMasks(binStrMinPadded, start, portMax);
436 int maskStart = binLower(binStrMinPadded, mask);
437 int maskEnd = binHigher(binStrMinPadded, mask);
438
439 log.debug("start : {} port/mask = {} / {} ", start, getMask(mask), maskStart);
440 portMaskMap.put(TpPort.tpPort(maskStart), TpPort.tpPort(
441 Integer.parseInt(Objects.requireNonNull(getMask(mask)), PORT_RADIX)));
442
443 start = maskEnd + 1;
444 if (start > portMax) {
445 processing = false;
446 }
447 }
448
449 return portMaskMap;
450 }
451
452 private static int binLower(String binStr, int bits) {
453 StringBuilder outBin = new StringBuilder(
454 binStr.substring(MASK_BEGIN_IDX, MASK_MAX_IDX - bits));
455 for (int i = 0; i < bits; i++) {
456 outBin.append(STR_ZERO);
457 }
458
459 return Integer.parseInt(outBin.toString(), MASK_RADIX);
460 }
461
462 private static int binHigher(String binStr, int bits) {
463 StringBuilder outBin = new StringBuilder(
464 binStr.substring(MASK_BEGIN_IDX, MASK_MAX_IDX - bits));
465 for (int i = 0; i < bits; i++) {
466 outBin.append(STR_ONE);
467 }
468
469 return Integer.parseInt(outBin.toString(), MASK_RADIX);
470 }
471
472 private static int testMasks(String binStr, int start, int end) {
473 int mask = MASK_BEGIN_IDX;
474 for (; mask <= MASK_MAX_IDX; mask++) {
475 int maskStart = binLower(binStr, mask);
476 int maskEnd = binHigher(binStr, mask);
477 if (maskStart < start || maskEnd > end) {
478 return mask - 1;
479 }
480 }
481
482 return mask;
483 }
484
485 private static String getMask(int bits) {
486 switch (bits) {
487 case 0: return "ffff";
488 case 1: return "fffe";
489 case 2: return "fffc";
490 case 3: return "fff8";
491 case 4: return "fff0";
492 case 5: return "ffe0";
493 case 6: return "ffc0";
494 case 7: return "ff80";
495 case 8: return "ff00";
496 case 9: return "fe00";
497 case 10: return "fc00";
498 case 11: return "f800";
499 case 12: return "f000";
500 case 13: return "e000";
501 case 14: return "c000";
502 case 15: return "8000";
503 case 16: return "0000";
504 default: return null;
505 }
506 }
507
Jian Li4910c4b2019-04-01 18:06:40 +0900508 private static boolean checkTreatmentResolver(Device device) {
509 if (device == null || !device.is(ExtensionTreatmentResolver.class)) {
510 log.warn("Nicira extension treatment is not supported");
511 return false;
512 }
513
514 return true;
515 }
516
sangho072c4dd2017-05-17 10:45:21 +0900517 /**
518 * Builder class for OVS Connection Tracking feature actions.
519 */
Jian Li5a26ab32019-03-21 15:20:01 +0900520 public static final class NiciraConnTrackTreatmentBuilder {
sangho072c4dd2017-05-17 10:45:21 +0900521
522 private DriverService driverService;
523 private DeviceId deviceId;
524 private IpAddress natAddress = null;
Jian Li5a26ab32019-03-21 15:20:01 +0900525 private TpPort natPortMin = null;
526 private TpPort natPortMax = null;
sangho072c4dd2017-05-17 10:45:21 +0900527 private int zone;
528 private boolean commit;
529 private short table = -1;
530 private boolean natAction;
Jian Li5a26ab32019-03-21 15:20:01 +0900531 private int natFlag;
sangho072c4dd2017-05-17 10:45:21 +0900532
Jian Li5a26ab32019-03-21 15:20:01 +0900533 // private constructor
534 private NiciraConnTrackTreatmentBuilder(DriverService driverService,
Jian Li5ecfd1a2018-12-10 11:41:03 +0900535 DeviceId deviceId) {
sangho072c4dd2017-05-17 10:45:21 +0900536 this.driverService = driverService;
537 this.deviceId = deviceId;
538 }
539
540 /**
541 * Sets commit flag.
542 *
543 * @param c true if commit, false if not.
544 * @return NiriraConnTrackTreatmentBuilder object
545 */
Jian Li5a26ab32019-03-21 15:20:01 +0900546 public NiciraConnTrackTreatmentBuilder commit(boolean c) {
sangho072c4dd2017-05-17 10:45:21 +0900547 this.commit = c;
548 return this;
549 }
550
551 /**
552 * Sets zone number.
553 *
554 * @param z zone number
555 * @return NiriraConnTrackTreatmentBuilder object
556 */
Jian Li5a26ab32019-03-21 15:20:01 +0900557 public NiciraConnTrackTreatmentBuilder zone(int z) {
sangho072c4dd2017-05-17 10:45:21 +0900558 this.zone = z;
559 return this;
560 }
561
562 /**
563 * Sets recirculation table number.
564 *
565 * @param t table number to restart
566 * @return NiriraConnTrackTreatmentBuilder object
567 */
Jian Li5a26ab32019-03-21 15:20:01 +0900568 public NiciraConnTrackTreatmentBuilder table(short t) {
sangho072c4dd2017-05-17 10:45:21 +0900569 this.table = t;
570 return this;
571 }
572
573 /**
574 * Sets IP address for NAT.
575 *
576 * @param ip NAT IP address
577 * @return NiriraConnTrackTreatmentBuilder object
578 */
Jian Li5a26ab32019-03-21 15:20:01 +0900579 public NiciraConnTrackTreatmentBuilder natIp(IpAddress ip) {
sangho072c4dd2017-05-17 10:45:21 +0900580 this.natAddress = ip;
581 return this;
582 }
583
584 /**
Jian Li5a26ab32019-03-21 15:20:01 +0900585 * Sets min port for NAT.
586 *
587 * @param port port number
588 * @return NiciraConnTrackTreatmentBuilder object
589 */
590 public NiciraConnTrackTreatmentBuilder natPortMin(TpPort port) {
591 this.natPortMin = port;
592 return this;
593 }
594
595 /**
596 * Sets max port for NAT.
597 *
598 * @param port port number
599 * @return NiciraConnTrackTreatmentBuilder object
600 */
601 public NiciraConnTrackTreatmentBuilder natPortMax(TpPort port) {
602 this.natPortMax = port;
603 return this;
604 }
605
606 /**
607 * Sets NAT flags.
608 * SRC NAT: 1 << 0
609 * DST NAT: 1 << 1
610 * PERSISTENT NAT: 1 << 2
611 * PROTO_HASH NAT: 1 << 3
612 * PROTO_RANDOM NAT : 1 << 4
613 *
614 * @param flag flag value
615 * @return NiciraConnTrackTreatmentBuilder object
616 */
617 public NiciraConnTrackTreatmentBuilder natFlag(int flag) {
618 this.natFlag = 1 << flag;
619 return this;
620 }
621
622 /**
sangho072c4dd2017-05-17 10:45:21 +0900623 * Sets the flag for NAT action.
624 *
625 * @param nat nat action is included if true, no nat action otherwise
626 * @return NiriraConnTrackTreatmentBuilder object
627 */
Jian Li5a26ab32019-03-21 15:20:01 +0900628 public NiciraConnTrackTreatmentBuilder natAction(boolean nat) {
sangho072c4dd2017-05-17 10:45:21 +0900629 this.natAction = nat;
630 return this;
631 }
632
633 /**
634 * Builds extension treatment for OVS ConnTack and NAT feature.
635 *
636 * @return ExtensionTreatment object
637 */
638 public ExtensionTreatment build() {
639 DriverHandler handler = driverService.createHandler(deviceId);
Jian Li5a26ab32019-03-21 15:20:01 +0900640 ExtensionTreatmentResolver etr =
641 handler.behaviour(ExtensionTreatmentResolver.class);
sangho072c4dd2017-05-17 10:45:21 +0900642
Jian Li5ecfd1a2018-12-10 11:41:03 +0900643 ExtensionTreatment natTreatment = etr.getExtensionInstruction(
644 ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_NAT.type());
sangho072c4dd2017-05-17 10:45:21 +0900645 try {
Jian Li5a26ab32019-03-21 15:20:01 +0900646
647 if (natAddress == null && natPortMin == null && natPortMax == null) {
sangho072c4dd2017-05-17 10:45:21 +0900648 natTreatment.setPropertyValue(CT_FLAGS, 0);
649 natTreatment.setPropertyValue(CT_PRESENT_FLAGS, 0);
Jian Li5a26ab32019-03-21 15:20:01 +0900650 } else {
651 natTreatment.setPropertyValue(CT_FLAGS, this.natFlag);
652
653 natTreatment.setPropertyValue(CT_PRESENT_FLAGS,
654 buildPresentFlag((natPortMin != null && natPortMax != null),
655 natAddress != null));
sangho072c4dd2017-05-17 10:45:21 +0900656 }
Jian Li5a26ab32019-03-21 15:20:01 +0900657
658 if (natAddress != null) {
659 natTreatment.setPropertyValue(CT_IPADDRESS_MIN, natAddress);
660 natTreatment.setPropertyValue(CT_IPADDRESS_MAX, natAddress);
661 }
662
663 if (natPortMin != null) {
664 natTreatment.setPropertyValue(CT_PORT_MIN, natPortMin.toInt());
665 }
666
667 if (natPortMax != null) {
668 natTreatment.setPropertyValue(CT_PORT_MAX, natPortMax.toInt());
669 }
670
sangho072c4dd2017-05-17 10:45:21 +0900671 } catch (Exception e) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900672 log.error("Failed to set NAT due to error : {}", e);
sangho072c4dd2017-05-17 10:45:21 +0900673 return null;
674 }
675
Jian Li5ecfd1a2018-12-10 11:41:03 +0900676 ExtensionTreatment ctTreatment = etr.getExtensionInstruction(
677 ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_CT.type());
sangho072c4dd2017-05-17 10:45:21 +0900678 try {
679 List<ExtensionTreatment> nat = new ArrayList<>();
680 if (natAction) {
681 nat.add(natTreatment);
682 }
683 ctTreatment.setPropertyValue(CT_FLAGS, commit ? 1 : 0);
684 ctTreatment.setPropertyValue(CT_ZONE, zone);
685 ctTreatment.setPropertyValue(CT_TABLE, table > -1 ? table : 0xff);
Jian Li5a26ab32019-03-21 15:20:01 +0900686 ctTreatment.setPropertyValue(CT_NESTED_ACTIONS, nat);
sangho072c4dd2017-05-17 10:45:21 +0900687 } catch (Exception e) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900688 log.error("Failed to set CT due to error : {}", e);
sangho072c4dd2017-05-17 10:45:21 +0900689 return null;
690 }
691
692 return ctTreatment;
693 }
694
695 private int buildPresentFlag(boolean isPortPresent, boolean isAddressPresent) {
696
697 int presentFlag = 0;
698
699 if (isPortPresent) {
Jian Li5a26ab32019-03-21 15:20:01 +0900700 presentFlag = 1 << PORT_MIN_FLAG | 1 << PORT_MAX_FLAG;
sangho072c4dd2017-05-17 10:45:21 +0900701 }
702
703 if (isAddressPresent) {
Jian Li5a26ab32019-03-21 15:20:01 +0900704 // TODO: need to support IPv6 address
705 presentFlag = presentFlag | 1 << ADDRESS_V4_MIN_FLAG | 1 << ADDRESS_V4_MAX_FLAG;
sangho072c4dd2017-05-17 10:45:21 +0900706 }
707
708 return presentFlag;
709 }
710 }
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700711}