]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_flowspec_util.c
Merge pull request #2164 from donaldsharp/pbr_nht_eats_gcc
[mirror_frr.git] / bgpd / bgp_flowspec_util.c
1 /* BGP FlowSpec Utilities
2 * Portions:
3 * Copyright (C) 2017 ChinaTelecom SDN Group
4 * Copyright (C) 2018 6WIND
5 *
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
9 * later version.
10 *
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.
15 *
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
19 */
20
21 #include "zebra.h"
22
23 #include "prefix.h"
24
25 #include "bgp_table.h"
26 #include "bgp_flowspec_util.h"
27 #include "bgp_flowspec_private.h"
28 #include "bgp_pbr.h"
29
30 static void hex2bin(uint8_t *hex, int *bin)
31 {
32 int remainder = *hex;
33 int i = 0;
34
35 while (remainder >= 1 && i < 8) {
36 bin[7-i] = remainder % 2;
37 remainder = remainder / 2;
38 i++;
39 }
40 for (; i < 8; i++)
41 bin[7-i] = 0;
42 }
43
44 static int hexstr2num(uint8_t *hexstr, int len)
45 {
46 int i = 0;
47 int num = 0;
48
49 for (i = 0; i < len; i++)
50 num = hexstr[i] + 16*16*num;
51 return num;
52 }
53
54 /* call bgp_flowspec_op_decode
55 * returns offset
56 */
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)
60 {
61 int ret;
62
63 ret = bgp_flowspec_op_decode(
64 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
65 nlri_content,
66 len,
67 mval, error);
68 if (*error < 0)
69 zlog_err("%s: flowspec_op_decode error %d",
70 __func__, *error);
71 else
72 *match_num = *error;
73 return ret;
74 }
75
76 static bool bgp_flowspec_contains_prefix(struct prefix *pfs,
77 struct prefix *input,
78 int prefix_check)
79 {
80 uint32_t offset = 0;
81 int type;
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;
86
87 error = 0;
88 while (offset < len-1 && error >= 0) {
89 type = nlri_content[offset];
90 offset++;
91 switch (type) {
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,
97 nlri_content+offset,
98 len - offset,
99 &compare, &error);
100 if (ret <= 0)
101 break;
102 if (prefix_check &&
103 compare.prefixlen != input->prefixlen)
104 break;
105 if (compare.family != input->family)
106 break;
107 if ((input->family == AF_INET) &&
108 IPV4_ADDR_SAME(&input->u.prefix4,
109 &compare.u.prefix4))
110 return true;
111 if ((input->family == AF_INET6) &&
112 IPV6_ADDR_SAME(&input->u.prefix6.s6_addr,
113 &compare.u.prefix6.s6_addr))
114 return true;
115 break;
116 case FLOWSPEC_IP_PROTOCOL:
117 case FLOWSPEC_PORT:
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,
123 nlri_content+offset,
124 len - offset,
125 NULL, &error);
126 break;
127 case FLOWSPEC_TCP_FLAGS:
128 ret = bgp_flowspec_tcpflags_decode(
129 BGP_FLOWSPEC_VALIDATE_ONLY,
130 nlri_content+offset,
131 len - offset,
132 NULL, &error);
133 break;
134 case FLOWSPEC_PKT_LEN:
135 case FLOWSPEC_DSCP:
136 ret = bgp_flowspec_op_decode(
137 BGP_FLOWSPEC_VALIDATE_ONLY,
138 nlri_content + offset,
139 len - offset, NULL,
140 &error);
141 break;
142 case FLOWSPEC_FRAGMENT:
143 ret = bgp_flowspec_fragment_type_decode(
144 BGP_FLOWSPEC_VALIDATE_ONLY,
145 nlri_content + offset,
146 len - offset, NULL,
147 &error);
148 break;
149 default:
150 error = -1;
151 break;
152 }
153 offset += ret;
154 }
155 return false;
156 }
157
158 /*
159 * handle the flowspec address src/dst or generic address NLRI
160 * return number of bytes analysed ( >= 0).
161 */
162 int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
163 uint8_t *nlri_ptr,
164 uint32_t max_len,
165 void *result, int *error)
166 {
167 char *display = (char *)result; /* for return_string */
168 struct prefix *prefix = (struct prefix *)result;
169 uint32_t offset = 0;
170 struct prefix prefix_local;
171 int psize;
172
173 *error = 0;
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);
178 offset++;
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)
183 *error = -1;
184 /* When packet overflow occur return immediately. */
185 if (psize + offset > max_len)
186 *error = -1;
187 /* Defensive coding, double-check
188 * the psize fits in a struct prefix
189 */
190 if (psize > (ssize_t)sizeof(prefix_local.u))
191 *error = -1;
192 memcpy(&prefix_local.u.prefix, &nlri_ptr[offset], psize);
193 offset += psize;
194 switch (type) {
195 case BGP_FLOWSPEC_RETURN_STRING:
196 prefix2str(&prefix_local, display,
197 BGP_FLOWSPEC_STRING_DISPLAY_MAX);
198 break;
199 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
200 PREFIX_COPY_IPV4(prefix, &prefix_local)
201 break;
202 case BGP_FLOWSPEC_VALIDATE_ONLY:
203 default:
204 break;
205 }
206 return offset;
207 }
208
209 /*
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
216 */
217 int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
218 uint8_t *nlri_ptr,
219 uint32_t max_len,
220 void *result, int *error)
221 {
222 int op[8];
223 int len, value, value_size;
224 int loop = 0;
225 char *ptr = (char *)result; /* for return_string */
226 uint32_t offset = 0;
227 int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
228 int len_written;
229 struct bgp_pbr_match_val *mval = (struct bgp_pbr_match_val *)result;
230
231 *error = 0;
232 do {
233 if (loop > BGP_PBR_MATCH_VAL_MAX)
234 *error = -2;
235 hex2bin(&nlri_ptr[offset], op);
236 offset++;
237 len = 2*op[2]+op[3];
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)
242 *error = -1;
243 /* if first element, AND bit can not be set */
244 if (op[1] == 1 && loop == 0)
245 *error = -1;
246 switch (type) {
247 case BGP_FLOWSPEC_RETURN_STRING:
248 if (loop) {
249 len_written = snprintf(ptr, len_string,
250 ", ");
251 len_string -= len_written;
252 ptr += len_written;
253 }
254 if (op[5] == 1) {
255 len_written = snprintf(ptr, len_string,
256 "<");
257 len_string -= len_written;
258 ptr += len_written;
259 }
260 if (op[6] == 1) {
261 len_written = snprintf(ptr, len_string,
262 ">");
263 len_string -= len_written;
264 ptr += len_written;
265 }
266 if (op[7] == 1) {
267 len_written = snprintf(ptr, len_string,
268 "=");
269 len_string -= len_written;
270 ptr += len_written;
271 }
272 len_written = snprintf(ptr, len_string,
273 " %d ", value);
274 len_string -= len_written;
275 ptr += len_written;
276 break;
277 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
278 /* limitation: stop converting */
279 if (*error == -2)
280 break;
281 mval->value = value;
282 if (op[5] == 1)
283 mval->compare_operator |=
284 OPERATOR_COMPARE_LESS_THAN;
285 if (op[6] == 1)
286 mval->compare_operator |=
287 OPERATOR_COMPARE_GREATER_THAN;
288 if (op[7] == 1)
289 mval->compare_operator |=
290 OPERATOR_COMPARE_EQUAL_TO;
291 if (op[1] == 1)
292 mval->unary_operator = OPERATOR_UNARY_AND;
293 else
294 mval->unary_operator = OPERATOR_UNARY_OR;
295 mval++;
296 break;
297 case BGP_FLOWSPEC_VALIDATE_ONLY:
298 default:
299 /* no action */
300 break;
301 }
302 offset += value_size;
303 loop++;
304 } while (op[0] == 0 && offset < max_len - 1);
305 if (offset > max_len)
306 *error = -1;
307 /* use error parameter to count the number of entries */
308 if (*error == 0)
309 *error = loop;
310 return offset;
311 }
312
313
314 /*
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
321 */
322 int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
323 uint8_t *nlri_ptr,
324 uint32_t max_len,
325 void *result, int *error)
326 {
327 int op[8];
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;
331 uint32_t offset = 0;
332 int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
333 int len_written;
334
335 *error = 0;
336 do {
337 if (loop > BGP_PBR_MATCH_VAL_MAX)
338 *error = -2;
339 hex2bin(&nlri_ptr[offset], op);
340 /* if first element, AND bit can not be set */
341 if (op[1] == 1 && loop == 0)
342 *error = -1;
343 offset++;
344 len = 2 * op[2] + op[3];
345 value_size = 1 << len;
346 value = hexstr2num(&nlri_ptr[offset], value_size);
347 switch (type) {
348 case BGP_FLOWSPEC_RETURN_STRING:
349 if (op[1] == 1 && loop != 0) {
350 len_written = snprintf(ptr, len_string,
351 ", and ");
352 len_string -= len_written;
353 ptr += len_written;
354 } else if (op[1] == 0 && loop != 0) {
355 len_written = snprintf(ptr, len_string,
356 ", or ");
357 len_string -= len_written;
358 ptr += len_written;
359 }
360 len_written = snprintf(ptr, len_string,
361 "tcp flags is ");
362 len_string -= len_written;
363 ptr += len_written;
364 if (op[6] == 1) {
365 ptr += snprintf(ptr, len_string,
366 "not ");
367 len_string -= len_written;
368 ptr += len_written;
369 }
370 if (op[7] == 1) {
371 ptr += snprintf(ptr, len_string,
372 "exactly match ");
373 len_string -= len_written;
374 ptr += len_written;
375 }
376 ptr += snprintf(ptr, len_string,
377 "%d", value);
378 len_string -= len_written;
379 ptr += len_written;
380 break;
381 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
382 /* limitation: stop converting */
383 if (*error == -2)
384 break;
385 mval->value = value;
386 if (op[6] == 1) {
387 /* different from */
388 mval->compare_operator |=
389 OPERATOR_COMPARE_LESS_THAN;
390 mval->compare_operator |=
391 OPERATOR_COMPARE_GREATER_THAN;
392 } else
393 mval->compare_operator |=
394 OPERATOR_COMPARE_EQUAL_TO;
395 if (op[7] == 1)
396 mval->compare_operator |=
397 OPERATOR_COMPARE_EXACT_MATCH;
398 if (op[1] == 1)
399 mval->unary_operator =
400 OPERATOR_UNARY_AND;
401 else
402 mval->unary_operator =
403 OPERATOR_UNARY_OR;
404 mval++;
405 break;
406 case BGP_FLOWSPEC_VALIDATE_ONLY:
407 default:
408 /* no action */
409 break;
410 }
411 offset += value_size;
412 loop++;
413 } while (op[0] == 0 && offset < max_len - 1);
414 if (offset > max_len)
415 *error = -1;
416 /* use error parameter to count the number of entries */
417 if (*error == 0)
418 *error = loop;
419 return offset;
420 }
421
422 /*
423 * handle the flowspec fragment type field
424 * return error (returned values are invalid) or number of bytes analysed
425 * -1 if error in decoding
426 * >= 0 : number of bytes analysed (ok).
427 */
428 int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type,
429 uint8_t *nlri_ptr,
430 uint32_t max_len,
431 void *result, int *error)
432 {
433 int op[8];
434 int len, value, value_size, loop = 0;
435 char *ptr = (char *)result; /* for return_string */
436 struct bgp_pbr_fragment_val *mval =
437 (struct bgp_pbr_fragment_val *)result;
438 uint32_t offset = 0;
439 int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
440 int len_written;
441
442 *error = 0;
443 do {
444 hex2bin(&nlri_ptr[offset], op);
445 offset++;
446 len = 2 * op[2] + op[3];
447 value_size = 1 << len;
448 value = hexstr2num(&nlri_ptr[offset], value_size);
449 if (value != 1 && value != 2 && value != 4 && value != 8)
450 *error = -1;
451 offset += value_size;
452 /* TODO : as per RFC5574 : first Fragment bits are Reserved
453 * does that mean that it is not possible
454 * to handle multiple occurences ?
455 * as of today, we only grab the first TCP fragment
456 */
457 if (loop) {
458 *error = -2;
459 loop++;
460 continue;
461 }
462 switch (type) {
463 case BGP_FLOWSPEC_RETURN_STRING:
464 switch (value) {
465 case 1:
466 len_written = snprintf(ptr, len_string,
467 "dont-fragment");
468 len_string -= len_written;
469 ptr += len_written;
470 break;
471 case 2:
472 len_written = snprintf(ptr, len_string,
473 "is-fragment");
474 len_string -= len_written;
475 ptr += len_written;
476 break;
477 case 4:
478 len_written = snprintf(ptr, len_string,
479 "first-fragment");
480 len_string -= len_written;
481 ptr += len_written;
482 break;
483 case 8:
484 len_written = snprintf(ptr, len_string,
485 "last-fragment");
486 len_string -= len_written;
487 ptr += len_written;
488 break;
489 default:
490 {}
491 }
492 break;
493 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
494 mval->bitmask = (uint8_t)value;
495 break;
496 case BGP_FLOWSPEC_VALIDATE_ONLY:
497 default:
498 /* no action */
499 break;
500 }
501 loop++;
502 } while (op[0] == 0 && offset < max_len - 1);
503 if (offset > max_len)
504 *error = -1;
505 return offset;
506 }
507
508 int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
509 struct bgp_pbr_entry_main *bpem)
510 {
511 int offset = 0, error = 0;
512 struct prefix *prefix;
513 struct bgp_pbr_match_val *mval;
514 uint8_t *match_num;
515 uint8_t bitmask = 0;
516 int ret = 0, type;
517
518 while (offset < len - 1 && error >= 0) {
519 type = nlri_content[offset];
520 offset++;
521 switch (type) {
522 case FLOWSPEC_DEST_PREFIX:
523 case FLOWSPEC_SRC_PREFIX:
524 bitmask = 0;
525 if (type == FLOWSPEC_DEST_PREFIX) {
526 bitmask |= PREFIX_DST_PRESENT;
527 prefix = &bpem->dst_prefix;
528 } else {
529 bitmask |= PREFIX_SRC_PRESENT;
530 prefix = &bpem->src_prefix;
531 }
532 ret = bgp_flowspec_ip_address(
533 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
534 nlri_content + offset,
535 len - offset,
536 prefix, &error);
537 if (error < 0)
538 zlog_err("%s: flowspec_ip_address error %d",
539 __func__, error);
540 else
541 bpem->match_bitmask |= bitmask;
542 offset += ret;
543 break;
544 case FLOWSPEC_IP_PROTOCOL:
545 match_num = &(bpem->match_protocol_num);
546 mval = (struct bgp_pbr_match_val *)
547 &(bpem->protocol);
548 offset += bgp_flowspec_call_non_opaque_decode(
549 nlri_content + offset,
550 len - offset,
551 mval, match_num,
552 &error);
553 break;
554 case FLOWSPEC_PORT:
555 match_num = &(bpem->match_port_num);
556 mval = (struct bgp_pbr_match_val *)
557 &(bpem->port);
558 offset += bgp_flowspec_call_non_opaque_decode(
559 nlri_content + offset,
560 len - offset,
561 mval, match_num,
562 &error);
563 break;
564 case FLOWSPEC_DEST_PORT:
565 match_num = &(bpem->match_dst_port_num);
566 mval = (struct bgp_pbr_match_val *)
567 &(bpem->dst_port);
568 offset += bgp_flowspec_call_non_opaque_decode(
569 nlri_content + offset,
570 len - offset,
571 mval, match_num,
572 &error);
573 break;
574 case FLOWSPEC_SRC_PORT:
575 match_num = &(bpem->match_src_port_num);
576 mval = (struct bgp_pbr_match_val *)
577 &(bpem->src_port);
578 offset += bgp_flowspec_call_non_opaque_decode(
579 nlri_content + offset,
580 len - offset,
581 mval, match_num,
582 &error);
583 break;
584 case FLOWSPEC_ICMP_TYPE:
585 match_num = &(bpem->match_icmp_type_num);
586 mval = (struct bgp_pbr_match_val *)
587 &(bpem->icmp_type);
588 offset += bgp_flowspec_call_non_opaque_decode(
589 nlri_content + offset,
590 len - offset,
591 mval, match_num,
592 &error);
593 break;
594 case FLOWSPEC_ICMP_CODE:
595 match_num = &(bpem->match_icmp_code_num);
596 mval = (struct bgp_pbr_match_val *)
597 &(bpem->icmp_code);
598 offset += bgp_flowspec_call_non_opaque_decode(
599 nlri_content + offset,
600 len - offset,
601 mval, match_num,
602 &error);
603 break;
604 case FLOWSPEC_PKT_LEN:
605 match_num =
606 &(bpem->match_packet_length_num);
607 mval = (struct bgp_pbr_match_val *)
608 &(bpem->packet_length);
609 offset += bgp_flowspec_call_non_opaque_decode(
610 nlri_content + offset,
611 len - offset,
612 mval, match_num,
613 &error);
614 break;
615 case FLOWSPEC_DSCP:
616 match_num = &(bpem->match_dscp_num);
617 mval = (struct bgp_pbr_match_val *)
618 &(bpem->dscp);
619 offset += bgp_flowspec_call_non_opaque_decode(
620 nlri_content + offset,
621 len - offset,
622 mval, match_num,
623 &error);
624 break;
625 case FLOWSPEC_TCP_FLAGS:
626 ret = bgp_flowspec_tcpflags_decode(
627 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
628 nlri_content + offset,
629 len - offset,
630 &bpem->tcpflags, &error);
631 if (error < 0)
632 zlog_err("%s: flowspec_tcpflags_decode error %d",
633 __func__, error);
634 else
635 bpem->match_tcpflags_num = error;
636 /* contains the number of slots used */
637 offset += ret;
638 break;
639 case FLOWSPEC_FRAGMENT:
640 ret = bgp_flowspec_fragment_type_decode(
641 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
642 nlri_content + offset,
643 len - offset, &bpem->fragment,
644 &error);
645 if (error < 0)
646 zlog_err("%s: flowspec_fragment_type_decode error %d",
647 __func__, error);
648 else
649 bpem->match_bitmask |= FRAGMENT_PRESENT;
650 offset += ret;
651 break;
652 default:
653 zlog_err("%s: unknown type %d\n", __func__, type);
654 }
655 }
656 return error;
657 }
658
659
660 struct bgp_node *bgp_flowspec_get_match_per_ip(afi_t afi,
661 struct bgp_table *rib,
662 struct prefix *match,
663 int prefix_check)
664 {
665 struct bgp_node *rn;
666 struct prefix *prefix;
667
668 for (rn = bgp_table_top(rib); rn; rn = bgp_route_next(rn)) {
669 prefix = &rn->p;
670
671 if (prefix->family != AF_FLOWSPEC)
672 continue;
673
674 if (bgp_flowspec_contains_prefix(prefix, match, prefix_check))
675 return rn;
676 }
677 return NULL;
678 }