1 /* BGP FlowSpec Utilities
3 * Copyright (C) 2017 ChinaTelecom SDN Group
4 * Copyright (C) 2018 6WIND
6 * FRRouting is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
11 * FRRouting is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "lib/printfrr.h"
26 #include "lib_errors.h"
28 #include "bgp_route.h"
29 #include "bgp_table.h"
30 #include "bgp_flowspec_util.h"
31 #include "bgp_flowspec_private.h"
33 #include "bgp_errors.h"
35 static void hex2bin(uint8_t *hex
, int *bin
)
40 while (remainder
>= 1 && i
< 8) {
41 bin
[7-i
] = remainder
% 2;
42 remainder
= remainder
/ 2;
49 static int hexstr2num(uint8_t *hexstr
, int len
)
54 for (i
= 0; i
< len
; i
++)
55 num
= hexstr
[i
] + 16*16*num
;
59 /* call bgp_flowspec_op_decode
62 static int bgp_flowspec_call_non_opaque_decode(uint8_t *nlri_content
, int len
,
63 struct bgp_pbr_match_val
*mval
,
64 uint8_t *match_num
, int *error
)
68 ret
= bgp_flowspec_op_decode(
69 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
74 flog_err(EC_BGP_FLOWSPEC_PACKET
,
75 "%s: flowspec_op_decode error %d", __func__
, *error
);
82 bool bgp_flowspec_contains_prefix(const struct prefix
*pfs
,
83 struct prefix
*input
, int prefix_check
)
87 int ret
= 0, error
= 0;
88 uint8_t *nlri_content
= (uint8_t *)pfs
->u
.prefix_flowspec
.ptr
;
89 size_t len
= pfs
->u
.prefix_flowspec
.prefixlen
;
90 afi_t afi
= family2afi(pfs
->u
.prefix_flowspec
.family
);
91 struct prefix compare
;
94 while (offset
< len
-1 && error
>= 0) {
95 type
= nlri_content
[offset
];
98 case FLOWSPEC_DEST_PREFIX
:
99 case FLOWSPEC_SRC_PREFIX
:
100 memset(&compare
, 0, sizeof(struct prefix
));
101 ret
= bgp_flowspec_ip_address(
102 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
110 compare
.prefixlen
!= input
->prefixlen
)
112 if (compare
.family
!= input
->family
)
114 if ((input
->family
== AF_INET
) &&
115 IPV4_ADDR_SAME(&input
->u
.prefix4
,
118 if ((input
->family
== AF_INET6
) &&
119 IPV6_ADDR_SAME(&input
->u
.prefix6
.s6_addr
,
120 &compare
.u
.prefix6
.s6_addr
))
123 case FLOWSPEC_FLOW_LABEL
:
128 ret
= bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY
,
133 case FLOWSPEC_IP_PROTOCOL
:
135 case FLOWSPEC_DEST_PORT
:
136 case FLOWSPEC_SRC_PORT
:
137 case FLOWSPEC_ICMP_TYPE
:
138 case FLOWSPEC_ICMP_CODE
:
139 ret
= bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY
,
144 case FLOWSPEC_FRAGMENT
:
145 case FLOWSPEC_TCP_FLAGS
:
146 ret
= bgp_flowspec_bitmask_decode(
147 BGP_FLOWSPEC_VALIDATE_ONLY
,
152 case FLOWSPEC_PKT_LEN
:
154 ret
= bgp_flowspec_op_decode(
155 BGP_FLOWSPEC_VALIDATE_ONLY
,
156 nlri_content
+ offset
,
170 * handle the flowspec address src/dst or generic address NLRI
171 * return number of bytes analysed ( >= 0).
173 int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type
,
176 void *result
, int *error
,
178 uint8_t *ipv6_offset
)
180 char *display
= (char *)result
; /* for return_string */
181 struct prefix
*prefix
= (struct prefix
*)result
;
183 struct prefix prefix_local
;
185 uint8_t prefix_offset
= 0;
188 memset(&prefix_local
, 0, sizeof(struct prefix
));
189 /* read the prefix length */
190 prefix_local
.prefixlen
= nlri_ptr
[offset
];
191 psize
= PSIZE(prefix_local
.prefixlen
);
193 prefix_local
.family
= afi2family(afi
);
194 if (prefix_local
.family
== AF_INET6
) {
195 prefix_offset
= nlri_ptr
[offset
];
197 *ipv6_offset
= prefix_offset
;
200 /* Prefix length check. */
201 if (prefix_local
.prefixlen
> prefix_blen(&prefix_local
) * 8)
203 /* When packet overflow occur return immediately. */
204 if (psize
+ offset
> max_len
)
206 /* Defensive coding, double-check
207 * the psize fits in a struct prefix
209 if (psize
> (ssize_t
)sizeof(prefix_local
.u
))
211 memcpy(&prefix_local
.u
.prefix
, &nlri_ptr
[offset
], psize
);
214 case BGP_FLOWSPEC_RETURN_STRING
:
215 if (prefix_local
.family
== AF_INET6
) {
219 display
, BGP_FLOWSPEC_STRING_DISPLAY_MAX
,
220 "%pFX/off %u", &prefix_local
, prefix_offset
);
226 prefix2str(&prefix_local
, display
,
227 BGP_FLOWSPEC_STRING_DISPLAY_MAX
);
229 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
231 prefix_copy(prefix
, &prefix_local
);
233 case BGP_FLOWSPEC_VALIDATE_ONLY
:
241 * handle the flowspec operator NLRI
242 * return number of bytes analysed
243 * if there is an error, the passed error param is used to give error:
244 * -1 if decoding error,
245 * if result is a string, its assumed length
246 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
248 int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type
,
251 void *result
, int *error
)
254 int len
, value
, value_size
;
256 char *ptr
= (char *)result
; /* for return_string */
258 int len_string
= BGP_FLOWSPEC_STRING_DISPLAY_MAX
;
260 struct bgp_pbr_match_val
*mval
= (struct bgp_pbr_match_val
*)result
;
264 if (loop
> BGP_PBR_MATCH_VAL_MAX
)
266 hex2bin(&nlri_ptr
[offset
], op
);
269 value_size
= 1 << len
;
270 value
= hexstr2num(&nlri_ptr
[offset
], value_size
);
271 /* can not be < and > at the same time */
272 if (op
[5] == 1 && op
[6] == 1)
274 /* if first element, AND bit can not be set */
275 if (op
[1] == 1 && loop
== 0)
278 case BGP_FLOWSPEC_RETURN_STRING
:
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
;
298 len_written
= snprintf(ptr
, len_string
,
300 len_string
-= len_written
;
303 len_written
= snprintf(ptr
, len_string
,
305 len_string
-= len_written
;
308 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
309 /* limitation: stop converting */
314 mval
->compare_operator
|=
315 OPERATOR_COMPARE_LESS_THAN
;
317 mval
->compare_operator
|=
318 OPERATOR_COMPARE_GREATER_THAN
;
320 mval
->compare_operator
|=
321 OPERATOR_COMPARE_EQUAL_TO
;
323 mval
->unary_operator
= OPERATOR_UNARY_AND
;
325 mval
->unary_operator
= OPERATOR_UNARY_OR
;
328 case BGP_FLOWSPEC_VALIDATE_ONLY
:
333 offset
+= value_size
;
335 } while (op
[0] == 0 && offset
< max_len
- 1);
336 if (offset
> max_len
)
338 /* use error parameter to count the number of entries */
346 * handle the flowspec tcpflags or fragment field
347 * return number of bytes analysed
348 * if there is an error, the passed error param is used to give error:
349 * -1 if decoding error,
350 * if result is a string, its assumed length
351 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
353 int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type
,
356 void *result
, int *error
)
359 int len
, value_size
, loop
= 0, value
;
360 char *ptr
= (char *)result
; /* for return_string */
361 struct bgp_pbr_match_val
*mval
= (struct bgp_pbr_match_val
*)result
;
363 int len_string
= BGP_FLOWSPEC_STRING_DISPLAY_MAX
;
368 if (loop
> BGP_PBR_MATCH_VAL_MAX
)
370 hex2bin(&nlri_ptr
[offset
], op
);
371 /* if first element, AND bit can not be set */
372 if (op
[1] == 1 && loop
== 0)
375 len
= 2 * op
[2] + op
[3];
376 value_size
= 1 << len
;
377 value
= hexstr2num(&nlri_ptr
[offset
], value_size
);
379 case BGP_FLOWSPEC_RETURN_STRING
:
380 if (op
[1] == 1 && loop
!= 0) {
381 len_written
= snprintf(ptr
, len_string
,
383 len_string
-= len_written
;
385 } else if (op
[1] == 0 && loop
!= 0) {
386 len_written
= snprintf(ptr
, len_string
,
388 len_string
-= len_written
;
392 len_written
= snprintf(ptr
, len_string
,
394 len_string
-= len_written
;
397 len_written
= snprintf(ptr
, len_string
,
399 len_string
-= len_written
;
403 len_written
= snprintf(ptr
, len_string
,
405 len_string
-= len_written
;
408 len_written
= snprintf(ptr
, len_string
,
410 len_string
-= len_written
;
413 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
414 /* limitation: stop converting */
420 mval
->compare_operator
|=
421 OPERATOR_COMPARE_LESS_THAN
;
422 mval
->compare_operator
|=
423 OPERATOR_COMPARE_GREATER_THAN
;
425 mval
->compare_operator
|=
426 OPERATOR_COMPARE_EQUAL_TO
;
428 mval
->compare_operator
|=
429 OPERATOR_COMPARE_EXACT_MATCH
;
431 mval
->unary_operator
=
434 mval
->unary_operator
=
438 case BGP_FLOWSPEC_VALIDATE_ONLY
:
443 offset
+= value_size
;
445 } while (op
[0] == 0 && offset
< max_len
- 1);
446 if (offset
> max_len
)
448 /* use error parameter to count the number of entries */
454 int bgp_flowspec_match_rules_fill(uint8_t *nlri_content
, int len
,
455 struct bgp_pbr_entry_main
*bpem
,
458 int offset
= 0, error
= 0;
459 struct prefix
*prefix
;
460 struct bgp_pbr_match_val
*mval
;
464 uint8_t *prefix_offset
;
466 while (offset
< len
- 1 && error
>= 0) {
467 type
= nlri_content
[offset
];
470 case FLOWSPEC_DEST_PREFIX
:
471 case FLOWSPEC_SRC_PREFIX
:
473 if (type
== FLOWSPEC_DEST_PREFIX
) {
474 bitmask
|= PREFIX_DST_PRESENT
;
475 prefix
= &bpem
->dst_prefix
;
476 prefix_offset
= &bpem
->dst_prefix_offset
;
478 bitmask
|= PREFIX_SRC_PRESENT
;
479 prefix
= &bpem
->src_prefix
;
480 prefix_offset
= &bpem
->src_prefix_offset
;
482 ret
= bgp_flowspec_ip_address(
483 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
484 nlri_content
+ offset
,
489 flog_err(EC_BGP_FLOWSPEC_PACKET
,
490 "%s: flowspec_ip_address error %d",
493 /* if src or dst address is 0.0.0.0,
496 if (prefix
->family
== AF_INET
497 && prefix
->u
.prefix4
.s_addr
== INADDR_ANY
)
498 bpem
->match_bitmask_iprule
|= bitmask
;
499 else if (prefix
->family
== AF_INET6
500 && !memcmp(&prefix
->u
.prefix6
,
502 sizeof(struct in6_addr
)))
503 bpem
->match_bitmask_iprule
|= bitmask
;
505 bpem
->match_bitmask
|= bitmask
;
509 case FLOWSPEC_FLOW_LABEL
:
514 match_num
= &(bpem
->match_flowlabel_num
);
515 mval
= (struct bgp_pbr_match_val
*)
517 offset
+= bgp_flowspec_call_non_opaque_decode(
518 nlri_content
+ offset
,
523 case FLOWSPEC_IP_PROTOCOL
:
524 match_num
= &(bpem
->match_protocol_num
);
525 mval
= (struct bgp_pbr_match_val
*)
527 offset
+= bgp_flowspec_call_non_opaque_decode(
528 nlri_content
+ offset
,
534 match_num
= &(bpem
->match_port_num
);
535 mval
= (struct bgp_pbr_match_val
*)
537 offset
+= bgp_flowspec_call_non_opaque_decode(
538 nlri_content
+ offset
,
543 case FLOWSPEC_DEST_PORT
:
544 match_num
= &(bpem
->match_dst_port_num
);
545 mval
= (struct bgp_pbr_match_val
*)
547 offset
+= bgp_flowspec_call_non_opaque_decode(
548 nlri_content
+ offset
,
553 case FLOWSPEC_SRC_PORT
:
554 match_num
= &(bpem
->match_src_port_num
);
555 mval
= (struct bgp_pbr_match_val
*)
557 offset
+= bgp_flowspec_call_non_opaque_decode(
558 nlri_content
+ offset
,
563 case FLOWSPEC_ICMP_TYPE
:
564 match_num
= &(bpem
->match_icmp_type_num
);
565 mval
= (struct bgp_pbr_match_val
*)
567 offset
+= bgp_flowspec_call_non_opaque_decode(
568 nlri_content
+ offset
,
573 case FLOWSPEC_ICMP_CODE
:
574 match_num
= &(bpem
->match_icmp_code_num
);
575 mval
= (struct bgp_pbr_match_val
*)
577 offset
+= bgp_flowspec_call_non_opaque_decode(
578 nlri_content
+ offset
,
583 case FLOWSPEC_PKT_LEN
:
585 &(bpem
->match_packet_length_num
);
586 mval
= (struct bgp_pbr_match_val
*)
587 &(bpem
->packet_length
);
588 offset
+= bgp_flowspec_call_non_opaque_decode(
589 nlri_content
+ offset
,
595 match_num
= &(bpem
->match_dscp_num
);
596 mval
= (struct bgp_pbr_match_val
*)
598 offset
+= bgp_flowspec_call_non_opaque_decode(
599 nlri_content
+ offset
,
604 case FLOWSPEC_TCP_FLAGS
:
605 ret
= bgp_flowspec_bitmask_decode(
606 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
607 nlri_content
+ offset
,
609 &bpem
->tcpflags
, &error
);
612 EC_BGP_FLOWSPEC_PACKET
,
613 "%s: flowspec_tcpflags_decode error %d",
616 bpem
->match_tcpflags_num
= error
;
617 /* contains the number of slots used */
620 case FLOWSPEC_FRAGMENT
:
621 ret
= bgp_flowspec_bitmask_decode(
622 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
623 nlri_content
+ offset
,
624 len
- offset
, &bpem
->fragment
,
628 EC_BGP_FLOWSPEC_PACKET
,
629 "%s: flowspec_fragment_type_decode error %d",
632 bpem
->match_fragment_num
= error
;
636 flog_err(EC_LIB_DEVELOPMENT
, "%s: unknown type %d",
640 if (bpem
->match_packet_length_num
|| bpem
->match_fragment_num
641 || bpem
->match_tcpflags_num
|| bpem
->match_dscp_num
642 || bpem
->match_icmp_code_num
|| bpem
->match_icmp_type_num
643 || bpem
->match_port_num
|| bpem
->match_src_port_num
644 || bpem
->match_dst_port_num
|| bpem
->match_protocol_num
645 || bpem
->match_bitmask
|| bpem
->match_flowlabel_num
)
646 bpem
->type
= BGP_PBR_IPSET
;
647 else if ((bpem
->match_bitmask_iprule
& PREFIX_SRC_PRESENT
) ||
648 (bpem
->match_bitmask_iprule
& PREFIX_DST_PRESENT
))
649 /* the extracted policy rule may not need an
650 * iptables/ipset filtering. check this may not be
651 * a standard ip rule : permit any to any ( eg)
653 bpem
->type
= BGP_PBR_IPRULE
;
655 bpem
->type
= BGP_PBR_UNDEFINED
;
659 /* return 1 if FS entry invalid or no NH IP */
660 bool bgp_flowspec_get_first_nh(struct bgp
*bgp
, struct bgp_path_info
*pi
,
661 struct prefix
*p
, afi_t afi
)
663 struct bgp_pbr_entry_main api
;
665 struct bgp_dest
*dest
= pi
->net
;
666 struct bgp_pbr_entry_action
*api_action
;
668 memset(&api
, 0, sizeof(struct bgp_pbr_entry_main
));
669 if (bgp_pbr_build_and_validate_entry(bgp_dest_get_prefix(dest
), pi
,
673 for (i
= 0; i
< api
.action_num
; i
++) {
674 api_action
= &api
.actions
[i
];
675 if (api_action
->action
!= ACTION_REDIRECT_IP
)
677 p
->family
= afi2family(afi
);
679 p
->prefixlen
= IPV4_MAX_BITLEN
;
680 p
->u
.prefix4
= api_action
->u
.zr
.redirect_ip_v4
;
682 p
->prefixlen
= IPV6_MAX_BITLEN
;
683 memcpy(&p
->u
.prefix6
, &api_action
->u
.zr
.redirect_ip_v6
,
684 sizeof(struct in6_addr
));