2 * BIRD Library -- Flow specification (RFC 5575)
4 * (c) 2016 CZ.NIC z.s.p.o.
6 * Can be freely distributed and used under the terms of the GNU GPL.
10 * DOC: Flow specification (flowspec)
12 * Flowspec are rules (RFC 5575) for firewalls disseminated using BGP protocol.
13 * The |flowspec.c| is a library for handling flowspec binary streams and
14 * flowspec data structures. You will find there functions for validation
15 * incoming flowspec binary streams, iterators for jumping over components,
16 * functions for handling a length and functions for formatting flowspec data
17 * structure into user-friendly text representation.
19 * In this library, you will find also flowspec builder. In |confbase.Y|, there
20 * are grammar's rules for parsing and building new flowspec data structure
21 * from BIRD's configuration files and from BIRD's command line interface.
22 * Finalize function will assemble final &net_addr_flow4 or &net_addr_flow6
25 * The data structures &net_addr_flow4 and &net_addr_flow6 are defined in
26 * |net.h| file. The attribute length is size of whole data structure plus
27 * binary stream representation of flowspec including a compressed encoded
30 * Sometimes in code, it is used expression flowspec type, it should mean
31 * flowspec component type.
34 #include "nest/bird.h"
35 #include "lib/flowspec.h"
36 #include "conf/conf.h"
39 static const char* flow4_type_str
[] = {
40 [FLOW_TYPE_DST_PREFIX
] = "dst",
41 [FLOW_TYPE_SRC_PREFIX
] = "src",
42 [FLOW_TYPE_IP_PROTOCOL
] = "proto",
43 [FLOW_TYPE_PORT
] = "port",
44 [FLOW_TYPE_DST_PORT
] = "dport",
45 [FLOW_TYPE_SRC_PORT
] = "sport",
46 [FLOW_TYPE_ICMP_TYPE
] = "icmp type",
47 [FLOW_TYPE_ICMP_CODE
] = "icmp code",
48 [FLOW_TYPE_TCP_FLAGS
] = "tcp flags",
49 [FLOW_TYPE_PACKET_LENGTH
] = "length",
50 [FLOW_TYPE_DSCP
] = "dscp",
51 [FLOW_TYPE_FRAGMENT
] = "fragment"
54 static const char* flow6_type_str
[] = {
55 [FLOW_TYPE_DST_PREFIX
] = "dst",
56 [FLOW_TYPE_SRC_PREFIX
] = "src",
57 [FLOW_TYPE_NEXT_HEADER
] = "next header",
58 [FLOW_TYPE_PORT
] = "port",
59 [FLOW_TYPE_DST_PORT
] = "dport",
60 [FLOW_TYPE_SRC_PORT
] = "sport",
61 [FLOW_TYPE_ICMP_TYPE
] = "icmp type",
62 [FLOW_TYPE_ICMP_CODE
] = "icmp code",
63 [FLOW_TYPE_TCP_FLAGS
] = "tcp flags",
64 [FLOW_TYPE_PACKET_LENGTH
] = "length",
65 [FLOW_TYPE_DSCP
] = "dscp",
66 [FLOW_TYPE_FRAGMENT
] = "fragment",
67 [FLOW_TYPE_LABEL
] = "label"
71 * flow_type_str - get stringified flowspec name of component
72 * @type: flowspec component type
73 * @ipv6: IPv4/IPv6 decide flag, use zero for IPv4 and one for IPv6
75 * This function returns flowspec name of component @type in string.
78 flow_type_str(enum flow_type type
, int ipv6
)
80 return ipv6
? flow6_type_str
[type
] : flow4_type_str
[type
];
88 * flow_write_length - write compressed length value
89 * @data: destination buffer to write
90 * @len: the value of the length (0 to 0xfff) for writing
92 * This function writes appropriate as (1- or 2-bytes) the value of @len into
93 * buffer @data. The function returns number of written bytes, thus 1 or 2 bytes.
96 flow_write_length(byte
*data
, u16 len
)
100 put_u16(data
, len
| 0xf000);
109 get_value_length(const byte
*op
)
111 return (1 << ((*op
& 0x30) >> 4));
119 static inline u8
num_op(const byte
*op
) { return (*op
& 0x07); }
120 static inline int isset_and(const byte
*op
) { return ((*op
& 0x40) == 0x40); }
121 static inline int isset_end(const byte
*op
) { return ((*op
& 0x80) == 0x80); }
124 flow_first_part(const byte
*data
)
126 if (!data
|| flow_read_length(data
) == 0)
129 /* It is allowed to encode the value of length less then 240 into 2-bytes too */
130 if ((data
[0] & 0xf0) == 0xf0)
137 * flow4_first_part - get position of the first flowspec component
138 * @f: flowspec data structure &net_addr_flow4
140 * This function return a position to the beginning of the first flowspec
141 * component in IPv4 flowspec @f.
144 flow4_first_part(const net_addr_flow4
*f
)
146 return f
? flow_first_part(f
->data
) : NULL
;
150 * flow6_first_part - get position of the first flowspec component
151 * @f: flowspec data structure &net_addr_flow6
153 * This function return a position to the beginning of the first flowspec
154 * component in IPv6 flowspec @f.
157 flow6_first_part(const net_addr_flow6
*f
)
159 return f
? flow_first_part(f
->data
) : NULL
;
163 flow_next_part(const byte
*pos
, const byte
*end
, int ipv6
)
167 case FLOW_TYPE_DST_PREFIX
:
168 case FLOW_TYPE_SRC_PREFIX
:
171 uint bytes
= BYTES(pxlen
);
174 uint offset
= *pos
++ / 8;
175 pos
+= bytes
- offset
;
184 case FLOW_TYPE_IP_PROTOCOL
: /* == FLOW_TYPE_NEXT_HEADER */
186 case FLOW_TYPE_DST_PORT
:
187 case FLOW_TYPE_SRC_PORT
:
188 case FLOW_TYPE_ICMP_TYPE
:
189 case FLOW_TYPE_ICMP_CODE
:
190 case FLOW_TYPE_TCP_FLAGS
:
191 case FLOW_TYPE_PACKET_LENGTH
:
193 case FLOW_TYPE_FRAGMENT
:
194 case FLOW_TYPE_LABEL
:
196 /* Is this the end of list operator-value pair? */
201 last
= isset_end(pos
);
203 /* Value length of operator */
204 uint len
= get_value_length(pos
);
213 return (pos
< end
) ? pos
: NULL
;
217 * flow4_next_part - an iterator over flowspec components in flowspec binary stream
218 * @pos: the beginning of a previous or the first component in flowspec binary
220 * @end: the last valid byte in scanned flowspec binary stream
222 * This function returns a position to the beginning of the next component
223 * (to a component type byte) in flowspec binary stream or %NULL for the end.
226 flow4_next_part(const byte
*pos
, const byte
*end
)
228 return flow_next_part(pos
, end
, 0);
232 * flow6_next_part - an iterator over flowspec components in flowspec binary stream
233 * @pos: the beginning of a previous or the first component in flowspec binary
235 * @end: the last valid byte in scanned flowspec binary stream
237 * This function returns a position to the beginning of the next component
238 * (to a component type byte) in flowspec binary stream or %NULL for the end.
241 flow6_next_part(const byte
*pos
, const byte
*end
)
243 return flow_next_part(pos
, end
, 1);
247 flow_get_part(const byte
*data
, uint dlen
, uint type
, int ipv6
)
251 for (part
= flow_first_part(data
);
252 part
&& (part
[0] <= type
);
253 part
= flow_next_part(part
, data
+dlen
, ipv6
))
261 flow4_get_part(const net_addr_flow4
*f
, uint type
)
263 return flow_get_part(f
->data
, f
->length
- sizeof(net_addr_flow4
), type
, 0);
267 flow6_get_part(const net_addr_flow6
*f
, uint type
)
269 return flow_get_part(f
->data
, f
->length
- sizeof(net_addr_flow6
), type
, 1);
277 static inline ip4_addr
278 flow_read_ip4(const byte
*px
, uint pxlen
)
280 ip4_addr ip
= IP4_NONE
;
281 memcpy(&ip
, px
, BYTES(pxlen
));
286 flow_read_ip4_part(const byte
*part
)
288 return flow_read_ip4(part
+ 2, part
[1]);
291 static inline ip6_addr
292 flow_read_ip6(const byte
*px
, uint pxlen
, uint pxoffset
)
294 uint floor_offset
= BYTES(pxoffset
- (pxoffset
% 8));
295 uint ceil_len
= BYTES(pxlen
);
296 ip6_addr ip
= IP6_NONE
;
298 memcpy(((byte
*) &ip
) + floor_offset
, px
, ceil_len
- floor_offset
);
304 flow_read_ip6_part(const byte
*part
)
306 return flow_read_ip6(part
+ 3, part
[1], part
[2]);
311 * Flowspec validation
314 static const char* flow_validated_state_str_
[] = {
315 [FLOW_ST_UNKNOWN_COMPONENT
] = "Unknown component",
316 [FLOW_ST_VALID
] = "Valid",
317 [FLOW_ST_NOT_COMPLETE
] = "Not complete",
318 [FLOW_ST_EXCEED_MAX_PREFIX_LENGTH
] = "Exceed maximal prefix length",
319 [FLOW_ST_EXCEED_MAX_PREFIX_OFFSET
] = "Exceed maximal prefix offset",
320 [FLOW_ST_EXCEED_MAX_VALUE_LENGTH
] = "Exceed maximal value length",
321 [FLOW_ST_BAD_TYPE_ORDER
] = "Bad component order",
322 [FLOW_ST_AND_BIT_SHOULD_BE_UNSET
] = "The AND-bit should be unset",
323 [FLOW_ST_ZERO_BIT_SHOULD_BE_UNSED
] = "The Zero-bit should be unset",
324 [FLOW_ST_DEST_PREFIX_REQUIRED
] = "Destination prefix is missing",
325 [FLOW_ST_INVALID_TCP_FLAGS
] = "TCP flags exceeding 0xfff",
326 [FLOW_ST_CANNOT_USE_DONT_FRAGMENT
] = "Cannot use Don't fragment flag in IPv6 flow"
330 * flow_validated_state_str - return a textual description of validation process
331 * @code: validation result
333 * This function return well described validation state in string.
336 flow_validated_state_str(enum flow_validated_state code
)
338 return flow_validated_state_str_
[code
];
341 static const u8 flow4_max_value_length
[] = {
342 [FLOW_TYPE_DST_PREFIX
] = 0,
343 [FLOW_TYPE_SRC_PREFIX
] = 0,
344 [FLOW_TYPE_IP_PROTOCOL
] = 1,
345 [FLOW_TYPE_PORT
] = 2,
346 [FLOW_TYPE_DST_PORT
] = 2,
347 [FLOW_TYPE_SRC_PORT
] = 2,
348 [FLOW_TYPE_ICMP_TYPE
] = 1,
349 [FLOW_TYPE_ICMP_CODE
] = 1,
350 [FLOW_TYPE_TCP_FLAGS
] = 2,
351 [FLOW_TYPE_PACKET_LENGTH
] = 2,
352 [FLOW_TYPE_DSCP
] = 1,
353 [FLOW_TYPE_FRAGMENT
] = 1 /* XXX */
356 static const u8 flow6_max_value_length
[] = {
357 [FLOW_TYPE_DST_PREFIX
] = 0,
358 [FLOW_TYPE_SRC_PREFIX
] = 0,
359 [FLOW_TYPE_NEXT_HEADER
] = 1,
360 [FLOW_TYPE_PORT
] = 2,
361 [FLOW_TYPE_DST_PORT
] = 2,
362 [FLOW_TYPE_SRC_PORT
] = 2,
363 [FLOW_TYPE_ICMP_TYPE
] = 1,
364 [FLOW_TYPE_ICMP_CODE
] = 1,
365 [FLOW_TYPE_TCP_FLAGS
] = 2,
366 [FLOW_TYPE_PACKET_LENGTH
] = 2,
367 [FLOW_TYPE_DSCP
] = 1,
368 [FLOW_TYPE_FRAGMENT
] = 1, /* XXX */
369 [FLOW_TYPE_LABEL
] = 4
373 flow_max_value_length(enum flow_type type
, int ipv6
)
375 return ipv6
? flow6_max_value_length
[type
] : flow4_max_value_length
[type
];
379 * flow_check_cf_bmk_values - check value/bitmask part of flowspec component
380 * @fb: flow builder instance
381 * @neg: negation operand
382 * @val: value from value/mask pair
383 * @mask: bitmap mask from value/mask pair
385 * This function checks value/bitmask pair. If some problem will appear, the
386 * function calls cf_error() function with a textual description of reason
387 * to failing of validation.
390 flow_check_cf_bmk_values(struct flow_builder
*fb
, u8 neg
, u32 val
, u32 mask
)
392 flow_check_cf_value_length(fb
, val
);
393 flow_check_cf_value_length(fb
, mask
);
395 if (neg
&& !(val
== 0 || val
== mask
))
396 cf_error("For negation, value must be zero or bitmask");
398 if ((fb
->this_type
== FLOW_TYPE_TCP_FLAGS
) && (mask
& 0xf000))
399 cf_error("Invalid mask 0x%x, must not exceed 0xfff", mask
);
401 if ((fb
->this_type
== FLOW_TYPE_FRAGMENT
) && fb
->ipv6
&& (mask
& 0x01))
402 cf_error("Invalid mask 0x%x, bit 0 must be 0", mask
);
405 cf_error("Value 0x%x outside bitmask 0x%x", val
, mask
);
409 * flow_check_cf_value_length - check value by flowspec component type
410 * @fb: flow builder instance
413 * This function checks if the value is in range of component's type support.
414 * If some problem will appear, the function calls cf_error() function with
415 * a textual description of reason to failing of validation.
418 flow_check_cf_value_length(struct flow_builder
*fb
, u32 val
)
420 enum flow_type t
= fb
->this_type
;
421 u8 max
= flow_max_value_length(t
, fb
->ipv6
);
423 if (t
== FLOW_TYPE_DSCP
&& val
> 0x3f)
424 cf_error("%s value %u out of range (0-63)", flow_type_str(t
, fb
->ipv6
), val
);
426 if (max
== 1 && (val
> 0xff))
427 cf_error("%s value %u out of range (0-255)", flow_type_str(t
, fb
->ipv6
), val
);
429 if (max
== 2 && (val
> 0xffff))
430 cf_error("%s value %u out of range (0-65535)", flow_type_str(t
, fb
->ipv6
), val
);
433 static enum flow_validated_state
434 flow_validate(const byte
*nlri
, uint len
, int ipv6
)
436 enum flow_type type
= 0;
437 const byte
*pos
= nlri
;
438 const byte
*end
= nlri
+ len
;
443 /* Check increasing type ordering */
445 return FLOW_ST_BAD_TYPE_ORDER
;
450 case FLOW_TYPE_DST_PREFIX
:
453 case FLOW_TYPE_SRC_PREFIX
:
456 if (pxlen
> (ipv6
? IP6_MAX_PREFIX_LENGTH
: IP4_MAX_PREFIX_LENGTH
))
457 return FLOW_ST_EXCEED_MAX_PREFIX_LENGTH
;
459 uint bytes
= BYTES(pxlen
);
462 uint pxoffset
= *pos
++;
463 if (pxoffset
> IP6_MAX_PREFIX_LENGTH
|| pxoffset
> pxlen
)
464 return FLOW_ST_EXCEED_MAX_PREFIX_OFFSET
;
465 bytes
-= pxoffset
/ 8;
472 case FLOW_TYPE_LABEL
:
474 return FLOW_ST_UNKNOWN_COMPONENT
;
476 case FLOW_TYPE_IP_PROTOCOL
: /* == FLOW_TYPE_NEXT_HEADER */
478 case FLOW_TYPE_DST_PORT
:
479 case FLOW_TYPE_SRC_PORT
:
480 case FLOW_TYPE_ICMP_TYPE
:
481 case FLOW_TYPE_ICMP_CODE
:
482 case FLOW_TYPE_TCP_FLAGS
:
483 case FLOW_TYPE_PACKET_LENGTH
:
485 case FLOW_TYPE_FRAGMENT
:
494 * +---+---+---+---+---+---+---+---+
495 * | e | a | len | 0 |lt |gt |eq |
496 * +---+---+---+---+---+---+---+---+
501 last
= isset_end(pos
);
503 /* The AND bit should in the first operator byte of a sequence */
504 if (first
&& isset_and(pos
))
505 return FLOW_ST_AND_BIT_SHOULD_BE_UNSET
;
507 /* This bit should be zero */
509 return FLOW_ST_ZERO_BIT_SHOULD_BE_UNSED
;
511 if (type
== FLOW_TYPE_TCP_FLAGS
|| type
== FLOW_TYPE_FRAGMENT
)
515 * +---+---+---+---+---+---+---+---+
516 * | e | a | len | 0 | 0 |not| m |
517 * +---+---+---+---+---+---+---+---+
522 return FLOW_ST_ZERO_BIT_SHOULD_BE_UNSED
;
525 /* Value length of operator */
526 uint len
= get_value_length(pos
);
527 if (len
> flow_max_value_length(type
, ipv6
))
528 return FLOW_ST_EXCEED_MAX_VALUE_LENGTH
;
530 /* TCP Flags component must not check highest nibble (just 12 valid bits) */
531 if ((type
== FLOW_TYPE_TCP_FLAGS
) && (len
== 2) && (pos
[1] & 0xf0))
532 return FLOW_ST_INVALID_TCP_FLAGS
;
534 /* Bit-7 must be 0 [draft-ietf-idr-flow-spec-v6] */
535 if ((type
== FLOW_TYPE_FRAGMENT
) && ipv6
&& (pos
[1] & 0x01))
536 return FLOW_ST_CANNOT_USE_DONT_FRAGMENT
;
537 /* XXX: Could be a fragment component encoded in 2-bytes? */
541 if (pos
> end
&& !last
)
542 return FLOW_ST_NOT_COMPLETE
;
545 return FLOW_ST_NOT_COMPLETE
;
552 return FLOW_ST_UNKNOWN_COMPONENT
;
557 return FLOW_ST_NOT_COMPLETE
;
559 if (!ipv6
&& !met_dst_pfx
)
560 return FLOW_ST_DEST_PREFIX_REQUIRED
;
562 return FLOW_ST_VALID
;
566 * flow4_validate - check untrustworthy IPv4 flowspec data stream
567 * @nlri: flowspec data stream without compressed encoded length value
568 * @len: length of @nlri
570 * This function checks meaningfulness of binary flowspec. It should return
571 * %FLOW_ST_VALID or %FLOW_ST_UNKNOWN_COMPONENT. If some problem appears, it
572 * returns some other %FLOW_ST_xxx state.
574 inline enum flow_validated_state
575 flow4_validate(const byte
*nlri
, uint len
)
577 return flow_validate(nlri
, len
, 0);
581 * flow6_validate - check untrustworthy IPv6 flowspec data stream
582 * @nlri: flowspec binary stream without encoded length value
583 * @len: length of @nlri
585 * This function checks meaningfulness of binary flowspec. It should return
586 * %FLOW_ST_VALID or %FLOW_ST_UNKNOWN_COMPONENT. If some problem appears, it
587 * returns some other %FLOW_ST_xxx state.
589 inline enum flow_validated_state
590 flow6_validate(const byte
*nlri
, uint len
)
592 return flow_validate(nlri
, len
, 1);
596 * flow4_validate_cf - validate flowspec data structure &net_addr_flow4 in parsing time
597 * @f: flowspec data structure &net_addr_flow4
599 * Check if @f is valid flowspec data structure. Can call cf_error() function
600 * with a textual description of reason to failing of validation.
603 flow4_validate_cf(net_addr_flow4
*f
)
605 enum flow_validated_state r
= flow4_validate(flow4_first_part(f
), flow_read_length(f
->data
));
607 if (r
!= FLOW_ST_VALID
)
608 cf_error("Invalid flow route: %s", flow_validated_state_str(r
));
612 * flow6_validate_cf - validate flowspec data structure &net_addr_flow6 in parsing time
613 * @f: flowspec data structure &net_addr_flow6
615 * Check if @f is valid flowspec data structure. Can call cf_error() function
616 * with a textual description of reason to failing of validation.
619 flow6_validate_cf(net_addr_flow6
*f
)
621 enum flow_validated_state r
= flow6_validate(flow6_first_part(f
), flow_read_length(f
->data
));
623 if (r
!= FLOW_ST_VALID
)
624 cf_error("Invalid flow route: %s", flow_validated_state_str(r
));
633 * flow_builder_init - constructor for flowspec builder instance
636 * This function prepares flowspec builder instance using memory pool @pool.
638 struct flow_builder
*
639 flow_builder_init(pool
*pool
)
641 struct flow_builder
*fb
= mb_allocz(pool
, sizeof(struct flow_builder
));
642 BUFFER_INIT(fb
->data
, pool
, 4);
647 is_stackable_type(enum flow_type type
)
651 case FLOW_TYPE_IP_PROTOCOL
:
653 case FLOW_TYPE_DST_PORT
:
654 case FLOW_TYPE_SRC_PORT
:
655 case FLOW_TYPE_ICMP_TYPE
:
656 case FLOW_TYPE_ICMP_CODE
:
657 case FLOW_TYPE_TCP_FLAGS
:
658 case FLOW_TYPE_PACKET_LENGTH
:
660 case FLOW_TYPE_FRAGMENT
:
661 case FLOW_TYPE_LABEL
:
665 /* The unknown components are not stack-able in default */
671 builder_add_prepare(struct flow_builder
*fb
)
673 if (fb
->parts
[fb
->this_type
].length
)
675 if (fb
->last_type
!= fb
->this_type
)
678 if (!is_stackable_type(fb
->this_type
))
683 fb
->parts
[fb
->this_type
].offset
= fb
->data
.used
;
690 builder_add_finish(struct flow_builder
*fb
)
692 fb
->parts
[fb
->this_type
].length
= fb
->data
.used
- fb
->parts
[fb
->this_type
].offset
;
693 flow_builder_set_type(fb
, fb
->this_type
);
697 push_pfx_to_buffer(struct flow_builder
*fb
, u8 pxlen_bytes
, byte
*ip
)
699 for (int i
= 0; i
< pxlen_bytes
; i
++)
700 BUFFER_PUSH(fb
->data
) = *ip
++;
704 * flow_builder4_add_pfx - add IPv4 prefix
705 * @fb: flowspec builder instance
706 * @n4: net address of type IPv4
708 * This function add IPv4 prefix into flowspec builder instance.
711 flow_builder4_add_pfx(struct flow_builder
*fb
, const net_addr_ip4
*n4
)
713 if (!builder_add_prepare(fb
))
716 ip4_addr ip4
= ip4_hton(n4
->prefix
);
718 BUFFER_PUSH(fb
->data
) = fb
->this_type
;
719 BUFFER_PUSH(fb
->data
) = n4
->pxlen
;
720 push_pfx_to_buffer(fb
, BYTES(n4
->pxlen
), (byte
*) &ip4
);
722 builder_add_finish(fb
);
727 * flow_builder6_add_pfx - add IPv6 prefix
728 * @fb: flowspec builder instance
729 * @n6: net address of type IPv4
730 * @pxoffset: prefix offset for @n6
732 * This function add IPv4 prefix into flowspec builder instance. This function
733 * should return 1 for successful adding, otherwise returns %0.
736 flow_builder6_add_pfx(struct flow_builder
*fb
, const net_addr_ip6
*n6
, u32 pxoffset
)
738 if (!builder_add_prepare(fb
))
741 ip6_addr ip6
= ip6_hton(n6
->prefix
);
743 BUFFER_PUSH(fb
->data
) = fb
->this_type
;
744 BUFFER_PUSH(fb
->data
) = n6
->pxlen
;
745 BUFFER_PUSH(fb
->data
) = pxoffset
;
746 push_pfx_to_buffer(fb
, BYTES(n6
->pxlen
) - (pxoffset
/ 8), ((byte
*) &ip6
) + (pxoffset
/ 8));
748 builder_add_finish(fb
);
753 * flow_builder_add_op_val - add operator/value pair
754 * @fb: flowspec builder instance
758 * This function add operator/value pair as a part of a flowspec component. It
759 * is required to set appropriate flowspec component type using function
760 * flow_builder_set_type(). This function should return 1 for successful
761 * adding, otherwise returns 0.
764 flow_builder_add_op_val(struct flow_builder
*fb
, byte op
, u32 value
)
766 if (!builder_add_prepare(fb
))
769 if (fb
->this_type
== fb
->last_type
)
771 /* Remove the end-bit from last operand-value pair of the component */
772 fb
->data
.data
[fb
->last_op_offset
] &= 0x7f;
776 BUFFER_PUSH(fb
->data
) = fb
->this_type
;
779 fb
->last_op_offset
= fb
->data
.used
;
781 /* Set the end-bit for operand-value pair of the component */
786 BUFFER_PUSH(fb
->data
) = op
| 0x10;
787 put_u16(BUFFER_INC(fb
->data
, 2), value
);
791 BUFFER_PUSH(fb
->data
) = op
;
792 BUFFER_PUSH(fb
->data
) = (u8
) value
;
795 builder_add_finish(fb
);
800 * flow_builder_add_val_mask - add value/bitmask pair
801 * @fb: flowspec builder instance
806 * It is required to set appropriate flowspec component type using function
807 * flow_builder_set_type(). This function should return 1 for successful adding,
808 * otherwise returns 0.
811 flow_builder_add_val_mask(struct flow_builder
*fb
, byte op
, u32 value
, u32 mask
)
813 u32 a
= value
& mask
;
814 u32 b
= ~value
& mask
;
818 flow_builder_add_op_val(fb
, op
^ 0x01, a
);
823 flow_builder_add_op_val(fb
, op
^ 0x02, b
);
830 * flow_builder_set_type - set type of next flowspec component
831 * @fb: flowspec builder instance
832 * @type: flowspec component type
834 * This function sets type of next flowspec component. It is necessary to call
835 * this function before each changing of adding flowspec component.
838 flow_builder_set_type(struct flow_builder
*fb
, enum flow_type type
)
840 fb
->last_type
= fb
->this_type
;
841 fb
->this_type
= type
;
845 builder_write_parts(struct flow_builder
*fb
, byte
*buf
)
847 for (int i
= 1; i
< FLOW_TYPE_MAX
; i
++)
849 if (fb
->parts
[i
].length
)
851 memcpy(buf
, fb
->data
.data
+ fb
->parts
[i
].offset
, fb
->parts
[i
].length
);
852 buf
+= fb
->parts
[i
].length
;
858 * flow_builder4_finalize - assemble final flowspec data structure &net_addr_flow4
859 * @fb: flowspec builder instance
860 * @lpool: linear memory pool
862 * This function returns final flowspec data structure &net_addr_flow4 allocated
863 * onto @lpool linear memory pool.
866 flow_builder4_finalize(struct flow_builder
*fb
, linpool
*lpool
)
868 uint data_len
= fb
->data
.used
+ (fb
->data
.used
< 0xf0 ? 1 : 2);
869 net_addr_flow4
*f
= lp_alloc(lpool
, sizeof(struct net_addr_flow4
) + data_len
);
871 ip4_addr prefix
= IP4_NONE
;
874 if (fb
->parts
[FLOW_TYPE_DST_PREFIX
].length
)
876 byte
*part
= fb
->data
.data
+ fb
->parts
[FLOW_TYPE_DST_PREFIX
].offset
;
877 prefix
= flow_read_ip4_part(part
);
880 *f
= NET_ADDR_FLOW4(prefix
, pxlen
, data_len
);
882 builder_write_parts(fb
, f
->data
+ flow_write_length(f
->data
, fb
->data
.used
));
888 * flow_builder6_finalize - assemble final flowspec data structure &net_addr_flow6
889 * @fb: flowspec builder instance
890 * @lpool: linear memory pool for allocation of
892 * This function returns final flowspec data structure &net_addr_flow6 allocated
893 * onto @lpool linear memory pool.
896 flow_builder6_finalize(struct flow_builder
*fb
, linpool
*lpool
)
898 uint data_len
= fb
->data
.used
+ (fb
->data
.used
< 0xf0 ? 1 : 2);
899 net_addr_flow6
*n
= lp_alloc(lpool
, sizeof(net_addr_flow6
) + data_len
);
901 ip6_addr prefix
= IP6_NONE
;
904 if (fb
->parts
[FLOW_TYPE_DST_PREFIX
].length
)
906 byte
*part
= fb
->data
.data
+ fb
->parts
[FLOW_TYPE_DST_PREFIX
].offset
;
907 prefix
= flow_read_ip6_part(part
);
910 *n
= NET_ADDR_FLOW6(prefix
, pxlen
, data_len
);
912 builder_write_parts(fb
, n
->data
+ flow_write_length(n
->data
, fb
->data
.used
));
918 * flow_builder_clear - flush flowspec builder instance for another flowspec creation
919 * @fb: flowspec builder instance
921 * This function flushes all data from builder but it maintains pre-allocated
925 flow_builder_clear(struct flow_builder
*fb
)
928 BUFFER_FLUSH(fb
->data
);
930 BUFFER_SHALLOW_COPY(data
, fb
->data
);
931 memset(fb
, 0, sizeof(struct flow_builder
));
932 BUFFER_SHALLOW_COPY(fb
->data
, data
);
940 /* Flowspec operators for [op, value]+ pairs */
943 num_op_str(const byte
*op
)
947 case FLOW_OP_TRUE
: return "true";
948 case FLOW_OP_EQ
: return "=";
949 case FLOW_OP_GT
: return ">";
950 case FLOW_OP_GEQ
: return ">=";
951 case FLOW_OP_LT
: return "<";
952 case FLOW_OP_LEQ
: return "<=";
953 case FLOW_OP_NEQ
: return "!=";
954 case FLOW_OP_FALSE
: return "false";
961 get_value(const byte
*val
, u8 len
)
966 case 2: return get_u16(val
);
967 case 4: return get_u32(val
);
968 // No component may have length 8
969 // case 8: return get_u64(val);
976 fragment_val_str(u8 val
)
980 case 1: return "dont_fragment";
981 case 2: return "is_fragment";
982 case 4: return "first_fragment";
983 case 8: return "last_fragment";
989 net_format_flow_ip(buffer
*b
, const byte
*part
, int ipv6
)
991 uint pxlen
= part
[1];
994 uint pxoffset
= part
[2];
996 buffer_print(b
, "%I6/%u offset %u; ", flow_read_ip6_part(part
), pxlen
, pxoffset
);
998 buffer_print(b
, "%I6/%u; ", flow_read_ip6_part(part
), pxlen
);
1002 buffer_print(b
, "%I4/%u; ", flow_read_ip4_part(part
), pxlen
);
1007 net_format_flow_num(buffer
*b
, const byte
*part
)
1009 const byte
*last_op
= NULL
;
1010 const byte
*op
= part
+1;
1019 /* XXX: I don't like this so complicated if-tree */
1020 if (!isset_and(op
) &&
1021 ((num_op( op
) == FLOW_OP_EQ
) || (num_op( op
) == FLOW_OP_GEQ
)) &&
1022 ((num_op(last_op
) == FLOW_OP_EQ
) || (num_op(last_op
) == FLOW_OP_LEQ
)))
1024 b
->pos
--; /* Remove last char (it is a space) */
1025 buffer_puts(b
, ",");
1029 buffer_puts(b
, isset_and(op
) ? "&& " : "|| ");
1034 len
= get_value_length(op
);
1035 val
= get_value(op
+1, len
);
1037 if (!isset_end(op
) && !isset_and(op
) && isset_and(op
+1+len
) &&
1038 (num_op(op
) == FLOW_OP_GEQ
) && (num_op(op
+1+len
) == FLOW_OP_LEQ
))
1040 /* Display interval */
1041 buffer_print(b
, "%u..", val
);
1043 len
= get_value_length(op
);
1044 val
= get_value(op
+1, len
);
1045 buffer_print(b
, "%u", val
);
1047 else if (num_op(op
) == FLOW_OP_EQ
)
1049 buffer_print(b
, "%u", val
);
1053 buffer_print(b
, "%s %u", num_op_str(op
), val
);
1058 buffer_puts(b
, "; ");
1063 buffer_puts(b
, " ");
1072 net_format_flow_bitmask(buffer
*b
, const byte
*part
)
1074 const byte
*op
= part
+1;
1085 b
->pos
--; /* Remove last char (it is a space) */
1086 buffer_puts(b
, ",");
1090 buffer_puts(b
, "|| ");
1095 len
= get_value_length(op
);
1096 val
= get_value(op
+1, len
);
1100 * ------------------
1107 if ((*op
& 0x3) == 0x3 || (*op
& 0x3) == 0)
1108 buffer_puts(b
, "!");
1110 if (*part
== FLOW_TYPE_FRAGMENT
&& (val
== 1 || val
== 2 || val
== 4 || val
== 8))
1111 buffer_print(b
, "%s%s", ((*op
& 0x1) ? "" : "!"), fragment_val_str(val
));
1113 buffer_print(b
, "0x%x/0x%x", ((*op
& 0x1) ? val
: 0), val
);
1117 buffer_puts(b
, "; ");
1122 buffer_puts(b
, " ");
1130 net_format_flow(char *buf
, uint blen
, const byte
*data
, uint dlen
, int ipv6
)
1138 const byte
*part
= flow_first_part(data
);
1142 buffer_puts(&b
, "flow6 { ");
1144 buffer_puts(&b
, "flow4 { ");
1148 buffer_print(&b
, "%s ", flow_type_str(*part
, ipv6
));
1152 case FLOW_TYPE_DST_PREFIX
:
1153 case FLOW_TYPE_SRC_PREFIX
:
1154 net_format_flow_ip(&b
, part
, ipv6
);
1156 case FLOW_TYPE_IP_PROTOCOL
: /* == FLOW_TYPE_NEXT_HEADER */
1157 case FLOW_TYPE_PORT
:
1158 case FLOW_TYPE_DST_PORT
:
1159 case FLOW_TYPE_SRC_PORT
:
1160 case FLOW_TYPE_ICMP_TYPE
:
1161 case FLOW_TYPE_ICMP_CODE
:
1162 case FLOW_TYPE_PACKET_LENGTH
:
1163 case FLOW_TYPE_DSCP
:
1164 net_format_flow_num(&b
, part
);
1166 case FLOW_TYPE_TCP_FLAGS
:
1167 case FLOW_TYPE_FRAGMENT
:
1168 case FLOW_TYPE_LABEL
:
1169 net_format_flow_bitmask(&b
, part
);
1173 part
= flow_next_part(part
, data
+dlen
, ipv6
);
1176 buffer_puts(&b
, "}");
1180 b
.pos
= b
.start
+ MIN(blen
- 6, strlen(b
.start
));
1181 buffer_puts(&b
, " ...}");
1184 return b
.pos
- b
.start
;
1188 * flow4_net_format - stringify flowspec data structure &net_addr_flow4
1189 * @buf: pre-allocated buffer for writing a stringify net address flowspec
1190 * @blen: free allocated space in @buf
1191 * @f: flowspec data structure &net_addr_flow4 for stringify
1193 * This function writes stringified @f into @buf. The function returns number
1194 * of written chars. If final string is too large, the string will ends the with
1195 * ' ...}' sequence and zero-terminator.
1198 flow4_net_format(char *buf
, uint blen
, const net_addr_flow4
*f
)
1200 return net_format_flow(buf
, blen
, f
->data
, f
->length
- sizeof(net_addr_flow4
), 0);
1204 * flow6_net_format - stringify flowspec data structure &net_addr_flow6
1205 * @buf: pre-allocated buffer for writing a stringify net address flowspec
1206 * @blen: free allocated space in @buf
1207 * @f: flowspec data structure &net_addr_flow4 for stringify
1209 * This function writes stringified @f into @buf. The function returns number
1210 * of written chars. If final string is too large, the string will ends the with
1211 * ' ...}' sequence and zero-terminator.
1214 flow6_net_format(char *buf
, uint blen
, const net_addr_flow6
*f
)
1216 return net_format_flow(buf
, blen
, f
->data
, f
->length
- sizeof(net_addr_flow6
), 1);