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
24 #include "lib_errors.h"
26 #include "bgp_table.h"
27 #include "bgp_flowspec_util.h"
28 #include "bgp_flowspec_private.h"
31 static void hex2bin(uint8_t *hex
, int *bin
)
36 while (remainder
>= 1 && i
< 8) {
37 bin
[7-i
] = remainder
% 2;
38 remainder
= remainder
/ 2;
45 static int hexstr2num(uint8_t *hexstr
, int len
)
50 for (i
= 0; i
< len
; i
++)
51 num
= hexstr
[i
] + 16*16*num
;
55 /* call bgp_flowspec_op_decode
58 static int bgp_flowspec_call_non_opaque_decode(uint8_t *nlri_content
, int len
,
59 struct bgp_pbr_match_val
*mval
,
60 uint8_t *match_num
, int *error
)
64 ret
= bgp_flowspec_op_decode(
65 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
70 zlog_err("%s: flowspec_op_decode error %d",
77 bool bgp_flowspec_contains_prefix(struct prefix
*pfs
,
83 int ret
= 0, error
= 0;
84 uint8_t *nlri_content
= (uint8_t *)pfs
->u
.prefix_flowspec
.ptr
;
85 size_t len
= pfs
->u
.prefix_flowspec
.prefixlen
;
86 struct prefix compare
;
89 while (offset
< len
-1 && error
>= 0) {
90 type
= nlri_content
[offset
];
93 case FLOWSPEC_DEST_PREFIX
:
94 case FLOWSPEC_SRC_PREFIX
:
95 memset(&compare
, 0, sizeof(struct prefix
));
96 ret
= bgp_flowspec_ip_address(
97 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
104 compare
.prefixlen
!= input
->prefixlen
)
106 if (compare
.family
!= input
->family
)
108 if ((input
->family
== AF_INET
) &&
109 IPV4_ADDR_SAME(&input
->u
.prefix4
,
112 if ((input
->family
== AF_INET6
) &&
113 IPV6_ADDR_SAME(&input
->u
.prefix6
.s6_addr
,
114 &compare
.u
.prefix6
.s6_addr
))
117 case FLOWSPEC_IP_PROTOCOL
:
119 case FLOWSPEC_DEST_PORT
:
120 case FLOWSPEC_SRC_PORT
:
121 case FLOWSPEC_ICMP_TYPE
:
122 case FLOWSPEC_ICMP_CODE
:
123 ret
= bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY
,
128 case FLOWSPEC_FRAGMENT
:
129 case FLOWSPEC_TCP_FLAGS
:
130 ret
= bgp_flowspec_bitmask_decode(
131 BGP_FLOWSPEC_VALIDATE_ONLY
,
136 case FLOWSPEC_PKT_LEN
:
138 ret
= bgp_flowspec_op_decode(
139 BGP_FLOWSPEC_VALIDATE_ONLY
,
140 nlri_content
+ offset
,
154 * handle the flowspec address src/dst or generic address NLRI
155 * return number of bytes analysed ( >= 0).
157 int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type
,
160 void *result
, int *error
)
162 char *display
= (char *)result
; /* for return_string */
163 struct prefix
*prefix
= (struct prefix
*)result
;
165 struct prefix prefix_local
;
169 memset(&prefix_local
, 0, sizeof(struct prefix
));
170 /* read the prefix length */
171 prefix_local
.prefixlen
= nlri_ptr
[offset
];
172 psize
= PSIZE(prefix_local
.prefixlen
);
174 /* TODO Flowspec IPv6 Support */
175 prefix_local
.family
= AF_INET
;
176 /* Prefix length check. */
177 if (prefix_local
.prefixlen
> prefix_blen(&prefix_local
) * 8)
179 /* When packet overflow occur return immediately. */
180 if (psize
+ offset
> max_len
)
182 /* Defensive coding, double-check
183 * the psize fits in a struct prefix
185 if (psize
> (ssize_t
)sizeof(prefix_local
.u
))
187 memcpy(&prefix_local
.u
.prefix
, &nlri_ptr
[offset
], psize
);
190 case BGP_FLOWSPEC_RETURN_STRING
:
191 prefix2str(&prefix_local
, display
,
192 BGP_FLOWSPEC_STRING_DISPLAY_MAX
);
194 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
195 PREFIX_COPY_IPV4(prefix
, &prefix_local
)
197 case BGP_FLOWSPEC_VALIDATE_ONLY
:
205 * handle the flowspec operator NLRI
206 * return number of bytes analysed
207 * if there is an error, the passed error param is used to give error:
208 * -1 if decoding error,
209 * if result is a string, its assumed length
210 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
212 int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type
,
215 void *result
, int *error
)
218 int len
, value
, value_size
;
220 char *ptr
= (char *)result
; /* for return_string */
222 int len_string
= BGP_FLOWSPEC_STRING_DISPLAY_MAX
;
224 struct bgp_pbr_match_val
*mval
= (struct bgp_pbr_match_val
*)result
;
228 if (loop
> BGP_PBR_MATCH_VAL_MAX
)
230 hex2bin(&nlri_ptr
[offset
], op
);
233 value_size
= 1 << len
;
234 value
= hexstr2num(&nlri_ptr
[offset
], value_size
);
235 /* can not be < and > at the same time */
236 if (op
[5] == 1 && op
[6] == 1)
238 /* if first element, AND bit can not be set */
239 if (op
[1] == 1 && loop
== 0)
242 case BGP_FLOWSPEC_RETURN_STRING
:
244 len_written
= snprintf(ptr
, len_string
,
246 len_string
-= len_written
;
250 len_written
= snprintf(ptr
, len_string
,
252 len_string
-= len_written
;
256 len_written
= snprintf(ptr
, len_string
,
258 len_string
-= len_written
;
262 len_written
= snprintf(ptr
, len_string
,
264 len_string
-= len_written
;
267 len_written
= snprintf(ptr
, len_string
,
269 len_string
-= len_written
;
272 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
273 /* limitation: stop converting */
278 mval
->compare_operator
|=
279 OPERATOR_COMPARE_LESS_THAN
;
281 mval
->compare_operator
|=
282 OPERATOR_COMPARE_GREATER_THAN
;
284 mval
->compare_operator
|=
285 OPERATOR_COMPARE_EQUAL_TO
;
287 mval
->unary_operator
= OPERATOR_UNARY_AND
;
289 mval
->unary_operator
= OPERATOR_UNARY_OR
;
292 case BGP_FLOWSPEC_VALIDATE_ONLY
:
297 offset
+= value_size
;
299 } while (op
[0] == 0 && offset
< max_len
- 1);
300 if (offset
> max_len
)
302 /* use error parameter to count the number of entries */
310 * handle the flowspec tcpflags or fragment field
311 * return number of bytes analysed
312 * if there is an error, the passed error param is used to give error:
313 * -1 if decoding error,
314 * if result is a string, its assumed length
315 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
317 int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type
,
320 void *result
, int *error
)
323 int len
, value_size
, loop
= 0, value
;
324 char *ptr
= (char *)result
; /* for return_string */
325 struct bgp_pbr_match_val
*mval
= (struct bgp_pbr_match_val
*)result
;
327 int len_string
= BGP_FLOWSPEC_STRING_DISPLAY_MAX
;
332 if (loop
> BGP_PBR_MATCH_VAL_MAX
)
334 hex2bin(&nlri_ptr
[offset
], op
);
335 /* if first element, AND bit can not be set */
336 if (op
[1] == 1 && loop
== 0)
339 len
= 2 * op
[2] + op
[3];
340 value_size
= 1 << len
;
341 value
= hexstr2num(&nlri_ptr
[offset
], value_size
);
343 case BGP_FLOWSPEC_RETURN_STRING
:
344 if (op
[1] == 1 && loop
!= 0) {
345 len_written
= snprintf(ptr
, len_string
,
347 len_string
-= len_written
;
349 } else if (op
[1] == 0 && loop
!= 0) {
350 len_written
= snprintf(ptr
, len_string
,
352 len_string
-= len_written
;
356 len_written
= snprintf(ptr
, len_string
,
358 len_string
-= len_written
;
361 len_written
= snprintf(ptr
, len_string
,
363 len_string
-= len_written
;
367 len_written
= snprintf(ptr
, len_string
,
369 len_string
-= len_written
;
372 len_written
= snprintf(ptr
, len_string
,
374 len_string
-= len_written
;
377 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
378 /* limitation: stop converting */
384 mval
->compare_operator
|=
385 OPERATOR_COMPARE_LESS_THAN
;
386 mval
->compare_operator
|=
387 OPERATOR_COMPARE_GREATER_THAN
;
389 mval
->compare_operator
|=
390 OPERATOR_COMPARE_EQUAL_TO
;
392 mval
->compare_operator
|=
393 OPERATOR_COMPARE_EXACT_MATCH
;
395 mval
->unary_operator
=
398 mval
->unary_operator
=
402 case BGP_FLOWSPEC_VALIDATE_ONLY
:
407 offset
+= value_size
;
409 } while (op
[0] == 0 && offset
< max_len
- 1);
410 if (offset
> max_len
)
412 /* use error parameter to count the number of entries */
418 int bgp_flowspec_match_rules_fill(uint8_t *nlri_content
, int len
,
419 struct bgp_pbr_entry_main
*bpem
)
421 int offset
= 0, error
= 0;
422 struct prefix
*prefix
;
423 struct bgp_pbr_match_val
*mval
;
428 while (offset
< len
- 1 && error
>= 0) {
429 type
= nlri_content
[offset
];
432 case FLOWSPEC_DEST_PREFIX
:
433 case FLOWSPEC_SRC_PREFIX
:
435 if (type
== FLOWSPEC_DEST_PREFIX
) {
436 bitmask
|= PREFIX_DST_PRESENT
;
437 prefix
= &bpem
->dst_prefix
;
439 bitmask
|= PREFIX_SRC_PRESENT
;
440 prefix
= &bpem
->src_prefix
;
442 ret
= bgp_flowspec_ip_address(
443 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
444 nlri_content
+ offset
,
448 zlog_err("%s: flowspec_ip_address error %d",
451 bpem
->match_bitmask
|= bitmask
;
454 case FLOWSPEC_IP_PROTOCOL
:
455 match_num
= &(bpem
->match_protocol_num
);
456 mval
= (struct bgp_pbr_match_val
*)
458 offset
+= bgp_flowspec_call_non_opaque_decode(
459 nlri_content
+ offset
,
465 match_num
= &(bpem
->match_port_num
);
466 mval
= (struct bgp_pbr_match_val
*)
468 offset
+= bgp_flowspec_call_non_opaque_decode(
469 nlri_content
+ offset
,
474 case FLOWSPEC_DEST_PORT
:
475 match_num
= &(bpem
->match_dst_port_num
);
476 mval
= (struct bgp_pbr_match_val
*)
478 offset
+= bgp_flowspec_call_non_opaque_decode(
479 nlri_content
+ offset
,
484 case FLOWSPEC_SRC_PORT
:
485 match_num
= &(bpem
->match_src_port_num
);
486 mval
= (struct bgp_pbr_match_val
*)
488 offset
+= bgp_flowspec_call_non_opaque_decode(
489 nlri_content
+ offset
,
494 case FLOWSPEC_ICMP_TYPE
:
495 match_num
= &(bpem
->match_icmp_type_num
);
496 mval
= (struct bgp_pbr_match_val
*)
498 offset
+= bgp_flowspec_call_non_opaque_decode(
499 nlri_content
+ offset
,
504 case FLOWSPEC_ICMP_CODE
:
505 match_num
= &(bpem
->match_icmp_code_num
);
506 mval
= (struct bgp_pbr_match_val
*)
508 offset
+= bgp_flowspec_call_non_opaque_decode(
509 nlri_content
+ offset
,
514 case FLOWSPEC_PKT_LEN
:
516 &(bpem
->match_packet_length_num
);
517 mval
= (struct bgp_pbr_match_val
*)
518 &(bpem
->packet_length
);
519 offset
+= bgp_flowspec_call_non_opaque_decode(
520 nlri_content
+ offset
,
526 match_num
= &(bpem
->match_dscp_num
);
527 mval
= (struct bgp_pbr_match_val
*)
529 offset
+= bgp_flowspec_call_non_opaque_decode(
530 nlri_content
+ offset
,
535 case FLOWSPEC_TCP_FLAGS
:
536 ret
= bgp_flowspec_bitmask_decode(
537 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
538 nlri_content
+ offset
,
540 &bpem
->tcpflags
, &error
);
542 zlog_err("%s: flowspec_tcpflags_decode error %d",
545 bpem
->match_tcpflags_num
= error
;
546 /* contains the number of slots used */
549 case FLOWSPEC_FRAGMENT
:
550 ret
= bgp_flowspec_bitmask_decode(
551 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
552 nlri_content
+ offset
,
553 len
- offset
, &bpem
->fragment
,
556 zlog_err("%s: flowspec_fragment_type_decode error %d",
559 bpem
->match_fragment_num
= error
;
563 zlog_ferr(LIB_ERR_DEVELOPMENT
, "%s: unknown type %d\n",