blob: 25a44eaf5afbb6a060f6f3f51b42f399ce16e4c2 [file] [log] [blame]
Jian Li4aa17642019-01-30 00:01:11 +09001/*
2 * Copyright 2019-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.k8snetworking.util;
17
18import org.onlab.packet.Ip4Address;
Jian Li2cc2b632019-02-18 00:56:40 +090019import org.onlab.packet.IpAddress;
20import org.onlab.packet.TpPort;
Jian Li4aa17642019-01-30 00:01:11 +090021import org.onosproject.net.Device;
22import org.onosproject.net.DeviceId;
Jian Li2cc2b632019-02-18 00:56:40 +090023import org.onosproject.net.behaviour.ExtensionSelectorResolver;
Jian Li4aa17642019-01-30 00:01:11 +090024import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
25import org.onosproject.net.device.DeviceService;
Jian Li2cc2b632019-02-18 00:56:40 +090026import org.onosproject.net.driver.DriverHandler;
27import org.onosproject.net.driver.DriverService;
28import org.onosproject.net.flow.TrafficTreatment;
29import org.onosproject.net.flow.criteria.ExtensionSelector;
30import org.onosproject.net.flow.criteria.ExtensionSelectorType;
Jian Li4aa17642019-01-30 00:01:11 +090031import org.onosproject.net.flow.instructions.ExtensionPropertyException;
32import org.onosproject.net.flow.instructions.ExtensionTreatment;
Jian Li2cc2b632019-02-18 00:56:40 +090033import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
34import org.onosproject.net.group.DefaultGroupBucket;
35import org.onosproject.net.group.GroupBucket;
36import org.onosproject.net.group.GroupDescription.Type;
Jian Li4aa17642019-01-30 00:01:11 +090037import org.slf4j.Logger;
38
Jian Li2cc2b632019-02-18 00:56:40 +090039import java.util.ArrayList;
40import java.util.List;
41
Jian Li5e8a22a2019-02-27 11:48:42 +090042import static org.onosproject.k8snetworking.api.Constants.DST;
43import static org.onosproject.k8snetworking.api.Constants.SRC;
Jian Li004526d2019-02-25 16:26:27 +090044import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_LOAD;
Jian Li2cc2b632019-02-18 00:56:40 +090045import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_RESUBMIT_TABLE;
Jian Li4aa17642019-01-30 00:01:11 +090046import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
47import static org.slf4j.LoggerFactory.getLogger;
48
49/**
50 * Provides common methods to help populating flow rules for SONA applications.
51 */
52public final class RulePopulatorUtil {
53
54 private static final Logger log = getLogger(RulePopulatorUtil.class);
55
56 private static final String TUNNEL_DST = "tunnelDst";
57
Jian Li2cc2b632019-02-18 00:56:40 +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
Jian Li004526d2019-02-25 16:26:27 +090083 private static final long CT_STATE_NONE = 0;
84 private static final long CT_STATE_NEW = 0x01;
85 private static final long CT_STATE_EST = 0x02;
86 private static final long CT_STATE_NOT_TRK = 0x20;
87 private static final long CT_STATE_TRK = 0x20;
Jian Li2cc2b632019-02-18 00:56:40 +090088
89 private static final String TABLE_EXTENSION = "table";
90
Jian Li004526d2019-02-25 16:26:27 +090091 private static final String OFF_SET_N_BITS = "ofsNbits";
92 private static final String DESTINATION = "dst";
93 private static final String VALUE = "value";
94
95 private static final int SRC_IP = 0x00000e04;
96 private static final int DST_IP = 0x00001004;
97
Jian Li004526d2019-02-25 16:26:27 +090098 private static final int OFF_SET_BIT = 16;
99 private static final int REMAINDER_BIT = 16;
100
Jian Li2cc2b632019-02-18 00:56:40 +0900101 // not intended for direct invocation from external
Jian Li4aa17642019-01-30 00:01:11 +0900102 private RulePopulatorUtil() {
103 }
104
105 /**
Jian Li2cc2b632019-02-18 00:56:40 +0900106 * Returns a builder for OVS Connection Tracking feature actions.
107 *
108 * @param ds DriverService
109 * @param id DeviceId
110 * @return a builder for OVS Connection Tracking feature actions
111 */
112 public static NiciraConnTrackTreatmentBuilder
113 niciraConnTrackTreatmentBuilder(DriverService ds, DeviceId id) {
114 return new NiciraConnTrackTreatmentBuilder(ds, id);
115 }
116
117 /**
118 * Builds OVS ConnTrack matches.
119 *
120 * @param driverService driver service
121 * @param deviceId device ID
122 * @param ctState connection tracking sate masking value
123 * @param ctSateMask connection tracking sate masking value
124 * @return OVS ConnTrack extension match
125 */
126 public static ExtensionSelector buildCtExtensionSelector(DriverService driverService,
127 DeviceId deviceId,
128 long ctState,
129 long ctSateMask) {
130 DriverHandler handler = driverService.createHandler(deviceId);
131 ExtensionSelectorResolver esr = handler.behaviour(ExtensionSelectorResolver.class);
132
133 ExtensionSelector extensionSelector = esr.getExtensionSelector(
134 ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_CONNTRACK_STATE.type());
135 try {
136 extensionSelector.setPropertyValue(CT_STATE, ctState);
137 extensionSelector.setPropertyValue(CT_STATE_MASK, ctSateMask);
138 } catch (Exception e) {
139 log.error("Failed to set nicira match CT state because of {}", e);
140 return null;
141 }
142
143 return extensionSelector;
144 }
145
146 /**
147 * Computes ConnTack State flag values.
148 *
149 * @param isTracking true for +trk, false for -trk
150 * @param isNew true for +new, false for -new
151 * @param isEstablished true for +est, false for -est
152 * @return ConnTrack State flags
153 */
154 public static long computeCtStateFlag(boolean isTracking,
155 boolean isNew,
156 boolean isEstablished) {
157 long ctStateFlag = 0x00;
158
159 if (isTracking) {
160 ctStateFlag = ctStateFlag | CT_STATE_TRK;
161 }
162
163 if (isNew) {
164 ctStateFlag = ctStateFlag | CT_STATE_TRK;
165 ctStateFlag = ctStateFlag | CT_STATE_NEW;
166 }
167
168 if (isEstablished) {
169 ctStateFlag = ctStateFlag | CT_STATE_TRK;
170 ctStateFlag = ctStateFlag | CT_STATE_EST;
171 }
172
173 return ctStateFlag;
174 }
175
176 /**
177 * Computes ConnTrack State mask values.
178 *
179 * @param isTracking true for setting +trk/-trk value, false for otherwise
180 * @param isNew true for setting +new/-new value, false for otherwise
181 * @param isEstablished true for setting +est/-est value, false for otherwise
182 * @return ConnTrack State Mask value
183 */
184 public static long computeCtMaskFlag(boolean isTracking,
185 boolean isNew,
186 boolean isEstablished) {
187 long ctMaskFlag = 0x00;
188
189 if (isTracking) {
190 ctMaskFlag = ctMaskFlag | CT_STATE_TRK;
191 }
192
193 if (isNew) {
194 ctMaskFlag = ctMaskFlag | CT_STATE_TRK;
195 ctMaskFlag = ctMaskFlag | CT_STATE_NEW;
196 }
197
198 if (isEstablished) {
199 ctMaskFlag = ctMaskFlag | CT_STATE_TRK;
200 ctMaskFlag = ctMaskFlag | CT_STATE_EST;
201 }
202
203 return ctMaskFlag;
204 }
205
206 /**
Jian Li4aa17642019-01-30 00:01:11 +0900207 * Returns tunnel destination extension treatment object.
208 *
209 * @param deviceService driver service
210 * @param deviceId device id to apply this treatment
211 * @param remoteIp tunnel destination ip address
212 * @return extension treatment
213 */
214 public static ExtensionTreatment buildExtension(DeviceService deviceService,
215 DeviceId deviceId,
216 Ip4Address remoteIp) {
217 Device device = deviceService.getDevice(deviceId);
218 if (device != null && !device.is(ExtensionTreatmentResolver.class)) {
219 log.error("The extension treatment is not supported");
220 return null;
221 }
222
223 if (device == null) {
224 return null;
225 }
226
227 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
228 ExtensionTreatment treatment =
229 resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
230 try {
231 treatment.setPropertyValue(TUNNEL_DST, remoteIp);
232 return treatment;
233 } catch (ExtensionPropertyException e) {
234 log.warn("Failed to get tunnelDst extension treatment for {} " +
235 "because of {}", deviceId, e);
236 return null;
237 }
238 }
Jian Li2cc2b632019-02-18 00:56:40 +0900239
240 /**
241 * Returns the group bucket with given traffic treatment and group type.
242 *
243 * @param treatment traffic treatment
244 * @param type group type
245 * @param weight weight (only for select type)
246 * @return group bucket
247 */
248 public static GroupBucket buildGroupBucket(TrafficTreatment treatment,
249 Type type, short weight) {
250 switch (type) {
251 case ALL:
252 return DefaultGroupBucket.createAllGroupBucket(treatment);
253 case SELECT:
254 if (weight == -1) {
255 return DefaultGroupBucket.createSelectGroupBucket(treatment);
256 } else {
257 return DefaultGroupBucket.createSelectGroupBucket(treatment, weight);
258 }
259 case INDIRECT:
260 return DefaultGroupBucket.createIndirectGroupBucket(treatment);
261 default:
262 return null;
263 }
264 }
265
266 /**
267 * Returns the nicira resubmit extension treatment with given table ID.
268 *
Jian Li004526d2019-02-25 16:26:27 +0900269 * @param device device instance
Jian Li2cc2b632019-02-18 00:56:40 +0900270 * @param tableId table identifier
271 * @return resubmit extension treatment
272 */
273 public static ExtensionTreatment buildResubmitExtension(Device device, int tableId) {
274 if (device == null || !device.is(ExtensionTreatmentResolver.class)) {
275 log.warn("Nicira extension treatment is not supported");
276 return null;
277 }
278
279 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
280 ExtensionTreatment treatment =
281 resolver.getExtensionInstruction(NICIRA_RESUBMIT_TABLE.type());
282
283 try {
284 treatment.setPropertyValue(TABLE_EXTENSION, ((short) tableId));
285 return treatment;
286 } catch (ExtensionPropertyException e) {
287 log.error("Failed to set nicira resubmit extension treatment for {}",
288 device.id());
289 return null;
290 }
291 }
292
293 /**
Jian Li004526d2019-02-25 16:26:27 +0900294 * Returns the nicira load extension treatment.
295 *
296 * @param device device instance
297 * @param ipType IP type (src|dst)
298 * @param shift shift (e.g., 10.10., 20.20.,)
299 * @return load extension treatment
300 */
301 public static ExtensionTreatment buildLoadExtension(Device device,
302 String ipType,
303 String shift) {
304 if (device == null || !device.is(ExtensionTreatmentResolver.class)) {
305 log.warn("Nicira extension treatment is not supported");
306 return null;
307 }
308
309 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
310 ExtensionTreatment treatment =
311 resolver.getExtensionInstruction(NICIRA_LOAD.type());
312
313 long dst = 0L;
314
315 if (SRC.equalsIgnoreCase(ipType)) {
316 dst = SRC_IP;
317 } else if (DST.equals(ipType)) {
318 dst = DST_IP;
319 }
320
321 long value = calculateUpperBit(shift);
322
323 // we only rewrite the upper 16 bits with value (A.B.X.Y -> C.D.X.Y)
324 int ofsNbits = OFF_SET_BIT << 6 | (REMAINDER_BIT - 1);
325
326 try {
327 treatment.setPropertyValue(OFF_SET_N_BITS, ofsNbits);
328 treatment.setPropertyValue(DESTINATION, dst);
329 treatment.setPropertyValue(VALUE, value);
330 return treatment;
331 } catch (ExtensionPropertyException e) {
332 log.error("Failed to set nicira load extension treatment for {}",
333 device.id());
334 return null;
335 }
336 }
337
338 /**
339 * Calculate IP address upper string into integer.
340 *
341 * @param shift IP address upper two octets with dot
342 * @return calculated integer
343 */
344 private static int calculateUpperBit(String shift) {
345 String[] strArray = shift.split("\\.");
346
347 int firstOctet = Integer.valueOf(strArray[0]);
348 int secondOctet = Integer.valueOf(strArray[1]);
349
350 return firstOctet << 8 | secondOctet;
351 }
352
353 /**
Jian Li2cc2b632019-02-18 00:56:40 +0900354 * Builder class for OVS Connection Tracking feature actions.
355 */
356 public static final class NiciraConnTrackTreatmentBuilder {
357
358 private DriverService driverService;
359 private DeviceId deviceId;
360 private IpAddress natAddress = null;
361 private TpPort natPort = null;
362 private int zone;
363 private boolean commit;
364 private short table = -1;
365 private boolean natAction;
366 private int natFlag;
367
368 // private constructor
369 private NiciraConnTrackTreatmentBuilder(DriverService driverService,
370 DeviceId deviceId) {
371 this.driverService = driverService;
372 this.deviceId = deviceId;
373 }
374
375 /**
376 * Sets commit flag.
377 *
378 * @param c true if commit, false if not.
379 * @return NiciraConnTrackTreatmentBuilder object
380 */
381 public NiciraConnTrackTreatmentBuilder commit(boolean c) {
382 this.commit = c;
383 return this;
384 }
385
386 /**
387 * Sets zone number.
388 *
389 * @param z zone number
390 * @return NiciraConnTrackTreatmentBuilder object
391 */
392 public NiciraConnTrackTreatmentBuilder zone(int z) {
393 this.zone = z;
394 return this;
395 }
396
397 /**
398 * Sets recirculation table number.
399 *
400 * @param t table number to restart
401 * @return NiciraConnTrackTreatmentBuilder object
402 */
403 public NiciraConnTrackTreatmentBuilder table(short t) {
404 this.table = t;
405 return this;
406 }
407
408 /**
409 * Sets IP address for NAT.
410 *
411 * @param ip NAT IP address
412 * @return NiciraConnTrackTreatmentBuilder object
413 */
414 public NiciraConnTrackTreatmentBuilder natIp(IpAddress ip) {
415 this.natAddress = ip;
416 return this;
417 }
418
419 /**
420 * Sets port for NAT.
421 *
422 * @param port port number
423 * @return NiciraConnTrackTreatmentBuilder object
424 */
425 public NiciraConnTrackTreatmentBuilder natPort(TpPort port) {
426 this.natPort = port;
427 return this;
428 }
429
430 /**
431 * Sets NAT flags.
432 * SRC NAT: 1 << 0
433 * DST NAT: 1 << 1
434 * PERSISTENT NAT: 1 << 2
435 * PROTO_HASH NAT: 1 << 3
436 * PROTO_RANDOM NAT : 1 << 4
437 *
438 * @param flag flag value
439 * @return NiciraConnTrackTreatmentBuilder object
440 */
441 public NiciraConnTrackTreatmentBuilder natFlag(int flag) {
442 this.natFlag = 1 << flag;
443 return this;
444 }
445
446 /**
447 * Sets the flag for NAT action.
448 *
449 * @param nat nat action is included if true, no nat action otherwise
450 * @return NiciraConnTrackTreatmentBuilder object
451 */
452 public NiciraConnTrackTreatmentBuilder natAction(boolean nat) {
453 this.natAction = nat;
454 return this;
455 }
456
457 /**
458 * Builds extension treatment for OVS ConnTack and NAT feature.
459 *
460 * @return ExtensionTreatment object
461 */
462 public ExtensionTreatment build() {
463 DriverHandler handler = driverService.createHandler(deviceId);
464 ExtensionTreatmentResolver etr =
465 handler.behaviour(ExtensionTreatmentResolver.class);
466
467 ExtensionTreatment natTreatment = etr.getExtensionInstruction(
468 ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_NAT.type());
469 try {
470
471 natTreatment.setPropertyValue(CT_FLAGS, this.natFlag);
472
473 natTreatment.setPropertyValue(CT_PRESENT_FLAGS,
474 buildPresentFlag(natPort != null, natAddress != null));
475
476 if (natAddress != null) {
477 natTreatment.setPropertyValue(CT_IPADDRESS_MIN, natAddress);
478 natTreatment.setPropertyValue(CT_IPADDRESS_MAX, natAddress);
479 }
480
481 if (natPort != null) {
482 natTreatment.setPropertyValue(CT_PORT_MIN, natPort.toInt());
483 natTreatment.setPropertyValue(CT_PORT_MAX, natPort.toInt());
484 }
485
486 } catch (Exception e) {
487 log.error("Failed to set NAT due to error : {}", e);
488 return null;
489 }
490
491 ExtensionTreatment ctTreatment = etr.getExtensionInstruction(
492 ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_CT.type());
493 try {
494 List<ExtensionTreatment> nat = new ArrayList<>();
495 if (natAction) {
496 nat.add(natTreatment);
497 }
498 ctTreatment.setPropertyValue(CT_FLAGS, commit ? 1 : 0);
499 ctTreatment.setPropertyValue(CT_ZONE, zone);
500 ctTreatment.setPropertyValue(CT_TABLE, table > -1 ? table : 0xff);
501 ctTreatment.setPropertyValue(CT_NESTED_ACTIONS, nat);
502 } catch (Exception e) {
503 log.error("Failed to set CT due to error : {}", e);
504 return null;
505 }
506
507 return ctTreatment;
508 }
509
510 private int buildPresentFlag(boolean isPortPresent, boolean isAddressPresent) {
511
512 int presentFlag = 0;
513
514 if (isPortPresent) {
515 presentFlag = 1 << PORT_MIN_FLAG | 1 << PORT_MAX_FLAG;
516 }
517
518 if (isAddressPresent) {
519 // TODO: need to support IPv6 address
520 presentFlag = presentFlag | 1 << ADDRESS_V4_MIN_FLAG | 1 << ADDRESS_V4_MAX_FLAG;
521 }
522
523 return presentFlag;
524 }
525 }
Jian Li4aa17642019-01-30 00:01:11 +0900526}