Line data Source code
1 : /* AS path management routines.
2 : * Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro
3 : * Copyright (C) 2005 Sun Microsystems, Inc.
4 : *
5 : * This file is part of GNU Zebra.
6 : *
7 : * GNU Zebra is free software; you can redistribute it and/or modify it
8 : * under the terms of the GNU General Public License as published by the
9 : * Free Software Foundation; either version 2, or (at your option) any
10 : * later version.
11 : *
12 : * GNU Zebra is distributed in the hope that it will be useful, but
13 : * WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : * General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU General Public License along
18 : * with this program; see the file COPYING; if not, write to the Free Software
19 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 : */
21 :
22 : #include <zebra.h>
23 :
24 : #include "hash.h"
25 : #include "memory.h"
26 : #include "vector.h"
27 : #include "log.h"
28 : #include "stream.h"
29 : #include "command.h"
30 : #include "jhash.h"
31 : #include "queue.h"
32 : #include "filter.h"
33 :
34 : #include "bgpd/bgpd.h"
35 : #include "bgpd/bgp_aspath.h"
36 : #include "bgpd/bgp_debug.h"
37 : #include "bgpd/bgp_attr.h"
38 : #include "bgpd/bgp_errors.h"
39 :
40 : /* Attr. Flags and Attr. Type Code. */
41 : #define AS_HEADER_SIZE 2
42 :
43 : /* Now FOUR octets are used for AS value. */
44 : #define AS_VALUE_SIZE sizeof(as_t)
45 : /* This is the old one */
46 : #define AS16_VALUE_SIZE sizeof(as16_t)
47 :
48 : /* Maximum protocol segment length value */
49 : #define AS_SEGMENT_MAX 255
50 :
51 : /* The following length and size macros relate specifically to Quagga's
52 : * internal representation of AS-Segments, not per se to the on-wire
53 : * sizes and lengths. At present (200508) they sort of match, however
54 : * the ONLY functions which should now about the on-wire syntax are
55 : * aspath_put, assegment_put and assegment_parse.
56 : *
57 : * aspath_put returns bytes written, the only definitive record of
58 : * size of wire-format attribute..
59 : */
60 :
61 : /* Calculated size in bytes of ASN segment data to hold N ASN's */
62 : #define ASSEGMENT_DATA_SIZE(N, S) \
63 : ((N) * ((S) ? AS_VALUE_SIZE : AS16_VALUE_SIZE))
64 :
65 : /* Calculated size of segment struct to hold N ASN's */
66 : #define ASSEGMENT_SIZE(N,S) (AS_HEADER_SIZE + ASSEGMENT_DATA_SIZE (N,S))
67 :
68 : /* AS segment octet length. */
69 : #define ASSEGMENT_LEN(X,S) ASSEGMENT_SIZE((X)->length,S)
70 :
71 : /* AS_SEQUENCE segments can be packed together */
72 : /* Can the types of X and Y be considered for packing? */
73 : #define ASSEGMENT_TYPES_PACKABLE(X, Y) \
74 : (((X)->type == (Y)->type) && ((X)->type == AS_SEQUENCE))
75 : /* Types and length of X,Y suitable for packing? */
76 : #define ASSEGMENTS_PACKABLE(X, Y) \
77 : (ASSEGMENT_TYPES_PACKABLE((X), (Y)) \
78 : && (((X)->length + (Y)->length) <= AS_SEGMENT_MAX))
79 :
80 : /* As segment header - the on-wire representation
81 : * NOT the internal representation!
82 : */
83 : struct assegment_header {
84 : uint8_t type;
85 : uint8_t length;
86 : };
87 :
88 : /* Hash for aspath. This is the top level structure of AS path. */
89 : static struct hash *ashash;
90 :
91 : /* Stream for SNMP. See aspath_snmp_pathseg */
92 : static struct stream *snmp_stream;
93 :
94 : /* Callers are required to initialize the memory */
95 27 : static as_t *assegment_data_new(int num)
96 : {
97 27 : return (XMALLOC(MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE(num, 1)));
98 : }
99 :
100 27 : static void assegment_data_free(as_t *asdata)
101 : {
102 54 : XFREE(MTYPE_AS_SEG_DATA, asdata);
103 : }
104 :
105 : const char *const aspath_segment_type_str[] = {
106 : "as-invalid", "as-set", "as-sequence", "as-confed-sequence",
107 : "as-confed-set"
108 : };
109 :
110 : /* Get a new segment. Note that 0 is an allowed length,
111 : * and will result in a segment with no allocated data segment.
112 : * the caller should immediately assign data to the segment, as the segment
113 : * otherwise is not generally valid
114 : */
115 23 : static struct assegment *assegment_new(uint8_t type, unsigned short length)
116 : {
117 23 : struct assegment *new;
118 :
119 23 : new = XCALLOC(MTYPE_AS_SEG, sizeof(struct assegment));
120 :
121 23 : if (length)
122 23 : new->as = assegment_data_new(length);
123 :
124 23 : new->length = length;
125 23 : new->type = type;
126 :
127 23 : return new;
128 : }
129 :
130 23 : static void assegment_free(struct assegment *seg)
131 : {
132 23 : if (!seg)
133 : return;
134 :
135 23 : assegment_data_free(seg->as);
136 23 : memset(seg, 0xfe, sizeof(struct assegment));
137 23 : XFREE(MTYPE_AS_SEG, seg);
138 :
139 23 : return;
140 : }
141 :
142 : /* free entire chain of segments */
143 7 : static void assegment_free_all(struct assegment *seg)
144 : {
145 7 : struct assegment *prev;
146 :
147 51 : while (seg) {
148 23 : prev = seg;
149 23 : seg = seg->next;
150 23 : assegment_free(prev);
151 : }
152 : }
153 :
154 : /* Duplicate just the given assegment and its data */
155 12 : static struct assegment *assegment_dup(struct assegment *seg)
156 : {
157 12 : struct assegment *new;
158 :
159 12 : new = assegment_new(seg->type, seg->length);
160 12 : memcpy(new->as, seg->as, ASSEGMENT_DATA_SIZE(new->length, 1));
161 :
162 12 : return new;
163 : }
164 :
165 : /* Duplicate entire chain of assegments, return the head */
166 12 : static struct assegment *assegment_dup_all(struct assegment *seg)
167 : {
168 12 : struct assegment *new = NULL;
169 12 : struct assegment *head = NULL;
170 :
171 24 : while (seg) {
172 12 : if (head) {
173 0 : new->next = assegment_dup(seg);
174 0 : new = new->next;
175 : } else
176 12 : head = new = assegment_dup(seg);
177 :
178 12 : seg = seg->next;
179 : }
180 12 : return head;
181 : }
182 :
183 : /* prepend the as number to given segment, given num of times */
184 4 : static struct assegment *assegment_prepend_asns(struct assegment *seg,
185 : as_t asnum, int num)
186 : {
187 4 : as_t *newas;
188 4 : int i;
189 :
190 4 : if (!num)
191 : return seg;
192 :
193 4 : if (num >= AS_SEGMENT_MAX)
194 : return seg; /* we don't do huge prepends */
195 :
196 4 : newas = assegment_data_new(seg->length + num);
197 4 : if (newas == NULL)
198 : return seg;
199 :
200 8 : for (i = 0; i < num; i++)
201 4 : newas[i] = asnum;
202 :
203 4 : memcpy(newas + num, seg->as, ASSEGMENT_DATA_SIZE(seg->length, 1));
204 4 : assegment_data_free(seg->as);
205 4 : seg->as = newas;
206 4 : seg->length += num;
207 :
208 4 : return seg;
209 : }
210 :
211 : /* append given array of as numbers to the segment */
212 0 : static struct assegment *assegment_append_asns(struct assegment *seg,
213 : as_t *asnos, int num)
214 : {
215 0 : as_t *newas;
216 :
217 0 : if (!seg)
218 : return seg;
219 :
220 0 : newas = XREALLOC(MTYPE_AS_SEG_DATA, seg->as,
221 : ASSEGMENT_DATA_SIZE(seg->length + num, 1));
222 :
223 0 : seg->as = newas;
224 0 : memcpy(seg->as + seg->length, asnos,
225 : ASSEGMENT_DATA_SIZE(num, 1));
226 0 : seg->length += num;
227 0 : return seg;
228 : }
229 :
230 0 : static int int_cmp(const void *p1, const void *p2)
231 : {
232 0 : const as_t *as1 = p1;
233 0 : const as_t *as2 = p2;
234 :
235 0 : return (*as1 == *as2) ? 0 : ((*as1 > *as2) ? 1 : -1);
236 : }
237 :
238 : /* normalise the segment.
239 : * In particular, merge runs of AS_SEQUENCEs into one segment
240 : * Internally, we do not care about the wire segment length limit, and
241 : * we want each distinct AS_PATHs to have the exact same internal
242 : * representation - eg, so that our hashing actually works..
243 : */
244 8 : static struct assegment *assegment_normalise(struct assegment *head)
245 : {
246 8 : struct assegment *seg = head, *pin;
247 8 : struct assegment *tmp;
248 :
249 8 : if (!head)
250 : return head;
251 :
252 16 : while (seg) {
253 8 : pin = seg;
254 :
255 : /* Sort values SET segments, for determinism in paths to aid
256 : * creation of hash values / path comparisons
257 : * and because it helps other lesser implementations ;)
258 : */
259 8 : if (seg->type == AS_SET || seg->type == AS_CONFED_SET) {
260 0 : int tail = 0;
261 0 : int i;
262 :
263 0 : qsort(seg->as, seg->length, sizeof(as_t), int_cmp);
264 :
265 : /* weed out dupes */
266 0 : for (i = 1; i < seg->length; i++) {
267 0 : if (seg->as[tail] == seg->as[i])
268 0 : continue;
269 :
270 0 : tail++;
271 0 : if (tail < i)
272 0 : seg->as[tail] = seg->as[i];
273 : }
274 : /* seg->length can be 0.. */
275 0 : if (seg->length)
276 0 : seg->length = tail + 1;
277 : }
278 :
279 : /* read ahead from the current, pinned segment while the
280 : * segments
281 : * are packable/mergeable. Append all following packable
282 : * segments
283 : * to the segment we have pinned and remove these appended
284 : * segments.
285 : */
286 8 : while (pin->next && ASSEGMENT_TYPES_PACKABLE(pin, pin->next)) {
287 0 : tmp = pin->next;
288 0 : seg = pin->next;
289 :
290 : /* append the next sequence to the pinned sequence */
291 0 : pin = assegment_append_asns(pin, seg->as, seg->length);
292 :
293 : /* bypass the next sequence */
294 0 : pin->next = seg->next;
295 :
296 : /* get rid of the now referenceless segment */
297 0 : assegment_free(tmp);
298 : }
299 :
300 : seg = pin->next;
301 : }
302 : return head;
303 : }
304 :
305 0 : static struct aspath *aspath_new(void)
306 : {
307 0 : return XCALLOC(MTYPE_AS_PATH, sizeof(struct aspath));
308 : }
309 :
310 : /* Free AS path structure. */
311 22 : void aspath_free(struct aspath *aspath)
312 : {
313 22 : if (!aspath)
314 : return;
315 22 : if (aspath->segments)
316 22 : assegment_free_all(aspath->segments);
317 22 : XFREE(MTYPE_AS_STR, aspath->str);
318 :
319 22 : if (aspath->json) {
320 0 : json_object_free(aspath->json);
321 0 : aspath->json = NULL;
322 : }
323 :
324 22 : XFREE(MTYPE_AS_PATH, aspath);
325 : }
326 :
327 : /* Unintern aspath from AS path bucket. */
328 79 : void aspath_unintern(struct aspath **aspath)
329 : {
330 79 : struct aspath *ret;
331 79 : struct aspath *asp;
332 :
333 79 : if (!*aspath)
334 : return;
335 :
336 67 : asp = *aspath;
337 :
338 67 : if (asp->refcnt)
339 67 : asp->refcnt--;
340 :
341 67 : if (asp->refcnt == 0) {
342 : /* This aspath must exist in aspath hash table. */
343 9 : ret = hash_release(ashash, asp);
344 9 : assert(ret != NULL);
345 9 : aspath_free(asp);
346 9 : *aspath = NULL;
347 : }
348 : }
349 :
350 : /* Return the start or end delimiters for a particular Segment type */
351 : #define AS_SEG_START 0
352 : #define AS_SEG_END 1
353 0 : static char aspath_delimiter_char(uint8_t type, uint8_t which)
354 : {
355 0 : int i;
356 0 : struct {
357 : int type;
358 : char start;
359 : char end;
360 0 : } aspath_delim_char[] = {{AS_SET, '{', '}'},
361 : {AS_CONFED_SET, '[', ']'},
362 : {AS_CONFED_SEQUENCE, '(', ')'},
363 : {0}};
364 :
365 0 : for (i = 0; aspath_delim_char[i].type != 0; i++) {
366 0 : if (aspath_delim_char[i].type == type) {
367 0 : if (which == AS_SEG_START)
368 0 : return aspath_delim_char[i].start;
369 0 : else if (which == AS_SEG_END)
370 0 : return aspath_delim_char[i].end;
371 : }
372 : }
373 : return ' ';
374 : }
375 :
376 : /* countup asns from this segment and index onward */
377 : static int assegment_count_asns(struct assegment *seg, int from)
378 : {
379 : int count = 0;
380 8 : while (seg) {
381 23 : if (!from)
382 23 : count += seg->length;
383 : else {
384 : count += (seg->length - from);
385 : from = 0;
386 : }
387 23 : seg = seg->next;
388 : }
389 23 : return count;
390 : }
391 :
392 0 : unsigned int aspath_count_confeds(struct aspath *aspath)
393 : {
394 0 : int count = 0;
395 0 : struct assegment *seg = aspath->segments;
396 :
397 0 : while (seg) {
398 0 : if (seg->type == AS_CONFED_SEQUENCE)
399 0 : count += seg->length;
400 0 : else if (seg->type == AS_CONFED_SET)
401 0 : count++;
402 :
403 0 : seg = seg->next;
404 : }
405 0 : return count;
406 : }
407 :
408 0 : unsigned int aspath_count_hops(const struct aspath *aspath)
409 : {
410 0 : int count = 0;
411 0 : struct assegment *seg = aspath->segments;
412 :
413 0 : while (seg) {
414 0 : if (seg->type == AS_SEQUENCE)
415 0 : count += seg->length;
416 0 : else if (seg->type == AS_SET)
417 0 : count++;
418 :
419 0 : seg = seg->next;
420 : }
421 0 : return count;
422 : }
423 :
424 : /* Check if aspath has AS_SET or AS_CONFED_SET */
425 0 : bool aspath_check_as_sets(struct aspath *aspath)
426 : {
427 0 : struct assegment *seg = aspath->segments;
428 :
429 0 : while (seg) {
430 0 : if (seg->type == AS_SET || seg->type == AS_CONFED_SET)
431 : return true;
432 0 : seg = seg->next;
433 : }
434 : return false;
435 : }
436 :
437 : /* Check if aspath has BGP_AS_ZERO */
438 24 : bool aspath_check_as_zero(struct aspath *aspath)
439 : {
440 24 : struct assegment *seg = aspath->segments;
441 24 : unsigned int i;
442 :
443 44 : while (seg) {
444 51 : for (i = 0; i < seg->length; i++)
445 31 : if (seg->as[i] == BGP_AS_ZERO)
446 : return true;
447 20 : seg = seg->next;
448 : }
449 :
450 : return false;
451 : }
452 :
453 : /* Estimate size aspath /might/ take if encoded into an
454 : * ASPATH attribute.
455 : *
456 : * This is a quick estimate, not definitive! aspath_put()
457 : * may return a different number!!
458 : */
459 0 : unsigned int aspath_size(struct aspath *aspath)
460 : {
461 0 : int size = 0;
462 0 : struct assegment *seg = aspath->segments;
463 :
464 0 : while (seg) {
465 0 : size += ASSEGMENT_SIZE(seg->length, 1);
466 0 : seg = seg->next;
467 : }
468 0 : return size;
469 : }
470 :
471 : /* Return highest public ASN in path */
472 0 : as_t aspath_highest(struct aspath *aspath)
473 : {
474 0 : struct assegment *seg = aspath->segments;
475 0 : as_t highest = 0;
476 0 : unsigned int i;
477 :
478 0 : while (seg) {
479 0 : for (i = 0; i < seg->length; i++)
480 0 : if (seg->as[i] > highest
481 0 : && !BGP_AS_IS_PRIVATE(seg->as[i]))
482 0 : highest = seg->as[i];
483 0 : seg = seg->next;
484 : }
485 0 : return highest;
486 : }
487 :
488 : /* Return the left-most ASN in path */
489 0 : as_t aspath_leftmost(struct aspath *aspath)
490 : {
491 0 : struct assegment *seg = aspath->segments;
492 0 : as_t leftmost = 0;
493 :
494 0 : if (seg && seg->length && seg->type == AS_SEQUENCE)
495 0 : leftmost = seg->as[0];
496 :
497 0 : return leftmost;
498 : }
499 :
500 : /* Return 1 if there are any 4-byte ASes in the path */
501 0 : bool aspath_has_as4(struct aspath *aspath)
502 : {
503 0 : struct assegment *seg = aspath->segments;
504 0 : unsigned int i;
505 :
506 0 : while (seg) {
507 0 : for (i = 0; i < seg->length; i++)
508 0 : if (seg->as[i] > BGP_AS_MAX)
509 : return true;
510 0 : seg = seg->next;
511 : }
512 : return false;
513 : }
514 :
515 : /* Convert aspath structure to string expression. */
516 25 : static void aspath_make_str_count(struct aspath *as, bool make_json)
517 : {
518 25 : struct assegment *seg;
519 25 : int str_size;
520 25 : int len = 0;
521 25 : char *str_buf;
522 25 : json_object *jaspath_segments = NULL;
523 25 : json_object *jseg = NULL;
524 25 : json_object *jseg_list = NULL;
525 :
526 25 : if (make_json) {
527 0 : as->json = json_object_new_object();
528 0 : jaspath_segments = json_object_new_array();
529 : }
530 :
531 : /* Empty aspath. */
532 25 : if (!as->segments) {
533 6 : if (make_json) {
534 0 : json_object_string_add(as->json, "string", "Local");
535 0 : json_object_object_add(as->json, "segments",
536 : jaspath_segments);
537 0 : json_object_int_add(as->json, "length", 0);
538 : }
539 6 : as->str = XMALLOC(MTYPE_AS_STR, 1);
540 6 : as->str[0] = '\0';
541 6 : as->str_len = 0;
542 6 : return;
543 : }
544 :
545 38 : seg = as->segments;
546 :
547 : /* ASN takes 5 to 10 chars plus separator, see below.
548 : * If there is one differing segment type, we need an additional
549 : * 2 chars for segment delimiters, and the final '\0'.
550 : * Hopefully this is large enough to avoid hitting the realloc
551 : * code below for most common sequences.
552 : *
553 : * This was changed to 10 after the well-known BGP assertion, which
554 : * had hit some parts of the Internet in May of 2009.
555 : */
556 : #define ASN_STR_LEN (10 + 1)
557 23 : str_size = MAX(assegment_count_asns(seg, 0) * ASN_STR_LEN + 2 + 1,
558 : ASPATH_STR_DEFAULT_LEN);
559 19 : str_buf = XMALLOC(MTYPE_AS_STR, str_size);
560 :
561 38 : while (seg) {
562 19 : int i;
563 19 : char separator;
564 :
565 : /* Check AS type validity. Set separator for segment */
566 19 : switch (seg->type) {
567 : case AS_SET:
568 : case AS_CONFED_SET:
569 : separator = ',';
570 : break;
571 19 : case AS_SEQUENCE:
572 : case AS_CONFED_SEQUENCE:
573 19 : separator = ' ';
574 19 : break;
575 0 : default:
576 0 : XFREE(MTYPE_AS_STR, str_buf);
577 0 : as->str = NULL;
578 0 : as->str_len = 0;
579 0 : json_object_free(as->json);
580 0 : as->json = NULL;
581 :
582 0 : return;
583 : }
584 :
585 : /* We might need to increase str_buf, particularly if path has
586 : * differing segments types, our initial guesstimate above will
587 : * have been wrong. Need 10 chars for ASN, a separator each and
588 : * potentially two segment delimiters, plus a space between each
589 : * segment and trailing zero.
590 : *
591 : * This definitely didn't work with the value of 5 bytes and
592 : * 32-bit ASNs.
593 : */
594 : #define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
595 19 : if ((len + SEGMENT_STR_LEN(seg)) > str_size) {
596 4 : str_size = len + SEGMENT_STR_LEN(seg);
597 4 : str_buf = XREALLOC(MTYPE_AS_STR, str_buf, str_size);
598 : }
599 : #undef ASN_STR_LEN
600 : #undef SEGMENT_STR_LEN
601 :
602 19 : if (seg->type != AS_SEQUENCE)
603 0 : len += snprintf(
604 0 : str_buf + len, str_size - len, "%c",
605 0 : aspath_delimiter_char(seg->type, AS_SEG_START));
606 :
607 19 : if (make_json)
608 0 : jseg_list = json_object_new_array();
609 :
610 : /* write out the ASNs, with their separators, bar the last one*/
611 55 : for (i = 0; i < seg->length; i++) {
612 36 : if (make_json)
613 0 : json_object_array_add(
614 : jseg_list,
615 0 : json_object_new_int64(seg->as[i]));
616 :
617 36 : len += snprintf(str_buf + len, str_size - len, "%u",
618 36 : seg->as[i]);
619 :
620 36 : if (i < (seg->length - 1))
621 17 : len += snprintf(str_buf + len, str_size - len,
622 : "%c", separator);
623 : }
624 :
625 19 : if (make_json) {
626 0 : jseg = json_object_new_object();
627 0 : json_object_string_add(
628 : jseg, "type",
629 0 : aspath_segment_type_str[seg->type]);
630 0 : json_object_object_add(jseg, "list", jseg_list);
631 0 : json_object_array_add(jaspath_segments, jseg);
632 : }
633 :
634 19 : if (seg->type != AS_SEQUENCE)
635 0 : len += snprintf(
636 0 : str_buf + len, str_size - len, "%c",
637 0 : aspath_delimiter_char(seg->type, AS_SEG_END));
638 19 : if (seg->next)
639 0 : len += snprintf(str_buf + len, str_size - len, " ");
640 :
641 19 : seg = seg->next;
642 : }
643 :
644 19 : assert(len < str_size);
645 :
646 19 : str_buf[len] = '\0';
647 19 : as->str = str_buf;
648 19 : as->str_len = len;
649 :
650 19 : if (make_json) {
651 0 : json_object_string_add(as->json, "string", str_buf);
652 0 : json_object_object_add(as->json, "segments", jaspath_segments);
653 0 : json_object_int_add(as->json, "length", aspath_count_hops(as));
654 : }
655 :
656 : return;
657 : }
658 :
659 25 : void aspath_str_update(struct aspath *as, bool make_json)
660 : {
661 25 : XFREE(MTYPE_AS_STR, as->str);
662 :
663 25 : if (as->json) {
664 0 : json_object_free(as->json);
665 0 : as->json = NULL;
666 : }
667 :
668 25 : aspath_make_str_count(as, make_json);
669 25 : }
670 :
671 : /* Intern allocated AS path. */
672 4 : struct aspath *aspath_intern(struct aspath *aspath)
673 : {
674 4 : struct aspath *find;
675 :
676 : /* Assert this AS path structure is not interned and has the string
677 : representation built. */
678 4 : assert(aspath->refcnt == 0);
679 4 : assert(aspath->str);
680 :
681 : /* Check AS path hash. */
682 4 : find = hash_get(ashash, aspath, hash_alloc_intern);
683 4 : if (find != aspath)
684 2 : aspath_free(aspath);
685 :
686 4 : find->refcnt++;
687 :
688 4 : return find;
689 : }
690 :
691 : /* Duplicate aspath structure. Created same aspath structure but
692 : reference count and AS path string is cleared. */
693 15 : struct aspath *aspath_dup(struct aspath *aspath)
694 : {
695 15 : unsigned short buflen = aspath->str_len + 1;
696 15 : struct aspath *new;
697 :
698 15 : new = XCALLOC(MTYPE_AS_PATH, sizeof(struct aspath));
699 15 : new->json = NULL;
700 :
701 15 : if (aspath->segments)
702 12 : new->segments = assegment_dup_all(aspath->segments);
703 :
704 15 : if (!aspath->str)
705 : return new;
706 :
707 15 : new->str = XMALLOC(MTYPE_AS_STR, buflen);
708 15 : new->str_len = aspath->str_len;
709 :
710 : /* copy the string data */
711 15 : if (aspath->str_len > 0)
712 12 : memcpy(new->str, aspath->str, buflen);
713 : else
714 3 : new->str[0] = '\0';
715 :
716 : return new;
717 : }
718 :
719 7 : static void *aspath_hash_alloc(void *arg)
720 : {
721 7 : const struct aspath *aspath = arg;
722 7 : struct aspath *new;
723 :
724 : /* Malformed AS path value. */
725 7 : assert(aspath->str);
726 :
727 : /* New aspath structure is needed. */
728 7 : new = XMALLOC(MTYPE_AS_PATH, sizeof(struct aspath));
729 :
730 : /* Reuse segments and string representation */
731 7 : new->refcnt = 0;
732 7 : new->segments = aspath->segments;
733 7 : new->str = aspath->str;
734 7 : new->str_len = aspath->str_len;
735 7 : new->json = aspath->json;
736 :
737 7 : return new;
738 : }
739 :
740 : /* parse as-segment byte stream in struct assegment */
741 14 : static int assegments_parse(struct stream *s, size_t length,
742 : struct assegment **result, int use32bit)
743 : {
744 14 : struct assegment_header segh;
745 14 : struct assegment *seg, *prev = NULL, *head = NULL;
746 14 : size_t bytes = 0;
747 :
748 : /* empty aspath (ie iBGP or somesuch) */
749 14 : if (length == 0)
750 : return 0;
751 :
752 8 : if (BGP_DEBUG(as4, AS4_SEGMENT))
753 0 : zlog_debug(
754 : "[AS4SEG] Parse aspath segment: got total byte length %lu",
755 : (unsigned long)length);
756 : /* basic checks */
757 8 : if ((STREAM_READABLE(s) < length)
758 8 : || (STREAM_READABLE(s) < AS_HEADER_SIZE)
759 8 : || (length % AS16_VALUE_SIZE))
760 : return -1;
761 :
762 16 : while (bytes < length) {
763 8 : int i;
764 8 : size_t seg_size;
765 :
766 8 : if ((length - bytes) <= AS_HEADER_SIZE) {
767 0 : if (head)
768 0 : assegment_free_all(head);
769 0 : return -1;
770 : }
771 :
772 : /* softly softly, get the header first on its own */
773 8 : segh.type = stream_getc(s);
774 8 : segh.length = stream_getc(s);
775 :
776 8 : seg_size = ASSEGMENT_SIZE(segh.length, use32bit);
777 :
778 8 : if (BGP_DEBUG(as4, AS4_SEGMENT))
779 0 : zlog_debug(
780 : "[AS4SEG] Parse aspath segment: got type %d, length %d",
781 : segh.type, segh.length);
782 :
783 : /* check it.. */
784 8 : if (((bytes + seg_size) > length)
785 : /* 1771bis 4.3b: seg length contains one or more */
786 : || (segh.length == 0)
787 : /* Paranoia in case someone changes type of segment length.
788 : * Shift both values by 0x10 to make the comparison operate
789 : * on more, than 8 bits (otherwise it's a warning, bug
790 : * #564).
791 : */
792 8 : || ((sizeof(segh.length) > 1)
793 : && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX))) {
794 0 : if (head)
795 0 : assegment_free_all(head);
796 0 : return -1;
797 : }
798 :
799 8 : switch (segh.type) {
800 : case AS_SEQUENCE:
801 : case AS_SET:
802 : case AS_CONFED_SEQUENCE:
803 : case AS_CONFED_SET:
804 8 : break;
805 0 : default:
806 0 : if (head)
807 14 : assegment_free_all(head);
808 : return -1;
809 : }
810 :
811 : /* now its safe to trust lengths */
812 8 : seg = assegment_new(segh.type, segh.length);
813 :
814 8 : if (head)
815 0 : prev->next = seg;
816 : else /* it's the first segment */
817 : head = seg;
818 :
819 23 : for (i = 0; i < segh.length; i++)
820 15 : seg->as[i] =
821 15 : (use32bit) ? stream_getl(s) : stream_getw(s);
822 :
823 8 : bytes += seg_size;
824 :
825 8 : if (BGP_DEBUG(as4, AS4_SEGMENT))
826 0 : zlog_debug(
827 : "[AS4SEG] Parse aspath segment: Bytes now: %lu",
828 : (unsigned long)bytes);
829 :
830 : prev = seg;
831 : }
832 :
833 8 : *result = assegment_normalise(head);
834 8 : return 0;
835 : }
836 :
837 : /* AS path parse function. pnt is a pointer to byte stream and length
838 : is length of byte stream. If there is same AS path in the the AS
839 : path hash then return it else make new AS path structure.
840 :
841 : On error NULL is returned.
842 : */
843 14 : struct aspath *aspath_parse(struct stream *s, size_t length, int use32bit)
844 : {
845 14 : struct aspath as;
846 14 : struct aspath *find;
847 :
848 : /* If length is odd it's malformed AS path. */
849 : /* Nit-picking: if (use32bit == 0) it is malformed if odd,
850 : * otherwise its malformed when length is larger than 2 and (length-2)
851 : * is not dividable by 4.
852 : * But... this time we're lazy
853 : */
854 14 : if (length % AS16_VALUE_SIZE)
855 : return NULL;
856 :
857 14 : memset(&as, 0, sizeof(as));
858 14 : if (assegments_parse(s, length, &as.segments, use32bit) < 0)
859 : return NULL;
860 :
861 : /* If already same aspath exist then return it. */
862 14 : find = hash_get(ashash, &as, aspath_hash_alloc);
863 :
864 : /* if the aspath was already hashed free temporary memory. */
865 14 : if (find->refcnt) {
866 7 : assegment_free_all(as.segments);
867 : /* aspath_key_make() always updates the string */
868 7 : XFREE(MTYPE_AS_STR, as.str);
869 7 : if (as.json) {
870 0 : json_object_free(as.json);
871 0 : as.json = NULL;
872 : }
873 : }
874 :
875 14 : find->refcnt++;
876 :
877 14 : return find;
878 : }
879 :
880 7 : static void assegment_data_put(struct stream *s, as_t *as, int num,
881 : int use32bit)
882 : {
883 7 : int i;
884 7 : assert(num <= AS_SEGMENT_MAX);
885 :
886 20 : for (i = 0; i < num; i++)
887 13 : if (use32bit)
888 13 : stream_putl(s, as[i]);
889 : else {
890 0 : if (as[i] <= BGP_AS_MAX)
891 0 : stream_putw(s, as[i]);
892 : else
893 0 : stream_putw(s, BGP_AS_TRANS);
894 : }
895 7 : }
896 :
897 7 : static size_t assegment_header_put(struct stream *s, uint8_t type, int length)
898 : {
899 7 : size_t lenp;
900 7 : assert(length <= AS_SEGMENT_MAX);
901 7 : stream_putc(s, type);
902 7 : lenp = stream_get_endp(s);
903 7 : stream_putc(s, length);
904 7 : return lenp;
905 : }
906 :
907 : /* write aspath data to stream */
908 7 : size_t aspath_put(struct stream *s, struct aspath *as, int use32bit)
909 : {
910 7 : struct assegment *seg = as->segments;
911 7 : size_t bytes = 0;
912 :
913 7 : if (!seg || seg->length == 0)
914 : return 0;
915 :
916 : /*
917 : * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
918 : * At the moment, we would write out a partial aspath, and our
919 : * peer
920 : * will complain and drop the session :-/
921 : *
922 : * The general assumption here is that many things tested will
923 : * never happen. And, in real live, up to now, they have not.
924 : */
925 14 : while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s))) {
926 7 : struct assegment *next = seg->next;
927 7 : int written = 0;
928 7 : int asns_packed = 0;
929 7 : size_t lenp;
930 :
931 : /* Overlength segments have to be split up */
932 7 : while ((seg->length - written) > AS_SEGMENT_MAX) {
933 0 : assegment_header_put(s, seg->type, AS_SEGMENT_MAX);
934 0 : assegment_data_put(s, (seg->as + written),
935 : AS_SEGMENT_MAX, use32bit);
936 0 : written += AS_SEGMENT_MAX;
937 0 : bytes += ASSEGMENT_SIZE(AS_SEGMENT_MAX, use32bit);
938 : }
939 :
940 : /* write the final segment, probably is also the first
941 : */
942 7 : lenp = assegment_header_put(s, seg->type,
943 : seg->length - written);
944 7 : assegment_data_put(s, (seg->as + written),
945 7 : seg->length - written, use32bit);
946 :
947 : /* Sequence-type segments can be 'packed' together
948 : * Case of a segment which was overlength and split up
949 : * will be missed here, but that doesn't matter.
950 : */
951 7 : while (next && ASSEGMENTS_PACKABLE(seg, next)) {
952 : /* NB: We should never normally get here given
953 : * we
954 : * normalise aspath data when parse them.
955 : * However, better
956 : * safe than sorry. We potentially could call
957 : * assegment_normalise here instead, but it's
958 : * cheaper and
959 : * easier to do it on the fly here rather than
960 : * go through
961 : * the segment list twice every time we write
962 : * out
963 : * aspath's.
964 : */
965 :
966 : /* Next segment's data can fit in this one */
967 0 : assegment_data_put(s, next->as, next->length, use32bit);
968 :
969 : /* update the length of the segment header */
970 0 : stream_putc_at(s, lenp,
971 0 : seg->length - written + next->length);
972 0 : asns_packed += next->length;
973 :
974 0 : next = next->next;
975 : }
976 :
977 7 : bytes += ASSEGMENT_SIZE(seg->length - written + asns_packed,
978 : use32bit);
979 7 : seg = next;
980 : }
981 : return bytes;
982 : }
983 :
984 : /* This is for SNMP BGP4PATHATTRASPATHSEGMENT
985 : * We have no way to manage the storage, so we use a static stream
986 : * wrapper around aspath_put.
987 : */
988 0 : uint8_t *aspath_snmp_pathseg(struct aspath *as, size_t *varlen)
989 : {
990 : #define SNMP_PATHSEG_MAX 1024
991 :
992 0 : if (!snmp_stream)
993 0 : snmp_stream = stream_new(SNMP_PATHSEG_MAX);
994 : else
995 0 : stream_reset(snmp_stream);
996 :
997 0 : if (!as) {
998 0 : *varlen = 0;
999 0 : return NULL;
1000 : }
1001 0 : aspath_put(snmp_stream, as, 0); /* use 16 bit for now here */
1002 :
1003 0 : *varlen = stream_get_endp(snmp_stream);
1004 0 : return stream_pnt(snmp_stream);
1005 : }
1006 :
1007 0 : static struct assegment *aspath_aggregate_as_set_add(struct aspath *aspath,
1008 : struct assegment *asset,
1009 : as_t as)
1010 : {
1011 0 : int i;
1012 :
1013 : /* If this is first AS set member, create new as-set segment. */
1014 0 : if (asset == NULL) {
1015 0 : asset = assegment_new(AS_SET, 1);
1016 0 : if (!aspath->segments)
1017 0 : aspath->segments = asset;
1018 : else {
1019 : struct assegment *seg = aspath->segments;
1020 0 : while (seg->next)
1021 : seg = seg->next;
1022 0 : seg->next = asset;
1023 : }
1024 0 : asset->type = AS_SET;
1025 0 : asset->length = 1;
1026 0 : asset->as[0] = as;
1027 : } else {
1028 : /* Check this AS value already exists or not. */
1029 0 : for (i = 0; i < asset->length; i++)
1030 0 : if (asset->as[i] == as)
1031 : return asset;
1032 :
1033 0 : asset->length++;
1034 0 : asset->as = XREALLOC(MTYPE_AS_SEG_DATA, asset->as,
1035 : asset->length * AS_VALUE_SIZE);
1036 0 : asset->as[asset->length - 1] = as;
1037 : }
1038 :
1039 :
1040 : return asset;
1041 : }
1042 :
1043 : /* Modify as1 using as2 for aggregation. */
1044 0 : struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2)
1045 : {
1046 0 : int i;
1047 0 : int minlen = 0;
1048 0 : int match = 0;
1049 0 : int from;
1050 0 : struct assegment *seg1 = as1->segments;
1051 0 : struct assegment *seg2 = as2->segments;
1052 0 : struct aspath *aspath = NULL;
1053 0 : struct assegment *asset = NULL;
1054 0 : struct assegment *prevseg = NULL;
1055 :
1056 : /* First of all check common leading sequence. */
1057 0 : while (seg1 && seg2) {
1058 : /* Check segment type. */
1059 0 : if (seg1->type != seg2->type)
1060 : break;
1061 :
1062 : /* Minimum segment length. */
1063 0 : minlen = MIN(seg1->length, seg2->length);
1064 :
1065 0 : for (match = 0; match < minlen; match++)
1066 0 : if (seg1->as[match] != seg2->as[match])
1067 : break;
1068 :
1069 0 : if (match) {
1070 0 : struct assegment *seg = assegment_new(seg1->type, 0);
1071 :
1072 0 : seg = assegment_append_asns(seg, seg1->as, match);
1073 :
1074 0 : if (!aspath) {
1075 0 : aspath = aspath_new();
1076 0 : aspath->segments = seg;
1077 : } else
1078 0 : prevseg->next = seg;
1079 :
1080 : prevseg = seg;
1081 : }
1082 :
1083 0 : if (match != minlen || match != seg1->length
1084 0 : || seg1->length != seg2->length)
1085 : break;
1086 : /* We are moving on to the next segment to reset match */
1087 : else
1088 0 : match = 0;
1089 :
1090 0 : seg1 = seg1->next;
1091 0 : seg2 = seg2->next;
1092 : }
1093 :
1094 0 : if (!aspath)
1095 0 : aspath = aspath_new();
1096 :
1097 : /* Make as-set using rest of all information. */
1098 0 : from = match;
1099 0 : while (seg1) {
1100 0 : for (i = from; i < seg1->length; i++)
1101 0 : asset = aspath_aggregate_as_set_add(aspath, asset,
1102 0 : seg1->as[i]);
1103 :
1104 0 : from = 0;
1105 0 : seg1 = seg1->next;
1106 : }
1107 :
1108 : from = match;
1109 0 : while (seg2) {
1110 0 : for (i = from; i < seg2->length; i++)
1111 0 : asset = aspath_aggregate_as_set_add(aspath, asset,
1112 0 : seg2->as[i]);
1113 :
1114 0 : from = 0;
1115 0 : seg2 = seg2->next;
1116 : }
1117 :
1118 0 : assegment_normalise(aspath->segments);
1119 0 : aspath_str_update(aspath, false);
1120 0 : return aspath;
1121 : }
1122 :
1123 : /* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1124 : attribute, check the leftmost AS number in the AS_PATH attribute is
1125 : or not the peer's AS number. */
1126 0 : bool aspath_firstas_check(struct aspath *aspath, as_t asno)
1127 : {
1128 0 : if ((aspath == NULL) || (aspath->segments == NULL))
1129 : return false;
1130 :
1131 0 : if (aspath->segments && (aspath->segments->type == AS_SEQUENCE)
1132 0 : && (aspath->segments->as[0] == asno))
1133 0 : return true;
1134 :
1135 : return false;
1136 : }
1137 :
1138 0 : unsigned int aspath_get_first_as(struct aspath *aspath)
1139 : {
1140 0 : if (aspath == NULL || aspath->segments == NULL)
1141 : return 0;
1142 :
1143 0 : return aspath->segments->as[0];
1144 : }
1145 :
1146 0 : unsigned int aspath_get_last_as(struct aspath *aspath)
1147 : {
1148 0 : int i;
1149 0 : unsigned int last_as = 0;
1150 0 : const struct assegment *seg;
1151 :
1152 0 : if (aspath == NULL || aspath->segments == NULL)
1153 : return last_as;
1154 :
1155 : seg = aspath->segments;
1156 :
1157 0 : while (seg) {
1158 0 : if (seg->type == AS_SEQUENCE || seg->type == AS_CONFED_SEQUENCE)
1159 0 : for (i = 0; i < seg->length; i++)
1160 0 : last_as = seg->as[i];
1161 0 : seg = seg->next;
1162 : }
1163 :
1164 : return last_as;
1165 : }
1166 :
1167 : /* AS path loop check. If aspath contains asno then return >= 1. */
1168 20 : int aspath_loop_check(struct aspath *aspath, as_t asno)
1169 : {
1170 20 : struct assegment *seg;
1171 20 : int count = 0;
1172 :
1173 20 : if ((aspath == NULL) || (aspath->segments == NULL))
1174 : return 0;
1175 :
1176 : seg = aspath->segments;
1177 :
1178 40 : while (seg) {
1179 : int i;
1180 :
1181 60 : for (i = 0; i < seg->length; i++)
1182 40 : if (seg->as[i] == asno)
1183 5 : count++;
1184 :
1185 20 : seg = seg->next;
1186 : }
1187 : return count;
1188 : }
1189 :
1190 : /* AS path loop check. If aspath contains asno
1191 : * that is a confed id then return >= 1.
1192 : */
1193 0 : int aspath_loop_check_confed(struct aspath *aspath, as_t asno)
1194 : {
1195 0 : struct assegment *seg;
1196 0 : int count = 0;
1197 :
1198 0 : if (aspath == NULL || aspath->segments == NULL)
1199 : return 0;
1200 :
1201 : seg = aspath->segments;
1202 :
1203 0 : while (seg) {
1204 : unsigned int i;
1205 :
1206 0 : for (i = 0; i < seg->length; i++)
1207 0 : if (seg->type != AS_CONFED_SEQUENCE &&
1208 0 : seg->type != AS_CONFED_SET && seg->as[i] == asno)
1209 0 : count++;
1210 :
1211 0 : seg = seg->next;
1212 : }
1213 : return count;
1214 : }
1215 :
1216 :
1217 : /* When all of AS path is private AS return 1. */
1218 0 : bool aspath_private_as_check(struct aspath *aspath)
1219 : {
1220 0 : struct assegment *seg;
1221 :
1222 0 : if (!(aspath && aspath->segments))
1223 : return false;
1224 :
1225 : seg = aspath->segments;
1226 :
1227 0 : while (seg) {
1228 : int i;
1229 :
1230 0 : for (i = 0; i < seg->length; i++) {
1231 0 : if (!BGP_AS_IS_PRIVATE(seg->as[i]))
1232 : return false;
1233 : }
1234 0 : seg = seg->next;
1235 : }
1236 : return true;
1237 : }
1238 :
1239 : /* Replace all instances of the target ASN with our own ASN */
1240 1 : struct aspath *aspath_replace_specific_asn(struct aspath *aspath,
1241 : as_t target_asn, as_t our_asn)
1242 : {
1243 1 : struct aspath *new;
1244 1 : struct assegment *seg;
1245 :
1246 1 : new = aspath_dup(aspath);
1247 1 : seg = new->segments;
1248 :
1249 2 : while (seg) {
1250 : int i;
1251 :
1252 3 : for (i = 0; i < seg->length; i++) {
1253 2 : if (seg->as[i] == target_asn)
1254 1 : seg->as[i] = our_asn;
1255 : }
1256 1 : seg = seg->next;
1257 : }
1258 :
1259 1 : aspath_str_update(new, false);
1260 1 : return new;
1261 : }
1262 :
1263 : /* Replace all ASNs with our own ASN */
1264 3 : struct aspath *aspath_replace_all_asn(struct aspath *aspath, as_t our_asn)
1265 : {
1266 3 : struct aspath *new;
1267 3 : struct assegment *seg;
1268 :
1269 3 : new = aspath_dup(aspath);
1270 3 : seg = new->segments;
1271 :
1272 6 : while (seg) {
1273 : int i;
1274 :
1275 9 : for (i = 0; i < seg->length; i++)
1276 6 : seg->as[i] = our_asn;
1277 :
1278 3 : seg = seg->next;
1279 : }
1280 :
1281 3 : aspath_str_update(new, false);
1282 3 : return new;
1283 : }
1284 :
1285 : /* Replace all private ASNs with our own ASN */
1286 0 : struct aspath *aspath_replace_private_asns(struct aspath *aspath, as_t asn,
1287 : as_t peer_asn)
1288 : {
1289 0 : struct aspath *new;
1290 0 : struct assegment *seg;
1291 :
1292 0 : new = aspath_dup(aspath);
1293 0 : seg = new->segments;
1294 :
1295 0 : while (seg) {
1296 : int i;
1297 :
1298 0 : for (i = 0; i < seg->length; i++) {
1299 : /* Don't replace if public ASN or peer's ASN */
1300 0 : if (BGP_AS_IS_PRIVATE(seg->as[i])
1301 0 : && (seg->as[i] != peer_asn))
1302 0 : seg->as[i] = asn;
1303 : }
1304 0 : seg = seg->next;
1305 : }
1306 :
1307 0 : aspath_str_update(new, false);
1308 0 : return new;
1309 : }
1310 :
1311 : /* Remove all private ASNs */
1312 0 : struct aspath *aspath_remove_private_asns(struct aspath *aspath, as_t peer_asn)
1313 : {
1314 0 : struct aspath *new;
1315 0 : struct assegment *seg;
1316 0 : struct assegment *new_seg;
1317 0 : struct assegment *last_new_seg;
1318 0 : int i;
1319 0 : int j;
1320 0 : int public = 0;
1321 0 : int peer = 0;
1322 :
1323 0 : new = XCALLOC(MTYPE_AS_PATH, sizeof(struct aspath));
1324 :
1325 0 : new->json = NULL;
1326 0 : new_seg = NULL;
1327 0 : last_new_seg = NULL;
1328 0 : seg = aspath->segments;
1329 0 : while (seg) {
1330 : public = 0;
1331 : peer = 0;
1332 0 : for (i = 0; i < seg->length; i++) {
1333 : // ASN is public
1334 0 : if (!BGP_AS_IS_PRIVATE(seg->as[i]))
1335 0 : public++;
1336 : /* ASN matches peer's.
1337 : * Don't double-count if peer_asn is public.
1338 : */
1339 0 : else if (seg->as[i] == peer_asn)
1340 0 : peer++;
1341 : }
1342 :
1343 : // The entire segment is public so copy it
1344 0 : if (public == seg->length)
1345 0 : new_seg = assegment_dup(seg);
1346 :
1347 : // The segment is a mix of public and private ASNs. Copy as many
1348 : // spots as
1349 : // there are public ASNs then come back and fill in only the
1350 : // public ASNs.
1351 : else {
1352 : /* length needs to account for all retained ASNs
1353 : * (public or peer_asn), not just public
1354 : */
1355 0 : new_seg = assegment_new(seg->type, (public + peer));
1356 0 : j = 0;
1357 0 : for (i = 0; i < seg->length; i++) {
1358 : // keep ASN if public or matches peer's ASN
1359 0 : if (!BGP_AS_IS_PRIVATE(seg->as[i])
1360 0 : || (seg->as[i] == peer_asn)) {
1361 0 : new_seg->as[j] = seg->as[i];
1362 0 : j++;
1363 : }
1364 : }
1365 : }
1366 :
1367 : // This is the first segment so set the aspath segments pointer
1368 : // to this one
1369 0 : if (!last_new_seg)
1370 0 : new->segments = new_seg;
1371 : else
1372 0 : last_new_seg->next = new_seg;
1373 :
1374 0 : last_new_seg = new_seg;
1375 0 : seg = seg->next;
1376 : }
1377 :
1378 0 : aspath_str_update(new, false);
1379 0 : return new;
1380 : }
1381 :
1382 : /* AS path confed check. If aspath contains confed set or sequence then return
1383 : * 1. */
1384 8 : bool aspath_confed_check(struct aspath *aspath)
1385 : {
1386 8 : struct assegment *seg;
1387 :
1388 8 : if (!(aspath && aspath->segments))
1389 : return false;
1390 :
1391 : seg = aspath->segments;
1392 :
1393 16 : while (seg) {
1394 8 : if (seg->type == AS_CONFED_SET
1395 8 : || seg->type == AS_CONFED_SEQUENCE)
1396 : return true;
1397 8 : seg = seg->next;
1398 : }
1399 : return false;
1400 : }
1401 :
1402 : /* Leftmost AS path segment confed check. If leftmost AS segment is of type
1403 : AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */
1404 0 : bool aspath_left_confed_check(struct aspath *aspath)
1405 : {
1406 :
1407 0 : if (!(aspath && aspath->segments))
1408 : return false;
1409 :
1410 0 : if ((aspath->segments->type == AS_CONFED_SEQUENCE)
1411 0 : || (aspath->segments->type == AS_CONFED_SET))
1412 0 : return true;
1413 :
1414 : return false;
1415 : }
1416 :
1417 : /* Merge as1 to as2. as2 should be uninterned aspath. */
1418 0 : static struct aspath *aspath_merge(struct aspath *as1, struct aspath *as2)
1419 : {
1420 0 : struct assegment *last, *new;
1421 :
1422 0 : if (!as1 || !as2)
1423 : return NULL;
1424 :
1425 0 : last = new = assegment_dup_all(as1->segments);
1426 :
1427 : /* find the last valid segment */
1428 0 : while (last && last->next)
1429 : last = last->next;
1430 :
1431 0 : if (last)
1432 0 : last->next = as2->segments;
1433 0 : as2->segments = new;
1434 0 : aspath_str_update(as2, false);
1435 0 : return as2;
1436 : }
1437 :
1438 : /* Prepend as1 to as2. as2 should be uninterned aspath. */
1439 0 : struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2)
1440 : {
1441 0 : struct assegment *as1segtail;
1442 0 : struct assegment *as2segtail;
1443 0 : struct assegment *as2seghead;
1444 :
1445 0 : if (!as1 || !as2)
1446 : return NULL;
1447 :
1448 : /* If as2 is empty, only need to dupe as1's chain onto as2 */
1449 0 : if (as2->segments == NULL) {
1450 0 : as2->segments = assegment_dup_all(as1->segments);
1451 0 : aspath_str_update(as2, false);
1452 0 : return as2;
1453 : }
1454 :
1455 : /* If as1 is empty AS, no prepending to do. */
1456 0 : if (as1->segments == NULL)
1457 : return as2;
1458 :
1459 : /* find the tail as1's segment chain. */
1460 : as1segtail = as1->segments;
1461 0 : while (as1segtail && as1segtail->next)
1462 : as1segtail = as1segtail->next;
1463 :
1464 : /* Delete any AS_CONFED_SEQUENCE segment from as2. */
1465 0 : if (as1segtail->type == AS_SEQUENCE
1466 0 : && as2->segments->type == AS_CONFED_SEQUENCE)
1467 0 : as2 = aspath_delete_confed_seq(as2);
1468 :
1469 0 : if (!as2->segments) {
1470 0 : as2->segments = assegment_dup_all(as1->segments);
1471 0 : aspath_str_update(as2, false);
1472 0 : return as2;
1473 : }
1474 :
1475 : /* Compare last segment type of as1 and first segment type of as2. */
1476 0 : if (as1segtail->type != as2->segments->type)
1477 0 : return aspath_merge(as1, as2);
1478 :
1479 0 : if (as1segtail->type == AS_SEQUENCE) {
1480 : /* We have two chains of segments, as1->segments and seg2,
1481 : * and we have to attach them together, merging the attaching
1482 : * segments together into one.
1483 : *
1484 : * 1. dupe as1->segments onto head of as2
1485 : * 2. merge seg2's asns onto last segment of this new chain
1486 : * 3. attach chain after seg2
1487 : */
1488 :
1489 : /* save as2 head */
1490 0 : as2seghead = as2->segments;
1491 :
1492 : /* dupe as1 onto as2's head */
1493 0 : as2segtail = as2->segments = assegment_dup_all(as1->segments);
1494 :
1495 : /* refind the tail of as2 */
1496 0 : while (as2segtail && as2segtail->next)
1497 : as2segtail = as2segtail->next;
1498 :
1499 : /* merge the old head, seg2, into tail, seg1 */
1500 0 : assegment_append_asns(as2segtail, as2seghead->as,
1501 0 : as2seghead->length);
1502 :
1503 : /*
1504 : * bypass the merged seg2, and attach any chain after it
1505 : * to chain descending from as2's head
1506 : */
1507 0 : if (as2segtail)
1508 0 : as2segtail->next = as2seghead->next;
1509 :
1510 : /* as2->segments is now referenceless and useless */
1511 0 : assegment_free(as2seghead);
1512 :
1513 : /* we've now prepended as1's segment chain to as2, merging
1514 : * the inbetween AS_SEQUENCE of seg2 in the process
1515 : */
1516 0 : aspath_str_update(as2, false);
1517 0 : return as2;
1518 : } else {
1519 : /* AS_SET merge code is needed at here. */
1520 0 : return aspath_merge(as1, as2);
1521 : }
1522 : /* XXX: Ermmm, what if as1 has multiple segments?? */
1523 :
1524 : /* Not reached */
1525 : }
1526 :
1527 : /* Iterate over AS_PATH segments and wipe all occurrences of the
1528 : * listed AS numbers. Hence some segments may lose some or even
1529 : * all data on the way, the operation is implemented as a smarter
1530 : * version of aspath_dup(), which allocates memory to hold the new
1531 : * data, not the original. The new AS path is returned.
1532 : */
1533 0 : struct aspath *aspath_filter_exclude(struct aspath *source,
1534 : struct aspath *exclude_list)
1535 : {
1536 0 : struct assegment *srcseg, *exclseg, *lastseg;
1537 0 : struct aspath *newpath;
1538 :
1539 0 : newpath = aspath_new();
1540 0 : lastseg = NULL;
1541 :
1542 0 : for (srcseg = source->segments; srcseg; srcseg = srcseg->next) {
1543 0 : unsigned i, y, newlen = 0, done = 0, skip_as;
1544 : struct assegment *newseg;
1545 :
1546 : /* Find out, how much ASns are we going to pick from this
1547 : * segment.
1548 : * We can't perform filtering right inline, because the size of
1549 : * the new segment isn't known at the moment yet.
1550 : */
1551 0 : for (i = 0; i < srcseg->length; i++) {
1552 0 : skip_as = 0;
1553 0 : for (exclseg = exclude_list->segments;
1554 0 : exclseg && !skip_as; exclseg = exclseg->next)
1555 0 : for (y = 0; y < exclseg->length; y++)
1556 0 : if (srcseg->as[i] == exclseg->as[y]) {
1557 : skip_as = 1;
1558 : // There's no sense in testing
1559 : // the rest of exclusion list,
1560 : // bail out.
1561 : break;
1562 : }
1563 0 : if (!skip_as)
1564 0 : newlen++;
1565 : }
1566 : /* newlen is now the number of ASns to copy */
1567 0 : if (!newlen)
1568 0 : continue;
1569 :
1570 : /* Actual copying. Allocate memory and iterate once more,
1571 : * performing filtering. */
1572 0 : newseg = assegment_new(srcseg->type, newlen);
1573 0 : for (i = 0; i < srcseg->length; i++) {
1574 0 : skip_as = 0;
1575 0 : for (exclseg = exclude_list->segments;
1576 0 : exclseg && !skip_as; exclseg = exclseg->next)
1577 0 : for (y = 0; y < exclseg->length; y++)
1578 0 : if (srcseg->as[i] == exclseg->as[y]) {
1579 : skip_as = 1;
1580 : break;
1581 : }
1582 0 : if (skip_as)
1583 0 : continue;
1584 0 : newseg->as[done++] = srcseg->as[i];
1585 : }
1586 : /* At his point newlen must be equal to done, and both must be
1587 : * positive. Append
1588 : * the filtered segment to the gross result. */
1589 0 : if (!lastseg)
1590 0 : newpath->segments = newseg;
1591 : else
1592 0 : lastseg->next = newseg;
1593 : lastseg = newseg;
1594 : }
1595 0 : aspath_str_update(newpath, false);
1596 : /* We are happy returning even an empty AS_PATH, because the
1597 : * administrator
1598 : * might expect this very behaviour. There's a mean to avoid this, if
1599 : * necessary,
1600 : * by having a match rule against certain AS_PATH regexps in the
1601 : * route-map index.
1602 : */
1603 0 : aspath_free(source);
1604 0 : return newpath;
1605 : }
1606 :
1607 : /* Add specified AS to the leftmost of aspath. */
1608 7 : static struct aspath *aspath_add_asns(struct aspath *aspath, as_t asno,
1609 : uint8_t type, unsigned num)
1610 : {
1611 7 : struct assegment *assegment = aspath->segments;
1612 7 : unsigned i;
1613 :
1614 7 : if (assegment && assegment->type == type) {
1615 : /* extend existing segment */
1616 4 : aspath->segments =
1617 4 : assegment_prepend_asns(aspath->segments, asno, num);
1618 : } else {
1619 : /* prepend with new segment */
1620 3 : struct assegment *newsegment = assegment_new(type, num);
1621 9 : for (i = 0; i < num; i++)
1622 3 : newsegment->as[i] = asno;
1623 :
1624 : /* insert potentially replacing empty segment */
1625 3 : if (assegment && assegment->length == 0) {
1626 0 : newsegment->next = assegment->next;
1627 0 : assegment_free(assegment);
1628 : } else
1629 3 : newsegment->next = assegment;
1630 3 : aspath->segments = newsegment;
1631 : }
1632 :
1633 7 : aspath_str_update(aspath, false);
1634 7 : return aspath;
1635 : }
1636 :
1637 : /* Add specified AS to the leftmost of aspath num times. */
1638 0 : struct aspath *aspath_add_seq_n(struct aspath *aspath, as_t asno, unsigned num)
1639 : {
1640 0 : return aspath_add_asns(aspath, asno, AS_SEQUENCE, num);
1641 : }
1642 :
1643 : /* Add specified AS to the leftmost of aspath. */
1644 7 : struct aspath *aspath_add_seq(struct aspath *aspath, as_t asno)
1645 : {
1646 7 : return aspath_add_asns(aspath, asno, AS_SEQUENCE, 1);
1647 : }
1648 :
1649 : /* Compare leftmost AS value for MED check. If as1's leftmost AS and
1650 : as2's leftmost AS is same return 1. */
1651 0 : bool aspath_cmp_left(const struct aspath *aspath1, const struct aspath *aspath2)
1652 : {
1653 0 : const struct assegment *seg1;
1654 0 : const struct assegment *seg2;
1655 :
1656 0 : if (!(aspath1 && aspath2))
1657 : return false;
1658 :
1659 0 : seg1 = aspath1->segments;
1660 0 : seg2 = aspath2->segments;
1661 :
1662 : /* If both paths are originated in this AS then we do want to compare
1663 : * MED */
1664 0 : if (!seg1 && !seg2)
1665 : return true;
1666 :
1667 : /* find first non-confed segments for each */
1668 0 : while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1669 0 : || (seg1->type == AS_CONFED_SET)))
1670 0 : seg1 = seg1->next;
1671 :
1672 0 : while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1673 0 : || (seg2->type == AS_CONFED_SET)))
1674 0 : seg2 = seg2->next;
1675 :
1676 : /* Check as1's */
1677 0 : if (!(seg1 && seg2 && (seg1->type == AS_SEQUENCE)
1678 0 : && (seg2->type == AS_SEQUENCE)))
1679 : return false;
1680 :
1681 0 : if (seg1->as[0] == seg2->as[0])
1682 0 : return true;
1683 :
1684 : return false;
1685 : }
1686 :
1687 : /* Truncate an aspath after a number of hops, and put the hops remaining
1688 : * at the front of another aspath. Needed for AS4 compat.
1689 : *
1690 : * Returned aspath is a /new/ aspath, which should either by free'd or
1691 : * interned by the caller, as desired.
1692 : */
1693 0 : struct aspath *aspath_reconcile_as4(struct aspath *aspath,
1694 : struct aspath *as4path)
1695 : {
1696 0 : struct assegment *seg, *newseg, *prevseg = NULL;
1697 0 : struct aspath *newpath = NULL, *mergedpath;
1698 0 : int hops, cpasns = 0;
1699 :
1700 0 : if (!aspath || !as4path)
1701 : return NULL;
1702 :
1703 0 : seg = aspath->segments;
1704 :
1705 : /* CONFEDs should get reconciled too.. */
1706 0 : hops = (aspath_count_hops(aspath) + aspath_count_confeds(aspath))
1707 0 : - aspath_count_hops(as4path);
1708 :
1709 0 : if (hops < 0) {
1710 0 : if (BGP_DEBUG(as4, AS4))
1711 0 : flog_warn(
1712 : EC_BGP_ASPATH_FEWER_HOPS,
1713 : "[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1714 : /* Something's gone wrong. The RFC says we should now ignore
1715 : * AS4_PATH,
1716 : * which is daft behaviour - it contains vital loop-detection
1717 : * information which must have been removed from AS_PATH.
1718 : */
1719 0 : hops = aspath_count_hops(aspath);
1720 : }
1721 :
1722 0 : if (!hops) {
1723 0 : newpath = aspath_dup(as4path);
1724 0 : aspath_str_update(newpath, false);
1725 0 : return newpath;
1726 : }
1727 :
1728 0 : if (BGP_DEBUG(as4, AS4))
1729 0 : zlog_debug(
1730 : "[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1731 : aspath->str, as4path->str);
1732 :
1733 0 : while (seg && hops > 0) {
1734 0 : switch (seg->type) {
1735 0 : case AS_SET:
1736 : case AS_CONFED_SET:
1737 0 : hops--;
1738 0 : cpasns = seg->length;
1739 0 : break;
1740 0 : case AS_CONFED_SEQUENCE:
1741 : /* Should never split a confed-sequence, if hop-count
1742 : * suggests we must then something's gone wrong
1743 : * somewhere.
1744 : *
1745 : * Most important goal is to preserve AS_PATHs prime
1746 : * function
1747 : * as loop-detector, so we fudge the numbers so that the
1748 : * entire
1749 : * confed-sequence is merged in.
1750 : */
1751 0 : if (hops < seg->length) {
1752 0 : if (BGP_DEBUG(as4, AS4))
1753 0 : zlog_debug(
1754 : "[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls across 2/4 ASN boundary somewhere, broken..");
1755 0 : hops = seg->length;
1756 : }
1757 : /* fallthru */
1758 : case AS_SEQUENCE:
1759 0 : cpasns = MIN(seg->length, hops);
1760 0 : hops -= seg->length;
1761 : }
1762 :
1763 0 : assert(cpasns <= seg->length);
1764 :
1765 0 : newseg = assegment_new(seg->type, 0);
1766 0 : newseg = assegment_append_asns(newseg, seg->as, cpasns);
1767 :
1768 0 : if (!newpath) {
1769 0 : newpath = aspath_new();
1770 0 : newpath->segments = newseg;
1771 : } else
1772 0 : prevseg->next = newseg;
1773 :
1774 0 : prevseg = newseg;
1775 0 : seg = seg->next;
1776 : }
1777 :
1778 : /* We may be able to join some segments here, and we must
1779 : * do this because... we want normalised aspaths in out hash
1780 : * and we do not want to stumble in aspath_put.
1781 : */
1782 0 : mergedpath = aspath_merge(newpath, aspath_dup(as4path));
1783 0 : aspath_free(newpath);
1784 0 : mergedpath->segments = assegment_normalise(mergedpath->segments);
1785 0 : aspath_str_update(mergedpath, false);
1786 :
1787 0 : if (BGP_DEBUG(as4, AS4))
1788 0 : zlog_debug("[AS4] result of synthesizing is %s",
1789 : mergedpath->str);
1790 :
1791 : return mergedpath;
1792 : }
1793 :
1794 : /* Compare leftmost AS value for MED check. If as1's leftmost AS and
1795 : as2's leftmost AS is same return 1. (confederation as-path
1796 : only). */
1797 0 : bool aspath_cmp_left_confed(const struct aspath *aspath1,
1798 : const struct aspath *aspath2)
1799 : {
1800 0 : if (!(aspath1 && aspath2))
1801 : return false;
1802 :
1803 0 : if (!(aspath1->segments && aspath2->segments))
1804 : return false;
1805 :
1806 0 : if ((aspath1->segments->type != AS_CONFED_SEQUENCE)
1807 0 : || (aspath2->segments->type != AS_CONFED_SEQUENCE))
1808 : return false;
1809 :
1810 0 : if (aspath1->segments->as[0] == aspath2->segments->as[0])
1811 0 : return true;
1812 :
1813 : return false;
1814 : }
1815 :
1816 : /* Delete all AS_CONFED_SEQUENCE/SET segments from aspath.
1817 : * RFC 5065 section 4.1.c.1
1818 : *
1819 : * 1) if any path segments of the AS_PATH are of the type
1820 : * AS_CONFED_SEQUENCE or AS_CONFED_SET, those segments MUST be
1821 : * removed from the AS_PATH attribute, leaving the sanitized
1822 : * AS_PATH attribute to be operated on by steps 2, 3 or 4.
1823 : */
1824 7 : struct aspath *aspath_delete_confed_seq(struct aspath *aspath)
1825 : {
1826 7 : struct assegment *seg, *prev, *next;
1827 7 : char removed_confed_segment;
1828 :
1829 7 : if (!(aspath && aspath->segments))
1830 : return aspath;
1831 :
1832 : seg = aspath->segments;
1833 : removed_confed_segment = 0;
1834 8 : next = NULL;
1835 : prev = NULL;
1836 :
1837 8 : while (seg) {
1838 4 : next = seg->next;
1839 :
1840 4 : if (seg->type == AS_CONFED_SEQUENCE
1841 4 : || seg->type == AS_CONFED_SET) {
1842 : /* This is the first segment in the aspath */
1843 0 : if (aspath->segments == seg)
1844 0 : aspath->segments = seg->next;
1845 : else
1846 0 : prev->next = seg->next;
1847 :
1848 0 : assegment_free(seg);
1849 0 : removed_confed_segment = 1;
1850 : } else
1851 : prev = seg;
1852 :
1853 : seg = next;
1854 : }
1855 :
1856 4 : if (removed_confed_segment)
1857 0 : aspath_str_update(aspath, false);
1858 :
1859 : return aspath;
1860 : }
1861 :
1862 : /* Add new AS number to the leftmost part of the aspath as
1863 : AS_CONFED_SEQUENCE. */
1864 0 : struct aspath *aspath_add_confed_seq(struct aspath *aspath, as_t asno)
1865 : {
1866 0 : return aspath_add_asns(aspath, asno, AS_CONFED_SEQUENCE, 1);
1867 : }
1868 :
1869 : /* Add new as value to as path structure. */
1870 0 : static void aspath_as_add(struct aspath *as, as_t asno)
1871 : {
1872 0 : struct assegment *seg = as->segments;
1873 :
1874 0 : if (!seg)
1875 : return;
1876 :
1877 : /* Last segment search procedure. */
1878 0 : while (seg->next)
1879 : seg = seg->next;
1880 :
1881 0 : assegment_append_asns(seg, &asno, 1);
1882 : }
1883 :
1884 : /* Add new as segment to the as path. */
1885 0 : static void aspath_segment_add(struct aspath *as, int type)
1886 : {
1887 0 : struct assegment *seg = as->segments;
1888 0 : struct assegment *new = assegment_new(type, 0);
1889 :
1890 0 : if (seg) {
1891 0 : while (seg->next)
1892 : seg = seg->next;
1893 0 : seg->next = new;
1894 : } else
1895 0 : as->segments = new;
1896 0 : }
1897 :
1898 6 : struct aspath *aspath_empty(void)
1899 : {
1900 6 : return aspath_parse(NULL, 0, 1); /* 32Bit ;-) */
1901 : }
1902 :
1903 0 : struct aspath *aspath_empty_get(void)
1904 : {
1905 0 : struct aspath *aspath;
1906 :
1907 0 : aspath = aspath_new();
1908 0 : aspath_make_str_count(aspath, false);
1909 0 : return aspath;
1910 : }
1911 :
1912 0 : unsigned long aspath_count(void)
1913 : {
1914 0 : return ashash->count;
1915 : }
1916 :
1917 : /*
1918 : Theoretically, one as path can have:
1919 :
1920 : One BGP packet size should be less than 4096.
1921 : One BGP attribute size should be less than 4096 - BGP header size.
1922 : One BGP aspath size should be less than 4096 - BGP header size -
1923 : BGP mandantry attribute size.
1924 : */
1925 :
1926 : /* AS path string lexical token enum. */
1927 : enum as_token {
1928 : as_token_asval,
1929 : as_token_set_start,
1930 : as_token_set_end,
1931 : as_token_confed_seq_start,
1932 : as_token_confed_seq_end,
1933 : as_token_confed_set_start,
1934 : as_token_confed_set_end,
1935 : as_token_unknown
1936 : };
1937 :
1938 : /* Return next token and point for string parse. */
1939 0 : static const char *aspath_gettoken(const char *buf, enum as_token *token,
1940 : unsigned long *asno)
1941 : {
1942 0 : const char *p = buf;
1943 :
1944 : /* Skip separators (space for sequences, ',' for sets). */
1945 0 : while (isspace((unsigned char)*p) || *p == ',')
1946 0 : p++;
1947 :
1948 : /* Check the end of the string and type specify characters
1949 : (e.g. {}()). */
1950 0 : switch (*p) {
1951 : case '\0':
1952 : return NULL;
1953 0 : case '{':
1954 0 : *token = as_token_set_start;
1955 0 : p++;
1956 0 : return p;
1957 0 : case '}':
1958 0 : *token = as_token_set_end;
1959 0 : p++;
1960 0 : return p;
1961 0 : case '(':
1962 0 : *token = as_token_confed_seq_start;
1963 0 : p++;
1964 0 : return p;
1965 0 : case ')':
1966 0 : *token = as_token_confed_seq_end;
1967 0 : p++;
1968 0 : return p;
1969 0 : case '[':
1970 0 : *token = as_token_confed_set_start;
1971 0 : p++;
1972 0 : return p;
1973 0 : case ']':
1974 0 : *token = as_token_confed_set_end;
1975 0 : p++;
1976 0 : return p;
1977 : }
1978 :
1979 : /* Check actual AS value. */
1980 0 : if (isdigit((unsigned char)*p)) {
1981 0 : as_t asval;
1982 :
1983 0 : *token = as_token_asval;
1984 0 : asval = (*p - '0');
1985 0 : p++;
1986 :
1987 0 : while (isdigit((unsigned char)*p)) {
1988 0 : asval *= 10;
1989 0 : asval += (*p - '0');
1990 0 : p++;
1991 : }
1992 0 : *asno = asval;
1993 0 : return p;
1994 : }
1995 :
1996 : /* There is no match then return unknown token. */
1997 0 : *token = as_token_unknown;
1998 0 : p++;
1999 0 : return p;
2000 : }
2001 :
2002 0 : struct aspath *aspath_str2aspath(const char *str)
2003 : {
2004 0 : enum as_token token = as_token_unknown;
2005 0 : unsigned short as_type;
2006 0 : unsigned long asno = 0;
2007 0 : struct aspath *aspath;
2008 0 : int needtype;
2009 :
2010 0 : aspath = aspath_new();
2011 :
2012 : /* We start default type as AS_SEQUENCE. */
2013 0 : as_type = AS_SEQUENCE;
2014 0 : needtype = 1;
2015 :
2016 0 : while ((str = aspath_gettoken(str, &token, &asno)) != NULL) {
2017 0 : switch (token) {
2018 0 : case as_token_asval:
2019 0 : if (needtype) {
2020 0 : aspath_segment_add(aspath, as_type);
2021 0 : needtype = 0;
2022 : }
2023 0 : aspath_as_add(aspath, asno);
2024 0 : break;
2025 0 : case as_token_set_start:
2026 0 : as_type = AS_SET;
2027 0 : aspath_segment_add(aspath, as_type);
2028 0 : needtype = 0;
2029 0 : break;
2030 : case as_token_set_end:
2031 : as_type = AS_SEQUENCE;
2032 : needtype = 1;
2033 : break;
2034 0 : case as_token_confed_seq_start:
2035 0 : as_type = AS_CONFED_SEQUENCE;
2036 0 : aspath_segment_add(aspath, as_type);
2037 0 : needtype = 0;
2038 0 : break;
2039 : case as_token_confed_seq_end:
2040 : as_type = AS_SEQUENCE;
2041 : needtype = 1;
2042 : break;
2043 0 : case as_token_confed_set_start:
2044 0 : as_type = AS_CONFED_SET;
2045 0 : aspath_segment_add(aspath, as_type);
2046 0 : needtype = 0;
2047 0 : break;
2048 : case as_token_confed_set_end:
2049 : as_type = AS_SEQUENCE;
2050 : needtype = 1;
2051 : break;
2052 0 : case as_token_unknown:
2053 : default:
2054 0 : aspath_free(aspath);
2055 0 : return NULL;
2056 : }
2057 : }
2058 :
2059 0 : aspath_make_str_count(aspath, false);
2060 :
2061 0 : return aspath;
2062 : }
2063 :
2064 : /* Make hash value by raw aspath data. */
2065 131 : unsigned int aspath_key_make(const void *p)
2066 : {
2067 131 : const struct aspath *aspath = p;
2068 131 : unsigned int key = 0;
2069 :
2070 131 : if (!aspath->str)
2071 14 : aspath_str_update((struct aspath *)aspath, false);
2072 :
2073 131 : key = jhash(aspath->str, aspath->str_len, 2334325);
2074 :
2075 131 : return key;
2076 : }
2077 :
2078 : /* If two aspath have same value then return 1 else return 0 */
2079 18 : bool aspath_cmp(const void *arg1, const void *arg2)
2080 : {
2081 18 : const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
2082 18 : const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
2083 :
2084 30 : while (seg1 || seg2) {
2085 12 : int i;
2086 12 : if ((!seg1 && seg2) || (seg1 && !seg2))
2087 : return false;
2088 12 : if (seg1->type != seg2->type)
2089 : return false;
2090 12 : if (seg1->length != seg2->length)
2091 : return false;
2092 35 : for (i = 0; i < seg1->length; i++)
2093 23 : if (seg1->as[i] != seg2->as[i])
2094 : return false;
2095 12 : seg1 = seg1->next;
2096 12 : seg2 = seg2->next;
2097 : }
2098 : return true;
2099 : }
2100 :
2101 : /* AS path hash initialize. */
2102 3 : void aspath_init(void)
2103 : {
2104 3 : ashash = hash_create_size(32768, aspath_key_make, aspath_cmp,
2105 : "BGP AS Path");
2106 3 : }
2107 :
2108 3 : void aspath_finish(void)
2109 : {
2110 3 : hash_clean(ashash, (void (*)(void *))aspath_free);
2111 3 : hash_free(ashash);
2112 3 : ashash = NULL;
2113 :
2114 3 : if (snmp_stream)
2115 0 : stream_free(snmp_stream);
2116 3 : }
2117 :
2118 : /* return and as path value */
2119 0 : const char *aspath_print(struct aspath *as)
2120 : {
2121 0 : return (as ? as->str : NULL);
2122 : }
2123 :
2124 : /* Printing functions */
2125 : /* Feed the AS_PATH to the vty; the space suffix follows it only in case
2126 : * AS_PATH wasn't empty.
2127 : */
2128 0 : void aspath_print_vty(struct vty *vty, struct aspath *as)
2129 : {
2130 0 : vty_out(vty, "%s%s", as->str, as->str_len ? " " : "");
2131 0 : }
2132 :
2133 0 : static void aspath_show_all_iterator(struct hash_bucket *bucket,
2134 : struct vty *vty)
2135 : {
2136 0 : struct aspath *as;
2137 :
2138 0 : as = (struct aspath *)bucket->data;
2139 :
2140 0 : vty_out(vty, "[%p:%u] (%ld) ", (void *)bucket, bucket->key, as->refcnt);
2141 0 : vty_out(vty, "%s\n", as->str);
2142 0 : }
2143 :
2144 : /* Print all aspath and hash information. This function is used from
2145 : `show [ip] bgp paths' command. */
2146 0 : void aspath_print_all_vty(struct vty *vty)
2147 : {
2148 0 : hash_iterate(ashash, (void (*)(struct hash_bucket *,
2149 : void *))aspath_show_all_iterator,
2150 : vty);
2151 0 : }
2152 :
2153 0 : static struct aspath *bgp_aggr_aspath_lookup(struct bgp_aggregate *aggregate,
2154 : struct aspath *aspath)
2155 : {
2156 0 : return hash_lookup(aggregate->aspath_hash, aspath);
2157 : }
2158 :
2159 0 : static void *bgp_aggr_aspath_hash_alloc(void *p)
2160 : {
2161 0 : struct aspath *ref = (struct aspath *)p;
2162 0 : struct aspath *aspath = NULL;
2163 :
2164 0 : aspath = aspath_dup(ref);
2165 0 : return aspath;
2166 : }
2167 :
2168 0 : static void bgp_aggr_aspath_prepare(struct hash_bucket *hb, void *arg)
2169 : {
2170 0 : struct aspath *hb_aspath = hb->data;
2171 0 : struct aspath **aggr_aspath = arg;
2172 :
2173 0 : if (*aggr_aspath)
2174 0 : *aggr_aspath = aspath_aggregate(*aggr_aspath, hb_aspath);
2175 : else
2176 0 : *aggr_aspath = aspath_dup(hb_aspath);
2177 0 : }
2178 :
2179 0 : void bgp_aggr_aspath_remove(void *arg)
2180 : {
2181 0 : struct aspath *aspath = arg;
2182 :
2183 0 : aspath_free(aspath);
2184 0 : }
2185 :
2186 0 : void bgp_compute_aggregate_aspath(struct bgp_aggregate *aggregate,
2187 : struct aspath *aspath)
2188 : {
2189 0 : bgp_compute_aggregate_aspath_hash(aggregate, aspath);
2190 :
2191 0 : bgp_compute_aggregate_aspath_val(aggregate);
2192 :
2193 0 : }
2194 :
2195 0 : void bgp_compute_aggregate_aspath_hash(struct bgp_aggregate *aggregate,
2196 : struct aspath *aspath)
2197 : {
2198 0 : struct aspath *aggr_aspath = NULL;
2199 :
2200 0 : if ((aggregate == NULL) || (aspath == NULL))
2201 : return;
2202 :
2203 : /* Create hash if not already created.
2204 : */
2205 0 : if (aggregate->aspath_hash == NULL)
2206 0 : aggregate->aspath_hash = hash_create(
2207 : aspath_key_make, aspath_cmp,
2208 : "BGP Aggregator as-path hash");
2209 :
2210 0 : aggr_aspath = bgp_aggr_aspath_lookup(aggregate, aspath);
2211 0 : if (aggr_aspath == NULL) {
2212 : /* Insert as-path into hash.
2213 : */
2214 0 : aggr_aspath = hash_get(aggregate->aspath_hash, aspath,
2215 : bgp_aggr_aspath_hash_alloc);
2216 : }
2217 :
2218 : /* Increment reference counter.
2219 : */
2220 0 : aggr_aspath->refcnt++;
2221 : }
2222 :
2223 0 : void bgp_compute_aggregate_aspath_val(struct bgp_aggregate *aggregate)
2224 : {
2225 0 : if (aggregate == NULL)
2226 : return;
2227 : /* Re-compute aggregate's as-path.
2228 : */
2229 0 : if (aggregate->aspath) {
2230 0 : aspath_free(aggregate->aspath);
2231 0 : aggregate->aspath = NULL;
2232 : }
2233 0 : if (aggregate->aspath_hash
2234 0 : && aggregate->aspath_hash->count) {
2235 0 : hash_iterate(aggregate->aspath_hash,
2236 : bgp_aggr_aspath_prepare,
2237 0 : &aggregate->aspath);
2238 : }
2239 : }
2240 :
2241 0 : void bgp_remove_aspath_from_aggregate(struct bgp_aggregate *aggregate,
2242 : struct aspath *aspath)
2243 : {
2244 0 : struct aspath *aggr_aspath = NULL;
2245 0 : struct aspath *ret_aspath = NULL;
2246 :
2247 0 : if ((!aggregate)
2248 0 : || (!aggregate->aspath_hash)
2249 0 : || (!aspath))
2250 : return;
2251 :
2252 : /* Look-up the aspath in the hash.
2253 : */
2254 0 : aggr_aspath = bgp_aggr_aspath_lookup(aggregate, aspath);
2255 0 : if (aggr_aspath) {
2256 0 : aggr_aspath->refcnt--;
2257 :
2258 0 : if (aggr_aspath->refcnt == 0) {
2259 0 : ret_aspath = hash_release(aggregate->aspath_hash,
2260 : aggr_aspath);
2261 0 : aspath_free(ret_aspath);
2262 0 : ret_aspath = NULL;
2263 :
2264 : /* Remove aggregate's old as-path.
2265 : */
2266 0 : aspath_free(aggregate->aspath);
2267 0 : aggregate->aspath = NULL;
2268 :
2269 0 : bgp_compute_aggregate_aspath_val(aggregate);
2270 : }
2271 : }
2272 : }
2273 :
2274 0 : void bgp_remove_aspath_from_aggregate_hash(struct bgp_aggregate *aggregate,
2275 : struct aspath *aspath)
2276 : {
2277 0 : struct aspath *aggr_aspath = NULL;
2278 0 : struct aspath *ret_aspath = NULL;
2279 :
2280 0 : if ((!aggregate)
2281 0 : || (!aggregate->aspath_hash)
2282 0 : || (!aspath))
2283 : return;
2284 :
2285 : /* Look-up the aspath in the hash.
2286 : */
2287 0 : aggr_aspath = bgp_aggr_aspath_lookup(aggregate, aspath);
2288 0 : if (aggr_aspath) {
2289 0 : aggr_aspath->refcnt--;
2290 :
2291 0 : if (aggr_aspath->refcnt == 0) {
2292 0 : ret_aspath = hash_release(aggregate->aspath_hash,
2293 : aggr_aspath);
2294 0 : aspath_free(ret_aspath);
2295 0 : ret_aspath = NULL;
2296 : }
2297 : }
2298 : }
2299 :
|