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)
190 /* When packet overflow occur return immediately. */
191 if (psize
+ offset
> max_len
)
193 /* Defensive coding, double-check
194 * the psize fits in a struct prefix
196 if (psize
> (ssize_t
)sizeof(prefix_local
.u
))
198 memcpy(&prefix_local
.u
.prefix
, &nlri_ptr
[offset
], psize
);
201 case BGP_FLOWSPEC_RETURN_STRING
:
202 if (prefix_local
.family
== AF_INET6
) {
206 display
, BGP_FLOWSPEC_STRING_DISPLAY_MAX
,
207 "%pFX/off %u", &prefix_local
, prefix_offset
);
213 prefix2str(&prefix_local
, display
,
214 BGP_FLOWSPEC_STRING_DISPLAY_MAX
);
216 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
218 prefix_copy(prefix
, &prefix_local
);
220 case BGP_FLOWSPEC_VALIDATE_ONLY
:
221 case BGP_FLOWSPEC_RETURN_JSON
:
228 * handle the flowspec operator NLRI
229 * return number of bytes analysed
230 * if there is an error, the passed error param is used to give error:
231 * -1 if decoding error,
232 * if result is a string, its assumed length
233 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
235 int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type
,
238 void *result
, int *error
)
241 int len
, value
, value_size
;
243 char *ptr
= (char *)result
; /* for return_string */
245 int len_string
= BGP_FLOWSPEC_STRING_DISPLAY_MAX
;
247 struct bgp_pbr_match_val
*mval
= (struct bgp_pbr_match_val
*)result
;
251 if (loop
> BGP_PBR_MATCH_VAL_MAX
)
253 hex2bin(&nlri_ptr
[offset
], op
);
256 value_size
= 1 << len
;
257 value
= hexstr2num(&nlri_ptr
[offset
], value_size
);
258 /* can not be < and > at the same time */
259 if (op
[5] == 1 && op
[6] == 1)
261 /* if first element, AND bit can not be set */
262 if (op
[1] == 1 && loop
== 0)
265 case BGP_FLOWSPEC_RETURN_STRING
:
267 len_written
= snprintf(ptr
, len_string
,
269 len_string
-= len_written
;
273 len_written
= snprintf(ptr
, len_string
,
275 len_string
-= len_written
;
279 len_written
= snprintf(ptr
, len_string
,
281 len_string
-= len_written
;
285 len_written
= snprintf(ptr
, len_string
,
287 len_string
-= len_written
;
290 len_written
= snprintf(ptr
, len_string
,
292 len_string
-= len_written
;
295 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
296 /* limitation: stop converting */
301 mval
->compare_operator
|=
302 OPERATOR_COMPARE_LESS_THAN
;
304 mval
->compare_operator
|=
305 OPERATOR_COMPARE_GREATER_THAN
;
307 mval
->compare_operator
|=
308 OPERATOR_COMPARE_EQUAL_TO
;
310 mval
->unary_operator
= OPERATOR_UNARY_AND
;
312 mval
->unary_operator
= OPERATOR_UNARY_OR
;
315 case BGP_FLOWSPEC_VALIDATE_ONLY
:
316 case BGP_FLOWSPEC_RETURN_JSON
:
320 offset
+= value_size
;
322 } while (op
[0] == 0 && offset
< max_len
- 1);
323 if (offset
> max_len
)
325 /* use error parameter to count the number of entries */
333 * handle the flowspec tcpflags or fragment field
334 * return number of bytes analysed
335 * if there is an error, the passed error param is used to give error:
336 * -1 if decoding error,
337 * if result is a string, its assumed length
338 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
340 int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type
,
343 void *result
, int *error
)
346 int len
, value_size
, loop
= 0, value
;
347 char *ptr
= (char *)result
; /* for return_string */
348 struct bgp_pbr_match_val
*mval
= (struct bgp_pbr_match_val
*)result
;
350 int len_string
= BGP_FLOWSPEC_STRING_DISPLAY_MAX
;
355 if (loop
> BGP_PBR_MATCH_VAL_MAX
)
357 hex2bin(&nlri_ptr
[offset
], op
);
358 /* if first element, AND bit can not be set */
359 if (op
[1] == 1 && loop
== 0)
362 len
= 2 * op
[2] + op
[3];
363 value_size
= 1 << len
;
364 value
= hexstr2num(&nlri_ptr
[offset
], value_size
);
366 case BGP_FLOWSPEC_RETURN_STRING
:
367 if (op
[1] == 1 && loop
!= 0) {
368 len_written
= snprintf(ptr
, len_string
,
370 len_string
-= len_written
;
372 } else if (op
[1] == 0 && loop
!= 0) {
373 len_written
= snprintf(ptr
, len_string
,
375 len_string
-= len_written
;
379 len_written
= snprintf(ptr
, len_string
,
381 len_string
-= len_written
;
384 len_written
= snprintf(ptr
, len_string
,
386 len_string
-= len_written
;
390 len_written
= snprintf(ptr
, len_string
,
392 len_string
-= len_written
;
395 len_written
= snprintf(ptr
, len_string
,
397 len_string
-= len_written
;
400 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
401 /* limitation: stop converting */
407 mval
->compare_operator
|=
408 OPERATOR_COMPARE_LESS_THAN
;
409 mval
->compare_operator
|=
410 OPERATOR_COMPARE_GREATER_THAN
;
412 mval
->compare_operator
|=
413 OPERATOR_COMPARE_EQUAL_TO
;
415 mval
->compare_operator
|=
416 OPERATOR_COMPARE_EXACT_MATCH
;
418 mval
->unary_operator
=
421 mval
->unary_operator
=
425 case BGP_FLOWSPEC_VALIDATE_ONLY
:
426 case BGP_FLOWSPEC_RETURN_JSON
:
430 offset
+= value_size
;
432 } while (op
[0] == 0 && offset
< max_len
- 1);
433 if (offset
> max_len
)
435 /* use error parameter to count the number of entries */
441 int bgp_flowspec_match_rules_fill(uint8_t *nlri_content
, int len
,
442 struct bgp_pbr_entry_main
*bpem
,
445 int offset
= 0, error
= 0;
446 struct prefix
*prefix
;
447 struct bgp_pbr_match_val
*mval
;
451 uint8_t *prefix_offset
;
453 while (offset
< len
- 1 && error
>= 0) {
454 type
= nlri_content
[offset
];
457 case FLOWSPEC_DEST_PREFIX
:
458 case FLOWSPEC_SRC_PREFIX
:
460 if (type
== FLOWSPEC_DEST_PREFIX
) {
461 bitmask
|= PREFIX_DST_PRESENT
;
462 prefix
= &bpem
->dst_prefix
;
463 prefix_offset
= &bpem
->dst_prefix_offset
;
465 bitmask
|= PREFIX_SRC_PRESENT
;
466 prefix
= &bpem
->src_prefix
;
467 prefix_offset
= &bpem
->src_prefix_offset
;
469 ret
= bgp_flowspec_ip_address(
470 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
471 nlri_content
+ offset
,
476 flog_err(EC_BGP_FLOWSPEC_PACKET
,
477 "%s: flowspec_ip_address error %d",
480 /* if src or dst address is 0.0.0.0,
483 if (prefix
->family
== AF_INET
484 && prefix
->u
.prefix4
.s_addr
== INADDR_ANY
)
485 bpem
->match_bitmask_iprule
|= bitmask
;
486 else if (prefix
->family
== AF_INET6
487 && !memcmp(&prefix
->u
.prefix6
,
489 sizeof(struct in6_addr
)))
490 bpem
->match_bitmask_iprule
|= bitmask
;
492 bpem
->match_bitmask
|= bitmask
;
496 case FLOWSPEC_FLOW_LABEL
:
501 match_num
= &(bpem
->match_flowlabel_num
);
502 mval
= (struct bgp_pbr_match_val
*)
504 offset
+= bgp_flowspec_call_non_opaque_decode(
505 nlri_content
+ offset
,
510 case FLOWSPEC_IP_PROTOCOL
:
511 match_num
= &(bpem
->match_protocol_num
);
512 mval
= (struct bgp_pbr_match_val
*)
514 offset
+= bgp_flowspec_call_non_opaque_decode(
515 nlri_content
+ offset
,
521 match_num
= &(bpem
->match_port_num
);
522 mval
= (struct bgp_pbr_match_val
*)
524 offset
+= bgp_flowspec_call_non_opaque_decode(
525 nlri_content
+ offset
,
530 case FLOWSPEC_DEST_PORT
:
531 match_num
= &(bpem
->match_dst_port_num
);
532 mval
= (struct bgp_pbr_match_val
*)
534 offset
+= bgp_flowspec_call_non_opaque_decode(
535 nlri_content
+ offset
,
540 case FLOWSPEC_SRC_PORT
:
541 match_num
= &(bpem
->match_src_port_num
);
542 mval
= (struct bgp_pbr_match_val
*)
544 offset
+= bgp_flowspec_call_non_opaque_decode(
545 nlri_content
+ offset
,
550 case FLOWSPEC_ICMP_TYPE
:
551 match_num
= &(bpem
->match_icmp_type_num
);
552 mval
= (struct bgp_pbr_match_val
*)
554 offset
+= bgp_flowspec_call_non_opaque_decode(
555 nlri_content
+ offset
,
560 case FLOWSPEC_ICMP_CODE
:
561 match_num
= &(bpem
->match_icmp_code_num
);
562 mval
= (struct bgp_pbr_match_val
*)
564 offset
+= bgp_flowspec_call_non_opaque_decode(
565 nlri_content
+ offset
,
570 case FLOWSPEC_PKT_LEN
:
572 &(bpem
->match_packet_length_num
);
573 mval
= (struct bgp_pbr_match_val
*)
574 &(bpem
->packet_length
);
575 offset
+= bgp_flowspec_call_non_opaque_decode(
576 nlri_content
+ offset
,
582 match_num
= &(bpem
->match_dscp_num
);
583 mval
= (struct bgp_pbr_match_val
*)
585 offset
+= bgp_flowspec_call_non_opaque_decode(
586 nlri_content
+ offset
,
591 case FLOWSPEC_TCP_FLAGS
:
592 ret
= bgp_flowspec_bitmask_decode(
593 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
594 nlri_content
+ offset
,
596 &bpem
->tcpflags
, &error
);
599 EC_BGP_FLOWSPEC_PACKET
,
600 "%s: flowspec_tcpflags_decode error %d",
603 bpem
->match_tcpflags_num
= error
;
604 /* contains the number of slots used */
607 case FLOWSPEC_FRAGMENT
:
608 ret
= bgp_flowspec_bitmask_decode(
609 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
610 nlri_content
+ offset
,
611 len
- offset
, &bpem
->fragment
,
615 EC_BGP_FLOWSPEC_PACKET
,
616 "%s: flowspec_fragment_type_decode error %d",
619 bpem
->match_fragment_num
= error
;
623 flog_err(EC_LIB_DEVELOPMENT
, "%s: unknown type %d",
627 if (bpem
->match_packet_length_num
|| bpem
->match_fragment_num
628 || bpem
->match_tcpflags_num
|| bpem
->match_dscp_num
629 || bpem
->match_icmp_code_num
|| bpem
->match_icmp_type_num
630 || bpem
->match_port_num
|| bpem
->match_src_port_num
631 || bpem
->match_dst_port_num
|| bpem
->match_protocol_num
632 || bpem
->match_bitmask
|| bpem
->match_flowlabel_num
)
633 bpem
->type
= BGP_PBR_IPSET
;
634 else if ((bpem
->match_bitmask_iprule
& PREFIX_SRC_PRESENT
) ||
635 (bpem
->match_bitmask_iprule
& PREFIX_DST_PRESENT
))
636 /* the extracted policy rule may not need an
637 * iptables/ipset filtering. check this may not be
638 * a standard ip rule : permit any to any ( eg)
640 bpem
->type
= BGP_PBR_IPRULE
;
642 bpem
->type
= BGP_PBR_UNDEFINED
;
646 /* return 1 if FS entry invalid or no NH IP */
647 bool bgp_flowspec_get_first_nh(struct bgp
*bgp
, struct bgp_path_info
*pi
,
648 struct prefix
*p
, afi_t afi
)
650 struct bgp_pbr_entry_main api
;
652 struct bgp_dest
*dest
= pi
->net
;
653 struct bgp_pbr_entry_action
*api_action
;
655 memset(&api
, 0, sizeof(api
));
656 if (bgp_pbr_build_and_validate_entry(bgp_dest_get_prefix(dest
), pi
,
660 for (i
= 0; i
< api
.action_num
; i
++) {
661 api_action
= &api
.actions
[i
];
662 if (api_action
->action
!= ACTION_REDIRECT_IP
)
664 p
->family
= afi2family(afi
);
666 p
->prefixlen
= IPV4_MAX_BITLEN
;
667 p
->u
.prefix4
= api_action
->u
.zr
.redirect_ip_v4
;
669 p
->prefixlen
= IPV6_MAX_BITLEN
;
670 memcpy(&p
->u
.prefix6
, &api_action
->u
.zr
.redirect_ip_v6
,
671 sizeof(struct in6_addr
));