1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* BGP FlowSpec Utilities
4 * Copyright (C) 2017 ChinaTelecom SDN Group
5 * Copyright (C) 2018 6WIND
10 #include "lib/printfrr.h"
13 #include "lib_errors.h"
15 #include "bgp_route.h"
16 #include "bgp_table.h"
17 #include "bgp_flowspec_util.h"
18 #include "bgp_flowspec_private.h"
20 #include "bgp_errors.h"
22 static void hex2bin(uint8_t *hex
, int *bin
)
27 while (remainder
>= 1 && i
< 8) {
28 bin
[7-i
] = remainder
% 2;
29 remainder
= remainder
/ 2;
36 static int hexstr2num(uint8_t *hexstr
, int len
)
41 for (i
= 0; i
< len
; i
++)
42 num
= hexstr
[i
] + 16*16*num
;
46 /* call bgp_flowspec_op_decode
49 static int bgp_flowspec_call_non_opaque_decode(uint8_t *nlri_content
, int len
,
50 struct bgp_pbr_match_val
*mval
,
51 uint8_t *match_num
, int *error
)
55 ret
= bgp_flowspec_op_decode(
56 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
61 flog_err(EC_BGP_FLOWSPEC_PACKET
,
62 "%s: flowspec_op_decode error %d", __func__
, *error
);
69 bool bgp_flowspec_contains_prefix(const struct prefix
*pfs
,
70 struct prefix
*input
, int prefix_check
)
74 int ret
= 0, error
= 0;
75 uint8_t *nlri_content
= (uint8_t *)pfs
->u
.prefix_flowspec
.ptr
;
76 size_t len
= pfs
->u
.prefix_flowspec
.prefixlen
;
77 afi_t afi
= family2afi(pfs
->u
.prefix_flowspec
.family
);
78 struct prefix compare
;
81 while (offset
< len
-1 && error
>= 0) {
82 type
= nlri_content
[offset
];
85 case FLOWSPEC_DEST_PREFIX
:
86 case FLOWSPEC_SRC_PREFIX
:
87 memset(&compare
, 0, sizeof(compare
));
88 ret
= bgp_flowspec_ip_address(
89 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
97 compare
.prefixlen
!= input
->prefixlen
)
99 if (compare
.family
!= input
->family
)
101 if ((input
->family
== AF_INET
) &&
102 IPV4_ADDR_SAME(&input
->u
.prefix4
,
105 if ((input
->family
== AF_INET6
) &&
106 IPV6_ADDR_SAME(&input
->u
.prefix6
.s6_addr
,
107 &compare
.u
.prefix6
.s6_addr
))
110 case FLOWSPEC_FLOW_LABEL
:
115 ret
= bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY
,
120 case FLOWSPEC_IP_PROTOCOL
:
122 case FLOWSPEC_DEST_PORT
:
123 case FLOWSPEC_SRC_PORT
:
124 case FLOWSPEC_ICMP_TYPE
:
125 case FLOWSPEC_ICMP_CODE
:
126 ret
= bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY
,
131 case FLOWSPEC_FRAGMENT
:
132 case FLOWSPEC_TCP_FLAGS
:
133 ret
= bgp_flowspec_bitmask_decode(
134 BGP_FLOWSPEC_VALIDATE_ONLY
,
139 case FLOWSPEC_PKT_LEN
:
141 ret
= bgp_flowspec_op_decode(
142 BGP_FLOWSPEC_VALIDATE_ONLY
,
143 nlri_content
+ offset
,
157 * handle the flowspec address src/dst or generic address NLRI
158 * return number of bytes analysed ( >= 0).
160 int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type
,
163 void *result
, int *error
,
165 uint8_t *ipv6_offset
)
167 char *display
= (char *)result
; /* for return_string */
168 struct prefix
*prefix
= (struct prefix
*)result
;
170 struct prefix prefix_local
;
172 uint8_t prefix_offset
= 0;
175 memset(&prefix_local
, 0, sizeof(prefix_local
));
176 /* read the prefix length */
177 prefix_local
.prefixlen
= nlri_ptr
[offset
];
178 psize
= PSIZE(prefix_local
.prefixlen
);
180 prefix_local
.family
= afi2family(afi
);
181 if (prefix_local
.family
== AF_INET6
) {
182 prefix_offset
= nlri_ptr
[offset
];
184 *ipv6_offset
= prefix_offset
;
187 /* Prefix length check. */
188 if (prefix_local
.prefixlen
> prefix_blen(&prefix_local
) * 8) {
192 /* When packet overflow occur return immediately. */
193 if (psize
+ offset
> max_len
) {
197 /* Defensive coding, double-check
198 * the psize fits in a struct prefix
200 if (psize
> (ssize_t
)sizeof(prefix_local
.u
)) {
205 memcpy(&prefix_local
.u
.prefix
, &nlri_ptr
[offset
], psize
);
208 case BGP_FLOWSPEC_RETURN_STRING
:
209 if (prefix_local
.family
== AF_INET6
) {
213 display
, BGP_FLOWSPEC_STRING_DISPLAY_MAX
,
214 "%pFX/off %u", &prefix_local
, prefix_offset
);
220 prefix2str(&prefix_local
, display
,
221 BGP_FLOWSPEC_STRING_DISPLAY_MAX
);
223 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
225 prefix_copy(prefix
, &prefix_local
);
227 case BGP_FLOWSPEC_VALIDATE_ONLY
:
228 case BGP_FLOWSPEC_RETURN_JSON
:
235 * handle the flowspec operator NLRI
236 * return number of bytes analysed
237 * if there is an error, the passed error param is used to give error:
238 * -1 if decoding error,
239 * if result is a string, its assumed length
240 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
242 int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type
,
245 void *result
, int *error
)
248 int len
, value
, value_size
;
250 char *ptr
= (char *)result
; /* for return_string */
252 int len_string
= BGP_FLOWSPEC_STRING_DISPLAY_MAX
;
254 struct bgp_pbr_match_val
*mval
= (struct bgp_pbr_match_val
*)result
;
258 if (loop
> BGP_PBR_MATCH_VAL_MAX
)
260 hex2bin(&nlri_ptr
[offset
], op
);
263 value_size
= 1 << len
;
264 value
= hexstr2num(&nlri_ptr
[offset
], value_size
);
265 /* can not be < and > at the same time */
266 if (op
[5] == 1 && op
[6] == 1)
268 /* if first element, AND bit can not be set */
269 if (op
[1] == 1 && loop
== 0)
272 case BGP_FLOWSPEC_RETURN_STRING
:
274 len_written
= snprintf(ptr
, len_string
,
276 len_string
-= len_written
;
280 len_written
= snprintf(ptr
, len_string
,
282 len_string
-= len_written
;
286 len_written
= snprintf(ptr
, len_string
,
288 len_string
-= len_written
;
292 len_written
= snprintf(ptr
, len_string
,
294 len_string
-= len_written
;
297 len_written
= snprintf(ptr
, len_string
,
299 len_string
-= len_written
;
302 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
303 /* limitation: stop converting */
308 mval
->compare_operator
|=
309 OPERATOR_COMPARE_LESS_THAN
;
311 mval
->compare_operator
|=
312 OPERATOR_COMPARE_GREATER_THAN
;
314 mval
->compare_operator
|=
315 OPERATOR_COMPARE_EQUAL_TO
;
317 mval
->unary_operator
= OPERATOR_UNARY_AND
;
319 mval
->unary_operator
= OPERATOR_UNARY_OR
;
322 case BGP_FLOWSPEC_VALIDATE_ONLY
:
323 case BGP_FLOWSPEC_RETURN_JSON
:
327 offset
+= value_size
;
329 } while (op
[0] == 0 && offset
< max_len
- 1);
330 if (offset
> max_len
)
332 /* use error parameter to count the number of entries */
340 * handle the flowspec tcpflags or fragment field
341 * return number of bytes analysed
342 * if there is an error, the passed error param is used to give error:
343 * -1 if decoding error,
344 * if result is a string, its assumed length
345 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
347 int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type
,
350 void *result
, int *error
)
353 int len
, value_size
, loop
= 0, value
;
354 char *ptr
= (char *)result
; /* for return_string */
355 struct bgp_pbr_match_val
*mval
= (struct bgp_pbr_match_val
*)result
;
357 int len_string
= BGP_FLOWSPEC_STRING_DISPLAY_MAX
;
362 if (loop
> BGP_PBR_MATCH_VAL_MAX
) {
366 hex2bin(&nlri_ptr
[offset
], op
);
367 /* if first element, AND bit can not be set */
368 if (op
[1] == 1 && loop
== 0)
371 len
= 2 * op
[2] + op
[3];
372 value_size
= 1 << len
;
373 value
= hexstr2num(&nlri_ptr
[offset
], value_size
);
375 case BGP_FLOWSPEC_RETURN_STRING
:
376 if (op
[1] == 1 && loop
!= 0) {
377 len_written
= snprintf(ptr
, len_string
,
379 len_string
-= len_written
;
381 } else if (op
[1] == 0 && loop
!= 0) {
382 len_written
= snprintf(ptr
, len_string
,
384 len_string
-= len_written
;
388 len_written
= snprintf(ptr
, len_string
,
390 len_string
-= len_written
;
393 len_written
= snprintf(ptr
, len_string
,
395 len_string
-= len_written
;
399 len_written
= snprintf(ptr
, len_string
,
401 len_string
-= len_written
;
404 len_written
= snprintf(ptr
, len_string
,
406 len_string
-= len_written
;
409 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
410 /* limitation: stop converting */
416 mval
->compare_operator
|=
417 OPERATOR_COMPARE_LESS_THAN
;
418 mval
->compare_operator
|=
419 OPERATOR_COMPARE_GREATER_THAN
;
421 mval
->compare_operator
|=
422 OPERATOR_COMPARE_EQUAL_TO
;
424 mval
->compare_operator
|=
425 OPERATOR_COMPARE_EXACT_MATCH
;
427 mval
->unary_operator
=
430 mval
->unary_operator
=
434 case BGP_FLOWSPEC_VALIDATE_ONLY
:
435 case BGP_FLOWSPEC_RETURN_JSON
:
439 offset
+= value_size
;
441 } while (op
[0] == 0 && offset
< max_len
- 1);
442 if (offset
> max_len
)
444 /* use error parameter to count the number of entries */
450 int bgp_flowspec_match_rules_fill(uint8_t *nlri_content
, int len
,
451 struct bgp_pbr_entry_main
*bpem
,
454 int offset
= 0, error
= 0;
455 struct prefix
*prefix
;
456 struct bgp_pbr_match_val
*mval
;
460 uint8_t *prefix_offset
;
462 while (offset
< len
- 1 && error
>= 0) {
463 type
= nlri_content
[offset
];
466 case FLOWSPEC_DEST_PREFIX
:
467 case FLOWSPEC_SRC_PREFIX
:
469 if (type
== FLOWSPEC_DEST_PREFIX
) {
470 bitmask
|= PREFIX_DST_PRESENT
;
471 prefix
= &bpem
->dst_prefix
;
472 prefix_offset
= &bpem
->dst_prefix_offset
;
474 bitmask
|= PREFIX_SRC_PRESENT
;
475 prefix
= &bpem
->src_prefix
;
476 prefix_offset
= &bpem
->src_prefix_offset
;
478 ret
= bgp_flowspec_ip_address(
479 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
480 nlri_content
+ offset
,
485 flog_err(EC_BGP_FLOWSPEC_PACKET
,
486 "%s: flowspec_ip_address error %d",
489 /* if src or dst address is 0.0.0.0,
492 if (prefix
->family
== AF_INET
493 && prefix
->u
.prefix4
.s_addr
== INADDR_ANY
)
494 bpem
->match_bitmask_iprule
|= bitmask
;
495 else if (prefix
->family
== AF_INET6
496 && !memcmp(&prefix
->u
.prefix6
,
498 sizeof(struct in6_addr
)))
499 bpem
->match_bitmask_iprule
|= bitmask
;
501 bpem
->match_bitmask
|= bitmask
;
505 case FLOWSPEC_FLOW_LABEL
:
510 match_num
= &(bpem
->match_flowlabel_num
);
511 mval
= (struct bgp_pbr_match_val
*)
513 offset
+= bgp_flowspec_call_non_opaque_decode(
514 nlri_content
+ offset
,
519 case FLOWSPEC_IP_PROTOCOL
:
520 match_num
= &(bpem
->match_protocol_num
);
521 mval
= (struct bgp_pbr_match_val
*)
523 offset
+= bgp_flowspec_call_non_opaque_decode(
524 nlri_content
+ offset
,
530 match_num
= &(bpem
->match_port_num
);
531 mval
= (struct bgp_pbr_match_val
*)
533 offset
+= bgp_flowspec_call_non_opaque_decode(
534 nlri_content
+ offset
,
539 case FLOWSPEC_DEST_PORT
:
540 match_num
= &(bpem
->match_dst_port_num
);
541 mval
= (struct bgp_pbr_match_val
*)
543 offset
+= bgp_flowspec_call_non_opaque_decode(
544 nlri_content
+ offset
,
549 case FLOWSPEC_SRC_PORT
:
550 match_num
= &(bpem
->match_src_port_num
);
551 mval
= (struct bgp_pbr_match_val
*)
553 offset
+= bgp_flowspec_call_non_opaque_decode(
554 nlri_content
+ offset
,
559 case FLOWSPEC_ICMP_TYPE
:
560 match_num
= &(bpem
->match_icmp_type_num
);
561 mval
= (struct bgp_pbr_match_val
*)
563 offset
+= bgp_flowspec_call_non_opaque_decode(
564 nlri_content
+ offset
,
569 case FLOWSPEC_ICMP_CODE
:
570 match_num
= &(bpem
->match_icmp_code_num
);
571 mval
= (struct bgp_pbr_match_val
*)
573 offset
+= bgp_flowspec_call_non_opaque_decode(
574 nlri_content
+ offset
,
579 case FLOWSPEC_PKT_LEN
:
581 &(bpem
->match_packet_length_num
);
582 mval
= (struct bgp_pbr_match_val
*)
583 &(bpem
->packet_length
);
584 offset
+= bgp_flowspec_call_non_opaque_decode(
585 nlri_content
+ offset
,
591 match_num
= &(bpem
->match_dscp_num
);
592 mval
= (struct bgp_pbr_match_val
*)
594 offset
+= bgp_flowspec_call_non_opaque_decode(
595 nlri_content
+ offset
,
600 case FLOWSPEC_TCP_FLAGS
:
601 ret
= bgp_flowspec_bitmask_decode(
602 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
603 nlri_content
+ offset
,
605 &bpem
->tcpflags
, &error
);
608 EC_BGP_FLOWSPEC_PACKET
,
609 "%s: flowspec_tcpflags_decode error %d",
612 bpem
->match_tcpflags_num
= error
;
613 /* contains the number of slots used */
616 case FLOWSPEC_FRAGMENT
:
617 ret
= bgp_flowspec_bitmask_decode(
618 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
619 nlri_content
+ offset
,
620 len
- offset
, &bpem
->fragment
,
624 EC_BGP_FLOWSPEC_PACKET
,
625 "%s: flowspec_fragment_type_decode error %d",
628 bpem
->match_fragment_num
= error
;
632 flog_err(EC_LIB_DEVELOPMENT
, "%s: unknown type %d",
636 if (bpem
->match_packet_length_num
|| bpem
->match_fragment_num
637 || bpem
->match_tcpflags_num
|| bpem
->match_dscp_num
638 || bpem
->match_icmp_code_num
|| bpem
->match_icmp_type_num
639 || bpem
->match_port_num
|| bpem
->match_src_port_num
640 || bpem
->match_dst_port_num
|| bpem
->match_protocol_num
641 || bpem
->match_bitmask
|| bpem
->match_flowlabel_num
)
642 bpem
->type
= BGP_PBR_IPSET
;
643 else if ((bpem
->match_bitmask_iprule
& PREFIX_SRC_PRESENT
) ||
644 (bpem
->match_bitmask_iprule
& PREFIX_DST_PRESENT
))
645 /* the extracted policy rule may not need an
646 * iptables/ipset filtering. check this may not be
647 * a standard ip rule : permit any to any ( eg)
649 bpem
->type
= BGP_PBR_IPRULE
;
651 bpem
->type
= BGP_PBR_UNDEFINED
;
655 /* return 1 if FS entry invalid or no NH IP */
656 bool bgp_flowspec_get_first_nh(struct bgp
*bgp
, struct bgp_path_info
*pi
,
657 struct prefix
*p
, afi_t afi
)
659 struct bgp_pbr_entry_main api
;
661 struct bgp_dest
*dest
= pi
->net
;
662 struct bgp_pbr_entry_action
*api_action
;
664 memset(&api
, 0, sizeof(api
));
665 if (bgp_pbr_build_and_validate_entry(bgp_dest_get_prefix(dest
), pi
,
669 for (i
= 0; i
< api
.action_num
; i
++) {
670 api_action
= &api
.actions
[i
];
671 if (api_action
->action
!= ACTION_REDIRECT_IP
)
673 p
->family
= afi2family(afi
);
675 p
->prefixlen
= IPV4_MAX_BITLEN
;
676 p
->u
.prefix4
= api_action
->u
.zr
.redirect_ip_v4
;
678 p
->prefixlen
= IPV6_MAX_BITLEN
;
679 memcpy(&p
->u
.prefix6
, &api_action
->u
.zr
.redirect_ip_v6
,
680 sizeof(struct in6_addr
));