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
25 #include "bgp_table.h"
26 #include "bgp_flowspec_util.h"
27 #include "bgp_flowspec_private.h"
30 static void hex2bin(uint8_t *hex
, int *bin
)
35 while (remainder
>= 1 && i
< 8) {
36 bin
[7-i
] = remainder
% 2;
37 remainder
= remainder
/ 2;
44 static int hexstr2num(uint8_t *hexstr
, int len
)
49 for (i
= 0; i
< len
; i
++)
50 num
= hexstr
[i
] + 16*16*num
;
54 /* call bgp_flowspec_op_decode
57 static int bgp_flowspec_call_non_opaque_decode(uint8_t *nlri_content
, int len
,
58 struct bgp_pbr_match_val
*mval
,
59 uint8_t *match_num
, int *error
)
63 ret
= bgp_flowspec_op_decode(
64 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
69 zlog_err("%s: flowspec_op_decode error %d",
76 static bool bgp_flowspec_contains_prefix(struct prefix
*pfs
,
82 int ret
= 0, error
= 0;
83 uint8_t *nlri_content
= (uint8_t *)pfs
->u
.prefix_flowspec
.ptr
;
84 size_t len
= pfs
->u
.prefix_flowspec
.prefixlen
;
85 struct prefix compare
;
88 while (offset
< len
-1 && error
>= 0) {
89 type
= nlri_content
[offset
];
92 case FLOWSPEC_DEST_PREFIX
:
93 case FLOWSPEC_SRC_PREFIX
:
94 memset(&compare
, 0, sizeof(struct prefix
));
95 ret
= bgp_flowspec_ip_address(
96 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
103 compare
.prefixlen
!= input
->prefixlen
)
105 if (compare
.family
!= input
->family
)
107 if ((input
->family
== AF_INET
) &&
108 IPV4_ADDR_SAME(&input
->u
.prefix4
,
111 if ((input
->family
== AF_INET6
) &&
112 IPV6_ADDR_SAME(&input
->u
.prefix6
.s6_addr
,
113 &compare
.u
.prefix6
.s6_addr
))
116 case FLOWSPEC_IP_PROTOCOL
:
118 case FLOWSPEC_DEST_PORT
:
119 case FLOWSPEC_SRC_PORT
:
120 case FLOWSPEC_ICMP_TYPE
:
121 case FLOWSPEC_ICMP_CODE
:
122 ret
= bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY
,
127 case FLOWSPEC_TCP_FLAGS
:
128 ret
= bgp_flowspec_tcpflags_decode(
129 BGP_FLOWSPEC_VALIDATE_ONLY
,
134 case FLOWSPEC_PKT_LEN
:
136 ret
= bgp_flowspec_op_decode(
137 BGP_FLOWSPEC_VALIDATE_ONLY
,
138 nlri_content
+ offset
,
142 case FLOWSPEC_FRAGMENT
:
143 ret
= bgp_flowspec_fragment_type_decode(
144 BGP_FLOWSPEC_VALIDATE_ONLY
,
145 nlri_content
+ offset
,
159 * handle the flowspec address src/dst or generic address NLRI
160 * return number of bytes analysed ( >= 0).
162 int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type
,
165 void *result
, int *error
)
167 char *display
= (char *)result
; /* for return_string */
168 struct prefix
*prefix
= (struct prefix
*)result
;
170 struct prefix prefix_local
;
174 memset(&prefix_local
, 0, sizeof(struct prefix
));
175 /* read the prefix length */
176 prefix_local
.prefixlen
= nlri_ptr
[offset
];
177 psize
= PSIZE(prefix_local
.prefixlen
);
179 /* TODO Flowspec IPv6 Support */
180 prefix_local
.family
= AF_INET
;
181 /* Prefix length check. */
182 if (prefix_local
.prefixlen
> prefix_blen(&prefix_local
) * 8)
184 /* When packet overflow occur return immediately. */
185 if (psize
+ offset
> max_len
)
187 /* Defensive coding, double-check
188 * the psize fits in a struct prefix
190 if (psize
> (ssize_t
)sizeof(prefix_local
.u
))
192 memcpy(&prefix_local
.u
.prefix
, &nlri_ptr
[offset
], psize
);
195 case BGP_FLOWSPEC_RETURN_STRING
:
196 prefix2str(&prefix_local
, display
,
197 BGP_FLOWSPEC_STRING_DISPLAY_MAX
);
199 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
200 PREFIX_COPY_IPV4(prefix
, &prefix_local
)
202 case BGP_FLOWSPEC_VALIDATE_ONLY
:
210 * handle the flowspec operator NLRI
211 * return number of bytes analysed
212 * if there is an error, the passed error param is used to give error:
213 * -1 if decoding error,
214 * if result is a string, its assumed length
215 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
217 int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type
,
220 void *result
, int *error
)
223 int len
, value
, value_size
;
225 char *ptr
= (char *)result
; /* for return_string */
227 int len_string
= BGP_FLOWSPEC_STRING_DISPLAY_MAX
;
229 struct bgp_pbr_match_val
*mval
= (struct bgp_pbr_match_val
*)result
;
233 if (loop
> BGP_PBR_MATCH_VAL_MAX
)
235 hex2bin(&nlri_ptr
[offset
], op
);
238 value_size
= 1 << len
;
239 value
= hexstr2num(&nlri_ptr
[offset
], value_size
);
240 /* can not be < and > at the same time */
241 if (op
[5] == 1 && op
[6] == 1)
243 /* if first element, AND bit can not be set */
244 if (op
[1] == 1 && loop
== 0)
247 case BGP_FLOWSPEC_RETURN_STRING
:
249 len_written
= snprintf(ptr
, len_string
,
251 len_string
-= len_written
;
255 len_written
= snprintf(ptr
, len_string
,
257 len_string
-= len_written
;
261 len_written
= snprintf(ptr
, len_string
,
263 len_string
-= len_written
;
267 len_written
= snprintf(ptr
, len_string
,
269 len_string
-= len_written
;
272 len_written
= snprintf(ptr
, len_string
,
274 len_string
-= len_written
;
277 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
278 /* limitation: stop converting */
283 mval
->compare_operator
|=
284 OPERATOR_COMPARE_LESS_THAN
;
286 mval
->compare_operator
|=
287 OPERATOR_COMPARE_GREATER_THAN
;
289 mval
->compare_operator
|=
290 OPERATOR_COMPARE_EQUAL_TO
;
292 mval
->unary_operator
= OPERATOR_UNARY_AND
;
294 mval
->unary_operator
= OPERATOR_UNARY_OR
;
297 case BGP_FLOWSPEC_VALIDATE_ONLY
:
302 offset
+= value_size
;
304 } while (op
[0] == 0 && offset
< max_len
- 1);
305 if (offset
> max_len
)
307 /* use error parameter to count the number of entries */
315 * handle the flowspec tcpflags field
316 * return number of bytes analysed
317 * if there is an error, the passed error param is used to give error:
318 * -1 if decoding error,
319 * if result is a string, its assumed length
320 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
322 int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type
,
325 void *result
, int *error
)
328 int len
, value_size
, loop
= 0, value
;
329 char *ptr
= (char *)result
; /* for return_string */
330 struct bgp_pbr_match_val
*mval
= (struct bgp_pbr_match_val
*)result
;
332 int len_string
= BGP_FLOWSPEC_STRING_DISPLAY_MAX
;
337 if (loop
> BGP_PBR_MATCH_VAL_MAX
)
339 hex2bin(&nlri_ptr
[offset
], op
);
340 /* if first element, AND bit can not be set */
341 if (op
[1] == 1 && loop
== 0)
344 len
= 2 * op
[2] + op
[3];
345 value_size
= 1 << len
;
346 value
= hexstr2num(&nlri_ptr
[offset
], value_size
);
348 case BGP_FLOWSPEC_RETURN_STRING
:
349 if (op
[1] == 1 && loop
!= 0) {
350 len_written
= snprintf(ptr
, len_string
,
352 len_string
-= len_written
;
354 } else if (op
[1] == 0 && loop
!= 0) {
355 len_written
= snprintf(ptr
, len_string
,
357 len_string
-= len_written
;
361 len_written
= snprintf(ptr
, len_string
,
363 len_string
-= len_written
;
366 len_written
= snprintf(ptr
, len_string
,
368 len_string
-= len_written
;
372 len_written
= snprintf(ptr
, len_string
,
374 len_string
-= len_written
;
377 len_written
= snprintf(ptr
, len_string
,
379 len_string
-= len_written
;
382 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
383 /* limitation: stop converting */
389 mval
->compare_operator
|=
390 OPERATOR_COMPARE_LESS_THAN
;
391 mval
->compare_operator
|=
392 OPERATOR_COMPARE_GREATER_THAN
;
394 mval
->compare_operator
|=
395 OPERATOR_COMPARE_EQUAL_TO
;
397 mval
->compare_operator
|=
398 OPERATOR_COMPARE_EXACT_MATCH
;
400 mval
->unary_operator
=
403 mval
->unary_operator
=
407 case BGP_FLOWSPEC_VALIDATE_ONLY
:
412 offset
+= value_size
;
414 } while (op
[0] == 0 && offset
< max_len
- 1);
415 if (offset
> max_len
)
417 /* use error parameter to count the number of entries */
424 * handle the flowspec fragment type field
425 * return error (returned values are invalid) or number of bytes analysed
426 * -1 if error in decoding
427 * >= 0 : number of bytes analysed (ok).
429 int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type
,
432 void *result
, int *error
)
435 int len
, value
, value_size
, loop
= 0;
436 char *ptr
= (char *)result
; /* for return_string */
437 struct bgp_pbr_fragment_val
*mval
=
438 (struct bgp_pbr_fragment_val
*)result
;
440 int len_string
= BGP_FLOWSPEC_STRING_DISPLAY_MAX
;
445 hex2bin(&nlri_ptr
[offset
], op
);
447 len
= 2 * op
[2] + op
[3];
448 value_size
= 1 << len
;
449 value
= hexstr2num(&nlri_ptr
[offset
], value_size
);
450 if (value
!= 1 && value
!= 2 && value
!= 4 && value
!= 8)
452 offset
+= value_size
;
453 /* TODO : as per RFC5574 : first Fragment bits are Reserved
454 * does that mean that it is not possible
455 * to handle multiple occurences ?
456 * as of today, we only grab the first TCP fragment
464 case BGP_FLOWSPEC_RETURN_STRING
:
467 len_written
= snprintf(ptr
, len_string
,
469 len_string
-= len_written
;
473 len_written
= snprintf(ptr
, len_string
,
475 len_string
-= len_written
;
479 len_written
= snprintf(ptr
, len_string
,
481 len_string
-= len_written
;
485 len_written
= snprintf(ptr
, len_string
,
487 len_string
-= len_written
;
494 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
495 mval
->bitmask
= (uint8_t)value
;
497 case BGP_FLOWSPEC_VALIDATE_ONLY
:
503 } while (op
[0] == 0 && offset
< max_len
- 1);
504 if (offset
> max_len
)
509 int bgp_flowspec_match_rules_fill(uint8_t *nlri_content
, int len
,
510 struct bgp_pbr_entry_main
*bpem
)
512 int offset
= 0, error
= 0;
513 struct prefix
*prefix
;
514 struct bgp_pbr_match_val
*mval
;
519 while (offset
< len
- 1 && error
>= 0) {
520 type
= nlri_content
[offset
];
523 case FLOWSPEC_DEST_PREFIX
:
524 case FLOWSPEC_SRC_PREFIX
:
526 if (type
== FLOWSPEC_DEST_PREFIX
) {
527 bitmask
|= PREFIX_DST_PRESENT
;
528 prefix
= &bpem
->dst_prefix
;
530 bitmask
|= PREFIX_SRC_PRESENT
;
531 prefix
= &bpem
->src_prefix
;
533 ret
= bgp_flowspec_ip_address(
534 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
535 nlri_content
+ offset
,
539 zlog_err("%s: flowspec_ip_address error %d",
542 bpem
->match_bitmask
|= bitmask
;
545 case FLOWSPEC_IP_PROTOCOL
:
546 match_num
= &(bpem
->match_protocol_num
);
547 mval
= (struct bgp_pbr_match_val
*)
549 offset
+= bgp_flowspec_call_non_opaque_decode(
550 nlri_content
+ offset
,
556 match_num
= &(bpem
->match_port_num
);
557 mval
= (struct bgp_pbr_match_val
*)
559 offset
+= bgp_flowspec_call_non_opaque_decode(
560 nlri_content
+ offset
,
565 case FLOWSPEC_DEST_PORT
:
566 match_num
= &(bpem
->match_dst_port_num
);
567 mval
= (struct bgp_pbr_match_val
*)
569 offset
+= bgp_flowspec_call_non_opaque_decode(
570 nlri_content
+ offset
,
575 case FLOWSPEC_SRC_PORT
:
576 match_num
= &(bpem
->match_src_port_num
);
577 mval
= (struct bgp_pbr_match_val
*)
579 offset
+= bgp_flowspec_call_non_opaque_decode(
580 nlri_content
+ offset
,
585 case FLOWSPEC_ICMP_TYPE
:
586 match_num
= &(bpem
->match_icmp_type_num
);
587 mval
= (struct bgp_pbr_match_val
*)
589 offset
+= bgp_flowspec_call_non_opaque_decode(
590 nlri_content
+ offset
,
595 case FLOWSPEC_ICMP_CODE
:
596 match_num
= &(bpem
->match_icmp_code_num
);
597 mval
= (struct bgp_pbr_match_val
*)
599 offset
+= bgp_flowspec_call_non_opaque_decode(
600 nlri_content
+ offset
,
605 case FLOWSPEC_PKT_LEN
:
607 &(bpem
->match_packet_length_num
);
608 mval
= (struct bgp_pbr_match_val
*)
609 &(bpem
->packet_length
);
610 offset
+= bgp_flowspec_call_non_opaque_decode(
611 nlri_content
+ offset
,
617 match_num
= &(bpem
->match_dscp_num
);
618 mval
= (struct bgp_pbr_match_val
*)
620 offset
+= bgp_flowspec_call_non_opaque_decode(
621 nlri_content
+ offset
,
626 case FLOWSPEC_TCP_FLAGS
:
627 ret
= bgp_flowspec_tcpflags_decode(
628 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
629 nlri_content
+ offset
,
631 &bpem
->tcpflags
, &error
);
633 zlog_err("%s: flowspec_tcpflags_decode error %d",
636 bpem
->match_tcpflags_num
= error
;
637 /* contains the number of slots used */
640 case FLOWSPEC_FRAGMENT
:
641 ret
= bgp_flowspec_fragment_type_decode(
642 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
643 nlri_content
+ offset
,
644 len
- offset
, &bpem
->fragment
,
647 zlog_err("%s: flowspec_fragment_type_decode error %d",
650 bpem
->match_bitmask
|= FRAGMENT_PRESENT
;
654 zlog_err("%s: unknown type %d\n", __func__
, type
);
661 struct bgp_node
*bgp_flowspec_get_match_per_ip(afi_t afi
,
662 struct bgp_table
*rib
,
663 struct prefix
*match
,
667 struct prefix
*prefix
;
669 for (rn
= bgp_table_top(rib
); rn
; rn
= bgp_route_next(rn
)) {
672 if (prefix
->family
!= AF_FLOWSPEC
)
675 if (bgp_flowspec_contains_prefix(prefix
, match
, prefix_check
))