Coverage Report

Created: 2026-01-13 06:56

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