Line data Source code
1 : /* BGP attributes management routines.
2 : Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
3 :
4 : This file is part of GNU Zebra.
5 :
6 : GNU Zebra is free software; you can redistribute it and/or modify it
7 : under the terms of the GNU General Public License as published by the
8 : Free Software Foundation; either version 2, or (at your option) any
9 : later version.
10 :
11 : GNU Zebra is distributed in the hope that it will be useful, but
12 : WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with GNU Zebra; see the file COPYING. If not, write to the Free
18 : Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 : 02111-1307, USA. */
20 :
21 : #include <zebra.h>
22 :
23 : #include "linklist.h"
24 : #include "prefix.h"
25 : #include "memory.h"
26 : #include "vector.h"
27 : #include "vty.h"
28 : #include "stream.h"
29 : #include "log.h"
30 : #include "hash.h"
31 : #include "jhash.h"
32 :
33 : #include "bgpd/bgpd.h"
34 : #include "bgpd/bgp_attr.h"
35 : #include "bgpd/bgp_route.h"
36 : #include "bgpd/bgp_aspath.h"
37 : #include "bgpd/bgp_community.h"
38 : #include "bgpd/bgp_debug.h"
39 : #include "bgpd/bgp_packet.h"
40 : #include "bgpd/bgp_ecommunity.h"
41 :
42 : /* Attribute strings for logging. */
43 : static const struct message attr_str [] =
44 : {
45 : { BGP_ATTR_ORIGIN, "ORIGIN" },
46 : { BGP_ATTR_AS_PATH, "AS_PATH" },
47 : { BGP_ATTR_NEXT_HOP, "NEXT_HOP" },
48 : { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
49 : { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" },
50 : { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
51 : { BGP_ATTR_AGGREGATOR, "AGGREGATOR" },
52 : { BGP_ATTR_COMMUNITIES, "COMMUNITY" },
53 : { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" },
54 : { BGP_ATTR_CLUSTER_LIST, "CLUSTER_LIST" },
55 : { BGP_ATTR_DPA, "DPA" },
56 : { BGP_ATTR_ADVERTISER, "ADVERTISER"} ,
57 : { BGP_ATTR_RCID_PATH, "RCID_PATH" },
58 : { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
59 : { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
60 : { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" },
61 : { BGP_ATTR_AS4_PATH, "AS4_PATH" },
62 : { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" },
63 : { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" },
64 : };
65 : static const int attr_str_max = array_size(attr_str);
66 :
67 : static const struct message attr_flag_str[] =
68 : {
69 : { BGP_ATTR_FLAG_OPTIONAL, "Optional" },
70 : { BGP_ATTR_FLAG_TRANS, "Transitive" },
71 : { BGP_ATTR_FLAG_PARTIAL, "Partial" },
72 : /* bgp_attr_flags_diagnose() relies on this bit being last in this list */
73 : { BGP_ATTR_FLAG_EXTLEN, "Extended Length" },
74 : };
75 : static const size_t attr_flag_str_max = array_size(attr_flag_str);
76 :
77 : static struct hash *cluster_hash;
78 :
79 : static void *
80 0 : cluster_hash_alloc (void *p)
81 : {
82 0 : struct cluster_list * val = (struct cluster_list *) p;
83 : struct cluster_list *cluster;
84 :
85 0 : cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
86 0 : cluster->length = val->length;
87 :
88 0 : if (cluster->length)
89 : {
90 0 : cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
91 0 : memcpy (cluster->list, val->list, val->length);
92 : }
93 : else
94 0 : cluster->list = NULL;
95 :
96 0 : cluster->refcnt = 0;
97 :
98 0 : return cluster;
99 : }
100 :
101 : /* Cluster list related functions. */
102 : static struct cluster_list *
103 0 : cluster_parse (struct in_addr * pnt, int length)
104 : {
105 : struct cluster_list tmp;
106 : struct cluster_list *cluster;
107 :
108 0 : tmp.length = length;
109 0 : tmp.list = pnt;
110 :
111 0 : cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
112 0 : cluster->refcnt++;
113 0 : return cluster;
114 : }
115 :
116 : int
117 0 : cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
118 : {
119 : int i;
120 :
121 0 : for (i = 0; i < cluster->length / 4; i++)
122 0 : if (cluster->list[i].s_addr == originator.s_addr)
123 0 : return 1;
124 0 : return 0;
125 : }
126 :
127 : static unsigned int
128 0 : cluster_hash_key_make (void *p)
129 : {
130 0 : const struct cluster_list *cluster = p;
131 :
132 0 : return jhash(cluster->list, cluster->length, 0);
133 : }
134 :
135 : static int
136 0 : cluster_hash_cmp (const void *p1, const void *p2)
137 : {
138 0 : const struct cluster_list * cluster1 = p1;
139 0 : const struct cluster_list * cluster2 = p2;
140 :
141 0 : return (cluster1->length == cluster2->length &&
142 0 : memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
143 : }
144 :
145 : static void
146 0 : cluster_free (struct cluster_list *cluster)
147 : {
148 0 : if (cluster->list)
149 0 : XFREE (MTYPE_CLUSTER_VAL, cluster->list);
150 0 : XFREE (MTYPE_CLUSTER, cluster);
151 0 : }
152 :
153 : #if 0
154 : static struct cluster_list *
155 : cluster_dup (struct cluster_list *cluster)
156 : {
157 : struct cluster_list *new;
158 :
159 : new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
160 : new->length = cluster->length;
161 :
162 : if (cluster->length)
163 : {
164 : new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
165 : memcpy (new->list, cluster->list, cluster->length);
166 : }
167 : else
168 : new->list = NULL;
169 :
170 : return new;
171 : }
172 : #endif
173 :
174 : static struct cluster_list *
175 0 : cluster_intern (struct cluster_list *cluster)
176 : {
177 : struct cluster_list *find;
178 :
179 0 : find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
180 0 : find->refcnt++;
181 :
182 0 : return find;
183 : }
184 :
185 : void
186 0 : cluster_unintern (struct cluster_list *cluster)
187 : {
188 0 : if (cluster->refcnt)
189 0 : cluster->refcnt--;
190 :
191 0 : if (cluster->refcnt == 0)
192 : {
193 0 : hash_release (cluster_hash, cluster);
194 0 : cluster_free (cluster);
195 : }
196 0 : }
197 :
198 : static void
199 1 : cluster_init (void)
200 : {
201 1 : cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
202 1 : }
203 :
204 : static void
205 0 : cluster_finish (void)
206 : {
207 0 : hash_free (cluster_hash);
208 0 : cluster_hash = NULL;
209 0 : }
210 :
211 : /* Unknown transit attribute. */
212 : static struct hash *transit_hash;
213 :
214 : static void
215 0 : transit_free (struct transit *transit)
216 : {
217 0 : if (transit->val)
218 0 : XFREE (MTYPE_TRANSIT_VAL, transit->val);
219 0 : XFREE (MTYPE_TRANSIT, transit);
220 0 : }
221 :
222 :
223 : static void *
224 0 : transit_hash_alloc (void *p)
225 : {
226 : /* Transit structure is already allocated. */
227 0 : return p;
228 : }
229 :
230 : static struct transit *
231 0 : transit_intern (struct transit *transit)
232 : {
233 : struct transit *find;
234 :
235 0 : find = hash_get (transit_hash, transit, transit_hash_alloc);
236 0 : if (find != transit)
237 0 : transit_free (transit);
238 0 : find->refcnt++;
239 :
240 0 : return find;
241 : }
242 :
243 : void
244 0 : transit_unintern (struct transit *transit)
245 : {
246 0 : if (transit->refcnt)
247 0 : transit->refcnt--;
248 :
249 0 : if (transit->refcnt == 0)
250 : {
251 0 : hash_release (transit_hash, transit);
252 0 : transit_free (transit);
253 : }
254 0 : }
255 :
256 : static unsigned int
257 0 : transit_hash_key_make (void *p)
258 : {
259 0 : const struct transit * transit = p;
260 :
261 0 : return jhash(transit->val, transit->length, 0);
262 : }
263 :
264 : static int
265 0 : transit_hash_cmp (const void *p1, const void *p2)
266 : {
267 0 : const struct transit * transit1 = p1;
268 0 : const struct transit * transit2 = p2;
269 :
270 0 : return (transit1->length == transit2->length &&
271 0 : memcmp (transit1->val, transit2->val, transit1->length) == 0);
272 : }
273 :
274 : static void
275 1 : transit_init (void)
276 : {
277 1 : transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
278 1 : }
279 :
280 : static void
281 0 : transit_finish (void)
282 : {
283 0 : hash_free (transit_hash);
284 0 : transit_hash = NULL;
285 0 : }
286 :
287 : /* Attribute hash routines. */
288 : static struct hash *attrhash;
289 :
290 : static struct attr_extra *
291 14 : bgp_attr_extra_new (void)
292 : {
293 14 : return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
294 : }
295 :
296 : void
297 0 : bgp_attr_extra_free (struct attr *attr)
298 : {
299 0 : if (attr->extra)
300 : {
301 0 : XFREE (MTYPE_ATTR_EXTRA, attr->extra);
302 0 : attr->extra = NULL;
303 : }
304 0 : }
305 :
306 : struct attr_extra *
307 14 : bgp_attr_extra_get (struct attr *attr)
308 : {
309 14 : if (!attr->extra)
310 14 : attr->extra = bgp_attr_extra_new();
311 14 : return attr->extra;
312 : }
313 :
314 : /* Shallow copy of an attribute
315 : * Though, not so shallow that it doesn't copy the contents
316 : * of the attr_extra pointed to by 'extra'
317 : */
318 : void
319 0 : bgp_attr_dup (struct attr *new, struct attr *orig)
320 : {
321 0 : struct attr_extra *extra = new->extra;
322 :
323 0 : *new = *orig;
324 : /* if caller provided attr_extra space, use it in any case.
325 : *
326 : * This is neccesary even if orig->extra equals NULL, because otherwise
327 : * memory may be later allocated on the heap by bgp_attr_extra_get.
328 : *
329 : * That memory would eventually be leaked, because the caller must not
330 : * call bgp_attr_extra_free if he provided attr_extra on the stack.
331 : */
332 0 : if (extra)
333 : {
334 0 : new->extra = extra;
335 0 : memset(new->extra, 0, sizeof(struct attr_extra));
336 0 : if (orig->extra)
337 0 : *new->extra = *orig->extra;
338 : }
339 0 : else if (orig->extra)
340 : {
341 0 : new->extra = bgp_attr_extra_new();
342 0 : *new->extra = *orig->extra;
343 : }
344 0 : }
345 :
346 : unsigned long int
347 0 : attr_count (void)
348 : {
349 0 : return attrhash->count;
350 : }
351 :
352 : unsigned long int
353 0 : attr_unknown_count (void)
354 : {
355 0 : return transit_hash->count;
356 : }
357 :
358 : unsigned int
359 0 : attrhash_key_make (void *p)
360 : {
361 0 : const struct attr *attr = (struct attr *) p;
362 0 : const struct attr_extra *extra = attr->extra;
363 0 : uint32_t key = 0;
364 : #define MIX(val) key = jhash_1word(val, key)
365 :
366 0 : MIX(attr->origin);
367 0 : MIX(attr->nexthop.s_addr);
368 0 : MIX(attr->med);
369 0 : MIX(attr->local_pref);
370 :
371 0 : key += attr->origin;
372 0 : key += attr->nexthop.s_addr;
373 0 : key += attr->med;
374 0 : key += attr->local_pref;
375 :
376 0 : if (extra)
377 : {
378 0 : MIX(extra->aggregator_as);
379 0 : MIX(extra->aggregator_addr.s_addr);
380 0 : MIX(extra->weight);
381 0 : MIX(extra->mp_nexthop_global_in.s_addr);
382 : }
383 :
384 0 : if (attr->aspath)
385 0 : MIX(aspath_key_make (attr->aspath));
386 0 : if (attr->community)
387 0 : MIX(community_hash_make (attr->community));
388 :
389 0 : if (extra)
390 : {
391 0 : if (extra->ecommunity)
392 0 : MIX(ecommunity_hash_make (extra->ecommunity));
393 0 : if (extra->cluster)
394 0 : MIX(cluster_hash_key_make (extra->cluster));
395 0 : if (extra->transit)
396 0 : MIX(transit_hash_key_make (extra->transit));
397 :
398 : #ifdef HAVE_IPV6
399 0 : MIX(extra->mp_nexthop_len);
400 0 : key = jhash(extra->mp_nexthop_global.s6_addr, 16, key);
401 0 : key = jhash(extra->mp_nexthop_local.s6_addr, 16, key);
402 : #endif /* HAVE_IPV6 */
403 : }
404 :
405 0 : return key;
406 : }
407 :
408 : int
409 0 : attrhash_cmp (const void *p1, const void *p2)
410 : {
411 0 : const struct attr * attr1 = p1;
412 0 : const struct attr * attr2 = p2;
413 :
414 0 : if (attr1->flag == attr2->flag
415 0 : && attr1->origin == attr2->origin
416 0 : && attr1->nexthop.s_addr == attr2->nexthop.s_addr
417 0 : && attr1->aspath == attr2->aspath
418 0 : && attr1->community == attr2->community
419 0 : && attr1->med == attr2->med
420 0 : && attr1->local_pref == attr2->local_pref)
421 : {
422 0 : const struct attr_extra *ae1 = attr1->extra;
423 0 : const struct attr_extra *ae2 = attr2->extra;
424 :
425 0 : if (ae1 && ae2
426 0 : && ae1->aggregator_as == ae2->aggregator_as
427 0 : && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
428 0 : && ae1->weight == ae2->weight
429 : #ifdef HAVE_IPV6
430 0 : && ae1->mp_nexthop_len == ae2->mp_nexthop_len
431 0 : && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
432 0 : && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
433 : #endif /* HAVE_IPV6 */
434 0 : && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
435 0 : && ae1->ecommunity == ae2->ecommunity
436 0 : && ae1->cluster == ae2->cluster
437 0 : && ae1->transit == ae2->transit)
438 0 : return 1;
439 0 : else if (ae1 || ae2)
440 0 : return 0;
441 : /* neither attribute has extra attributes, so they're same */
442 0 : return 1;
443 : }
444 : else
445 0 : return 0;
446 : }
447 :
448 : static void
449 1 : attrhash_init (void)
450 : {
451 1 : attrhash = hash_create (attrhash_key_make, attrhash_cmp);
452 1 : }
453 :
454 : static void
455 0 : attrhash_finish (void)
456 : {
457 0 : hash_free (attrhash);
458 0 : attrhash = NULL;
459 0 : }
460 :
461 : static void
462 0 : attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
463 : {
464 0 : struct attr *attr = backet->data;
465 :
466 0 : vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
467 0 : inet_ntoa (attr->nexthop), VTY_NEWLINE);
468 0 : }
469 :
470 : void
471 0 : attr_show_all (struct vty *vty)
472 : {
473 0 : hash_iterate (attrhash,
474 : (void (*)(struct hash_backet *, void *))
475 : attr_show_all_iterator,
476 : vty);
477 0 : }
478 :
479 : static void *
480 0 : bgp_attr_hash_alloc (void *p)
481 : {
482 0 : struct attr * val = (struct attr *) p;
483 : struct attr *attr;
484 :
485 0 : attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
486 0 : *attr = *val;
487 0 : if (val->extra)
488 : {
489 0 : attr->extra = bgp_attr_extra_new ();
490 0 : *attr->extra = *val->extra;
491 : }
492 0 : attr->refcnt = 0;
493 0 : return attr;
494 : }
495 :
496 : /* Internet argument attribute. */
497 : struct attr *
498 0 : bgp_attr_intern (struct attr *attr)
499 : {
500 : struct attr *find;
501 :
502 : /* Intern referenced strucutre. */
503 0 : if (attr->aspath)
504 : {
505 0 : if (! attr->aspath->refcnt)
506 0 : attr->aspath = aspath_intern (attr->aspath);
507 : else
508 0 : attr->aspath->refcnt++;
509 : }
510 0 : if (attr->community)
511 : {
512 0 : if (! attr->community->refcnt)
513 0 : attr->community = community_intern (attr->community);
514 : else
515 0 : attr->community->refcnt++;
516 : }
517 0 : if (attr->extra)
518 : {
519 0 : struct attr_extra *attre = attr->extra;
520 :
521 0 : if (attre->ecommunity)
522 : {
523 0 : if (! attre->ecommunity->refcnt)
524 0 : attre->ecommunity = ecommunity_intern (attre->ecommunity);
525 : else
526 0 : attre->ecommunity->refcnt++;
527 :
528 : }
529 0 : if (attre->cluster)
530 : {
531 0 : if (! attre->cluster->refcnt)
532 0 : attre->cluster = cluster_intern (attre->cluster);
533 : else
534 0 : attre->cluster->refcnt++;
535 : }
536 0 : if (attre->transit)
537 : {
538 0 : if (! attre->transit->refcnt)
539 0 : attre->transit = transit_intern (attre->transit);
540 : else
541 0 : attre->transit->refcnt++;
542 : }
543 : }
544 :
545 0 : find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
546 0 : find->refcnt++;
547 :
548 0 : return find;
549 : }
550 :
551 :
552 : /* Make network statement's attribute. */
553 : struct attr *
554 0 : bgp_attr_default_set (struct attr *attr, u_char origin)
555 : {
556 0 : memset (attr, 0, sizeof (struct attr));
557 0 : bgp_attr_extra_get (attr);
558 :
559 0 : attr->origin = origin;
560 0 : attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
561 0 : attr->aspath = aspath_empty ();
562 0 : attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
563 0 : attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
564 0 : attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
565 : #ifdef HAVE_IPV6
566 0 : attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
567 : #endif
568 :
569 0 : return attr;
570 : }
571 :
572 :
573 : /* Make network statement's attribute. */
574 : struct attr *
575 0 : bgp_attr_default_intern (u_char origin)
576 : {
577 : struct attr attr;
578 : struct attr *new;
579 :
580 0 : bgp_attr_default_set(&attr, origin);
581 :
582 0 : new = bgp_attr_intern (&attr);
583 0 : bgp_attr_extra_free (&attr);
584 :
585 0 : aspath_unintern (&new->aspath);
586 0 : return new;
587 : }
588 :
589 : struct attr *
590 0 : bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
591 : struct aspath *aspath,
592 : struct community *community, int as_set)
593 : {
594 : struct attr attr;
595 : struct attr *new;
596 : struct attr_extra attre;
597 :
598 0 : memset (&attr, 0, sizeof (struct attr));
599 0 : memset (&attre, 0, sizeof (struct attr_extra));
600 0 : attr.extra = &attre;
601 :
602 : /* Origin attribute. */
603 0 : attr.origin = origin;
604 0 : attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
605 :
606 : /* AS path attribute. */
607 0 : if (aspath)
608 0 : attr.aspath = aspath_intern (aspath);
609 : else
610 0 : attr.aspath = aspath_empty ();
611 0 : attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
612 :
613 : /* Next hop attribute. */
614 0 : attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
615 :
616 0 : if (community)
617 : {
618 0 : attr.community = community;
619 0 : attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
620 : }
621 :
622 0 : attre.weight = BGP_ATTR_DEFAULT_WEIGHT;
623 : #ifdef HAVE_IPV6
624 0 : attre.mp_nexthop_len = IPV6_MAX_BYTELEN;
625 : #endif
626 0 : if (! as_set)
627 0 : attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
628 0 : attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
629 0 : if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
630 0 : attre.aggregator_as = bgp->confed_id;
631 : else
632 0 : attre.aggregator_as = bgp->as;
633 0 : attre.aggregator_addr = bgp->router_id;
634 :
635 0 : new = bgp_attr_intern (&attr);
636 :
637 0 : aspath_unintern (&new->aspath);
638 0 : return new;
639 : }
640 :
641 : /* Unintern just the sub-components of the attr, but not the attr */
642 : void
643 0 : bgp_attr_unintern_sub (struct attr *attr)
644 : {
645 : /* aspath refcount shoud be decrement. */
646 0 : if (attr->aspath)
647 0 : aspath_unintern (&attr->aspath);
648 0 : UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH);
649 :
650 0 : if (attr->community)
651 0 : community_unintern (&attr->community);
652 0 : UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES);
653 :
654 0 : if (attr->extra)
655 : {
656 0 : if (attr->extra->ecommunity)
657 0 : ecommunity_unintern (&attr->extra->ecommunity);
658 0 : UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES);
659 :
660 0 : if (attr->extra->cluster)
661 0 : cluster_unintern (attr->extra->cluster);
662 0 : UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST);
663 :
664 0 : if (attr->extra->transit)
665 0 : transit_unintern (attr->extra->transit);
666 : }
667 0 : }
668 :
669 : /* Free bgp attribute and aspath. */
670 : void
671 0 : bgp_attr_unintern (struct attr **pattr)
672 : {
673 0 : struct attr *attr = *pattr;
674 : struct attr *ret;
675 : struct attr tmp;
676 : struct attr_extra tmp_extra;
677 :
678 : /* Decrement attribute reference. */
679 0 : attr->refcnt--;
680 :
681 0 : tmp = *attr;
682 :
683 0 : if (attr->extra)
684 : {
685 0 : tmp.extra = &tmp_extra;
686 0 : memcpy (tmp.extra, attr->extra, sizeof (struct attr_extra));
687 : }
688 :
689 : /* If reference becomes zero then free attribute object. */
690 0 : if (attr->refcnt == 0)
691 : {
692 0 : ret = hash_release (attrhash, attr);
693 0 : assert (ret != NULL);
694 0 : bgp_attr_extra_free (attr);
695 0 : XFREE (MTYPE_ATTR, attr);
696 0 : *pattr = NULL;
697 : }
698 :
699 0 : bgp_attr_unintern_sub (&tmp);
700 0 : }
701 :
702 : void
703 0 : bgp_attr_flush (struct attr *attr)
704 : {
705 0 : if (attr->aspath && ! attr->aspath->refcnt)
706 0 : aspath_free (attr->aspath);
707 0 : if (attr->community && ! attr->community->refcnt)
708 0 : community_free (attr->community);
709 0 : if (attr->extra)
710 : {
711 0 : struct attr_extra *attre = attr->extra;
712 :
713 0 : if (attre->ecommunity && ! attre->ecommunity->refcnt)
714 0 : ecommunity_free (&attre->ecommunity);
715 0 : if (attre->cluster && ! attre->cluster->refcnt)
716 0 : cluster_free (attre->cluster);
717 0 : if (attre->transit && ! attre->transit->refcnt)
718 0 : transit_free (attre->transit);
719 : }
720 0 : }
721 :
722 : /* Implement draft-scudder-idr-optional-transitive behaviour and
723 : * avoid resetting sessions for malformed attributes which are
724 : * are partial/optional and hence where the error likely was not
725 : * introduced by the sending neighbour.
726 : */
727 : static bgp_attr_parse_ret_t
728 6 : bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode,
729 : bgp_size_t length)
730 : {
731 6 : struct peer *const peer = args->peer;
732 6 : const u_int8_t flags = args->flags;
733 : /* startp and length must be special-cased, as whether or not to
734 : * send the attribute data with the NOTIFY depends on the error,
735 : * the caller therefore signals this with the seperate length argument
736 : */
737 6 : u_char *notify_datap = (length > 0 ? args->startp : NULL);
738 :
739 : /* Only relax error handling for eBGP peers */
740 6 : if (peer->sort != BGP_PEER_EBGP)
741 : {
742 6 : bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
743 : notify_datap, length);
744 6 : return BGP_ATTR_PARSE_ERROR;
745 :
746 : }
747 :
748 : /* Adjust the stream getp to the end of the attribute, in case we can
749 : * still proceed but the caller hasn't read all the attribute.
750 : */
751 0 : stream_set_getp (BGP_INPUT (peer),
752 0 : (args->startp - STREAM_DATA (BGP_INPUT (peer)))
753 0 : + args->total);
754 :
755 0 : switch (args->type) {
756 : /* where an attribute is relatively inconsequential, e.g. it does not
757 : * affect route selection, and can be safely ignored, then any such
758 : * attributes which are malformed should just be ignored and the route
759 : * processed as normal.
760 : */
761 : case BGP_ATTR_AS4_AGGREGATOR:
762 : case BGP_ATTR_AGGREGATOR:
763 : case BGP_ATTR_ATOMIC_AGGREGATE:
764 0 : return BGP_ATTR_PARSE_PROCEED;
765 :
766 : /* Core attributes, particularly ones which may influence route
767 : * selection, should always cause session resets
768 : */
769 : case BGP_ATTR_ORIGIN:
770 : case BGP_ATTR_AS_PATH:
771 : case BGP_ATTR_NEXT_HOP:
772 : case BGP_ATTR_MULTI_EXIT_DISC:
773 : case BGP_ATTR_LOCAL_PREF:
774 : case BGP_ATTR_COMMUNITIES:
775 : case BGP_ATTR_ORIGINATOR_ID:
776 : case BGP_ATTR_CLUSTER_LIST:
777 : case BGP_ATTR_MP_REACH_NLRI:
778 : case BGP_ATTR_MP_UNREACH_NLRI:
779 : case BGP_ATTR_EXT_COMMUNITIES:
780 0 : bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
781 : notify_datap, length);
782 0 : return BGP_ATTR_PARSE_ERROR;
783 : }
784 :
785 : /* Partial optional attributes that are malformed should not cause
786 : * the whole session to be reset. Instead treat it as a withdrawal
787 : * of the routes, if possible.
788 : */
789 0 : if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)
790 0 : && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
791 0 : && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
792 0 : return BGP_ATTR_PARSE_WITHDRAW;
793 :
794 : /* default to reset */
795 0 : return BGP_ATTR_PARSE_ERROR;
796 : }
797 :
798 : /* Find out what is wrong with the path attribute flag bits and log the error.
799 : "Flag bits" here stand for Optional, Transitive and Partial, but not for
800 : Extended Length. Checking O/T/P bits at once implies, that the attribute
801 : being diagnosed is defined by RFC as either a "well-known" or an "optional,
802 : non-transitive" attribute. */
803 : static void
804 2 : bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args,
805 : u_int8_t desired_flags /* how RFC says it must be */
806 : )
807 : {
808 2 : u_char seen = 0, i;
809 2 : u_char real_flags = args->flags;
810 2 : const u_int8_t attr_code = args->type;
811 :
812 2 : desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
813 2 : real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
814 8 : for (i = 0; i <= 2; i++) /* O,T,P, but not E */
815 : if
816 6 : (
817 6 : CHECK_FLAG (desired_flags, attr_flag_str[i].key) !=
818 : CHECK_FLAG (real_flags, attr_flag_str[i].key)
819 : )
820 : {
821 4 : zlog (args->peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"",
822 : LOOKUP (attr_str, attr_code),
823 2 : CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
824 : attr_flag_str[i].str);
825 2 : seen = 1;
826 : }
827 2 : if (!seen)
828 : {
829 0 : zlog (args->peer->log, LOG_DEBUG,
830 : "Strange, %s called for attr %s, but no problem found with flags"
831 : " (real flags 0x%x, desired 0x%x)",
832 : __func__, LOOKUP (attr_str, attr_code),
833 : real_flags, desired_flags);
834 : }
835 2 : }
836 :
837 : /* Required flags for attributes. EXTLEN will be masked off when testing,
838 : * as will PARTIAL for optional+transitive attributes.
839 : */
840 : const u_int8_t attr_flags_values [] = {
841 : [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS,
842 : [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS,
843 : [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS,
844 : [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL,
845 : [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS,
846 : [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
847 : [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
848 : [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
849 : [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL,
850 : [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL,
851 : [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
852 : [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
853 : [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
854 : [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
855 : [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
856 : };
857 : static const size_t attr_flags_values_max =
858 : sizeof (attr_flags_values) / sizeof (attr_flags_values[0]);
859 :
860 : static int
861 11 : bgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
862 : {
863 11 : u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
864 11 : const u_int8_t flags = args->flags;
865 11 : const u_int8_t attr_code = args->type;
866 11 : struct peer *const peer = args->peer;
867 :
868 : /* there may be attributes we don't know about */
869 11 : if (attr_code > attr_flags_values_max)
870 0 : return 0;
871 11 : if (attr_flags_values[attr_code] == 0)
872 0 : return 0;
873 :
874 : /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
875 : * 1."
876 : */
877 11 : if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags)
878 5 : && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags))
879 : {
880 0 : zlog (peer->log, LOG_ERR,
881 : "%s well-known attributes must have transitive flag set (%x)",
882 : LOOKUP (attr_str, attr_code), flags);
883 0 : return 1;
884 : }
885 :
886 : /* "For well-known attributes and for optional non-transitive attributes,
887 : * the Partial bit MUST be set to 0."
888 : */
889 11 : if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
890 : {
891 0 : if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL))
892 : {
893 0 : zlog (peer->log, LOG_ERR,
894 : "%s well-known attribute "
895 : "must NOT have the partial flag set (%x)",
896 : LOOKUP (attr_str, attr_code), flags);
897 0 : return 1;
898 : }
899 0 : if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
900 0 : && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
901 : {
902 0 : zlog (peer->log, LOG_ERR,
903 : "%s optional + transitive attribute "
904 : "must NOT have the partial flag set (%x)",
905 : LOOKUP (attr_str, attr_code), flags);
906 0 : return 1;
907 : }
908 : }
909 :
910 : /* Optional transitive attributes may go through speakers that don't
911 : * reocgnise them and set the Partial bit.
912 : */
913 11 : if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
914 6 : && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
915 6 : SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL);
916 :
917 22 : if ((flags & ~mask)
918 11 : == attr_flags_values[attr_code])
919 9 : return 0;
920 :
921 2 : bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]);
922 2 : return 1;
923 : }
924 :
925 : /* Get origin attribute of the update message. */
926 : static bgp_attr_parse_ret_t
927 0 : bgp_attr_origin (struct bgp_attr_parser_args *args)
928 : {
929 0 : struct peer *const peer = args->peer;
930 0 : struct attr *const attr = args->attr;
931 0 : const bgp_size_t length = args->length;
932 :
933 : /* If any recognized attribute has Attribute Length that conflicts
934 : with the expected length (based on the attribute type code), then
935 : the Error Subcode is set to Attribute Length Error. The Data
936 : field contains the erroneous attribute (type, length and
937 : value). */
938 0 : if (length != 1)
939 : {
940 0 : zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
941 : length);
942 0 : return bgp_attr_malformed (args,
943 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
944 0 : args->total);
945 : }
946 :
947 : /* Fetch origin attribute. */
948 0 : attr->origin = stream_getc (BGP_INPUT (peer));
949 :
950 : /* If the ORIGIN attribute has an undefined value, then the Error
951 : Subcode is set to Invalid Origin Attribute. The Data field
952 : contains the unrecognized attribute (type, length and value). */
953 0 : if ((attr->origin != BGP_ORIGIN_IGP)
954 0 : && (attr->origin != BGP_ORIGIN_EGP)
955 0 : && (attr->origin != BGP_ORIGIN_INCOMPLETE))
956 : {
957 0 : zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
958 0 : attr->origin);
959 0 : return bgp_attr_malformed (args,
960 : BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
961 0 : args->total);
962 : }
963 :
964 : /* Set oring attribute flag. */
965 0 : attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
966 :
967 0 : return 0;
968 : }
969 :
970 : /* Parse AS path information. This function is wrapper of
971 : aspath_parse. */
972 : static int
973 5 : bgp_attr_aspath (struct bgp_attr_parser_args *args)
974 : {
975 5 : struct attr *const attr = args->attr;
976 5 : struct peer *const peer = args->peer;
977 5 : const bgp_size_t length = args->length;
978 :
979 : /*
980 : * peer with AS4 => will get 4Byte ASnums
981 : * otherwise, will get 16 Bit
982 : */
983 5 : attr->aspath = aspath_parse (peer->ibuf, length,
984 5 : CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
985 :
986 : /* In case of IBGP, length will be zero. */
987 5 : if (! attr->aspath)
988 : {
989 2 : zlog (peer->log, LOG_ERR,
990 : "Malformed AS path from %s, length is %d",
991 : peer->host, length);
992 2 : return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0);
993 : }
994 :
995 : /* Set aspath attribute flag. */
996 3 : attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
997 :
998 3 : return BGP_ATTR_PARSE_PROCEED;
999 : }
1000 :
1001 : static bgp_attr_parse_ret_t
1002 3 : bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)
1003 : {
1004 : /* These checks were part of bgp_attr_aspath, but with
1005 : * as4 we should to check aspath things when
1006 : * aspath synthesizing with as4_path has already taken place.
1007 : * Otherwise we check ASPATH and use the synthesized thing, and that is
1008 : * not right.
1009 : * So do the checks later, i.e. here
1010 : */
1011 3 : struct bgp *bgp = peer->bgp;
1012 : struct aspath *aspath;
1013 :
1014 : /* Confederation sanity check. */
1015 6 : if ((peer->sort == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
1016 3 : (peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
1017 : {
1018 0 : zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
1019 0 : bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1020 : BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1021 0 : return BGP_ATTR_PARSE_ERROR;
1022 : }
1023 :
1024 : /* First AS check for EBGP. */
1025 3 : if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
1026 : {
1027 0 : if (peer->sort == BGP_PEER_EBGP
1028 0 : && ! aspath_firstas_check (attr->aspath, peer->as))
1029 : {
1030 0 : zlog (peer->log, LOG_ERR,
1031 : "%s incorrect first AS (must be %u)", peer->host, peer->as);
1032 0 : bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1033 : BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1034 0 : return BGP_ATTR_PARSE_ERROR;
1035 : }
1036 : }
1037 :
1038 : /* local-as prepend */
1039 3 : if (peer->change_local_as &&
1040 0 : ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
1041 : {
1042 0 : aspath = aspath_dup (attr->aspath);
1043 0 : aspath = aspath_add_seq (aspath, peer->change_local_as);
1044 0 : aspath_unintern (&attr->aspath);
1045 0 : attr->aspath = aspath_intern (aspath);
1046 : }
1047 :
1048 3 : return BGP_ATTR_PARSE_PROCEED;
1049 : }
1050 :
1051 : /* Parse AS4 path information. This function is another wrapper of
1052 : aspath_parse. */
1053 : static int
1054 4 : bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path)
1055 : {
1056 4 : struct peer *const peer = args->peer;
1057 4 : struct attr *const attr = args->attr;
1058 4 : const bgp_size_t length = args->length;
1059 :
1060 4 : *as4_path = aspath_parse (peer->ibuf, length, 1);
1061 :
1062 : /* In case of IBGP, length will be zero. */
1063 4 : if (!*as4_path)
1064 : {
1065 2 : zlog (peer->log, LOG_ERR,
1066 : "Malformed AS4 path from %s, length is %d",
1067 : peer->host, length);
1068 2 : return bgp_attr_malformed (args,
1069 : BGP_NOTIFY_UPDATE_MAL_AS_PATH,
1070 : 0);
1071 : }
1072 :
1073 : /* Set aspath attribute flag. */
1074 2 : if (as4_path)
1075 2 : attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
1076 :
1077 2 : return BGP_ATTR_PARSE_PROCEED;
1078 : }
1079 :
1080 : /* Nexthop attribute. */
1081 : static bgp_attr_parse_ret_t
1082 0 : bgp_attr_nexthop (struct bgp_attr_parser_args *args)
1083 : {
1084 0 : struct peer *const peer = args->peer;
1085 0 : struct attr *const attr = args->attr;
1086 0 : const bgp_size_t length = args->length;
1087 :
1088 : in_addr_t nexthop_h, nexthop_n;
1089 :
1090 : /* Check nexthop attribute length. */
1091 0 : if (length != 4)
1092 : {
1093 0 : zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
1094 : length);
1095 :
1096 0 : return bgp_attr_malformed (args,
1097 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1098 0 : args->total);
1099 : }
1100 :
1101 : /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1102 : attribute must result in a NOTIFICATION message (this is implemented below).
1103 : At the same time, semantically incorrect NEXT_HOP is more likely to be just
1104 : logged locally (this is implemented somewhere else). The UPDATE message
1105 : gets ignored in any of these cases. */
1106 0 : nexthop_n = stream_get_ipv4 (peer->ibuf);
1107 0 : nexthop_h = ntohl (nexthop_n);
1108 0 : if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
1109 : {
1110 : char buf[INET_ADDRSTRLEN];
1111 0 : inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
1112 0 : zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
1113 0 : return bgp_attr_malformed (args,
1114 : BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
1115 0 : args->total);
1116 : }
1117 :
1118 0 : attr->nexthop.s_addr = nexthop_n;
1119 0 : attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1120 :
1121 0 : return BGP_ATTR_PARSE_PROCEED;
1122 : }
1123 :
1124 : /* MED atrribute. */
1125 : static bgp_attr_parse_ret_t
1126 0 : bgp_attr_med (struct bgp_attr_parser_args *args)
1127 : {
1128 0 : struct peer *const peer = args->peer;
1129 0 : struct attr *const attr = args->attr;
1130 0 : const bgp_size_t length = args->length;
1131 :
1132 : /* Length check. */
1133 0 : if (length != 4)
1134 : {
1135 0 : zlog (peer->log, LOG_ERR,
1136 : "MED attribute length isn't four [%d]", length);
1137 :
1138 0 : return bgp_attr_malformed (args,
1139 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1140 0 : args->total);
1141 : }
1142 :
1143 0 : attr->med = stream_getl (peer->ibuf);
1144 :
1145 0 : attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1146 :
1147 0 : return BGP_ATTR_PARSE_PROCEED;
1148 : }
1149 :
1150 : /* Local preference attribute. */
1151 : static bgp_attr_parse_ret_t
1152 0 : bgp_attr_local_pref (struct bgp_attr_parser_args *args)
1153 : {
1154 0 : struct peer *const peer = args->peer;
1155 0 : struct attr *const attr = args->attr;
1156 0 : const bgp_size_t length = args->length;
1157 :
1158 : /* Length check. */
1159 0 : if (length != 4)
1160 : {
1161 0 : zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]",
1162 : length);
1163 0 : return bgp_attr_malformed (args,
1164 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1165 0 : args->total);
1166 : }
1167 :
1168 : /* If it is contained in an UPDATE message that is received from an
1169 : external peer, then this attribute MUST be ignored by the
1170 : receiving speaker. */
1171 0 : if (peer->sort == BGP_PEER_EBGP)
1172 : {
1173 0 : stream_forward_getp (peer->ibuf, length);
1174 0 : return BGP_ATTR_PARSE_PROCEED;
1175 : }
1176 :
1177 0 : attr->local_pref = stream_getl (peer->ibuf);
1178 :
1179 : /* Set atomic aggregate flag. */
1180 0 : attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1181 :
1182 0 : return BGP_ATTR_PARSE_PROCEED;
1183 : }
1184 :
1185 : /* Atomic aggregate. */
1186 : static int
1187 0 : bgp_attr_atomic (struct bgp_attr_parser_args *args)
1188 : {
1189 0 : struct peer *const peer = args->peer;
1190 0 : struct attr *const attr = args->attr;
1191 0 : const bgp_size_t length = args->length;
1192 :
1193 : /* Length check. */
1194 0 : if (length != 0)
1195 : {
1196 0 : zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1197 : length);
1198 0 : return bgp_attr_malformed (args,
1199 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1200 0 : args->total);
1201 : }
1202 :
1203 : /* Set atomic aggregate flag. */
1204 0 : attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1205 :
1206 0 : return BGP_ATTR_PARSE_PROCEED;
1207 : }
1208 :
1209 : /* Aggregator attribute */
1210 : static int
1211 0 : bgp_attr_aggregator (struct bgp_attr_parser_args *args)
1212 : {
1213 0 : struct peer *const peer = args->peer;
1214 0 : struct attr *const attr = args->attr;
1215 0 : const bgp_size_t length = args->length;
1216 :
1217 0 : int wantedlen = 6;
1218 0 : struct attr_extra *attre = bgp_attr_extra_get (attr);
1219 :
1220 : /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1221 0 : if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
1222 0 : wantedlen = 8;
1223 :
1224 0 : if (length != wantedlen)
1225 : {
1226 0 : zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]",
1227 : wantedlen, length);
1228 0 : return bgp_attr_malformed (args,
1229 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1230 0 : args->total);
1231 : }
1232 :
1233 0 : if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1234 0 : attre->aggregator_as = stream_getl (peer->ibuf);
1235 : else
1236 0 : attre->aggregator_as = stream_getw (peer->ibuf);
1237 0 : attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
1238 :
1239 : /* Set atomic aggregate flag. */
1240 0 : attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1241 :
1242 0 : return BGP_ATTR_PARSE_PROCEED;
1243 : }
1244 :
1245 : /* New Aggregator attribute */
1246 : static bgp_attr_parse_ret_t
1247 0 : bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args,
1248 : as_t *as4_aggregator_as,
1249 : struct in_addr *as4_aggregator_addr)
1250 : {
1251 0 : struct peer *const peer = args->peer;
1252 0 : struct attr *const attr = args->attr;
1253 0 : const bgp_size_t length = args->length;
1254 :
1255 0 : if (length != 8)
1256 : {
1257 0 : zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]",
1258 : length);
1259 0 : return bgp_attr_malformed (args,
1260 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1261 : 0);
1262 : }
1263 :
1264 0 : *as4_aggregator_as = stream_getl (peer->ibuf);
1265 0 : as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1266 :
1267 0 : attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1268 :
1269 0 : return BGP_ATTR_PARSE_PROCEED;
1270 : }
1271 :
1272 : /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1273 : */
1274 : static bgp_attr_parse_ret_t
1275 4 : bgp_attr_munge_as4_attrs (struct peer *const peer,
1276 : struct attr *const attr,
1277 : struct aspath *as4_path, as_t as4_aggregator,
1278 : struct in_addr *as4_aggregator_addr)
1279 : {
1280 4 : int ignore_as4_path = 0;
1281 : struct aspath *newpath;
1282 4 : struct attr_extra *attre = attr->extra;
1283 :
1284 4 : if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
1285 : {
1286 : /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1287 : * if given.
1288 : * It is worth a warning though, because the peer really
1289 : * should not send them
1290 : */
1291 1 : if (BGP_DEBUG(as4, AS4))
1292 : {
1293 0 : if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1294 0 : zlog_debug ("[AS4] %s %s AS4_PATH",
1295 : peer->host, "AS4 capable peer, yet it sent");
1296 :
1297 0 : if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1298 0 : zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1299 : peer->host, "AS4 capable peer, yet it sent");
1300 : }
1301 :
1302 1 : return BGP_ATTR_PARSE_PROCEED;
1303 : }
1304 :
1305 : /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1306 : * because that may override AS4_PATH
1307 : */
1308 3 : if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1309 : {
1310 0 : if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1311 : {
1312 0 : assert (attre);
1313 :
1314 : /* received both.
1315 : * if the as_number in aggregator is not AS_TRANS,
1316 : * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1317 : * and the Aggregator shall be taken as
1318 : * info on the aggregating node, and the AS_PATH
1319 : * shall be taken as the AS_PATH
1320 : * otherwise
1321 : * the Aggregator shall be ignored and the
1322 : * AS4_AGGREGATOR shall be taken as the
1323 : * Aggregating node and the AS_PATH is to be
1324 : * constructed "as in all other cases"
1325 : */
1326 0 : if (attre->aggregator_as != BGP_AS_TRANS)
1327 : {
1328 : /* ignore */
1329 0 : if ( BGP_DEBUG(as4, AS4))
1330 0 : zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1331 : " send AGGREGATOR != AS_TRANS and"
1332 : " AS4_AGGREGATOR, so ignore"
1333 : " AS4_AGGREGATOR and AS4_PATH", peer->host);
1334 0 : ignore_as4_path = 1;
1335 : }
1336 : else
1337 : {
1338 : /* "New_aggregator shall be taken as aggregator" */
1339 0 : attre->aggregator_as = as4_aggregator;
1340 0 : attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1341 : }
1342 : }
1343 : else
1344 : {
1345 : /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1346 : * That is bogus - but reading the conditions
1347 : * we have to handle AS4_AGGREGATOR as if it were
1348 : * AGGREGATOR in that case
1349 : */
1350 0 : if ( BGP_DEBUG(as4, AS4))
1351 0 : zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1352 : " AS4_AGGREGATOR but no AGGREGATOR, will take"
1353 : " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
1354 0 : (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
1355 : /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1356 0 : attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1357 : }
1358 : }
1359 :
1360 : /* need to reconcile NEW_AS_PATH and AS_PATH */
1361 3 : if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
1362 : {
1363 2 : if (!attr->aspath)
1364 1 : return BGP_ATTR_PARSE_PROCEED;
1365 :
1366 1 : newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1367 1 : aspath_unintern (&attr->aspath);
1368 1 : attr->aspath = aspath_intern (newpath);
1369 : }
1370 2 : return BGP_ATTR_PARSE_PROCEED;
1371 : }
1372 :
1373 : /* Community attribute. */
1374 : static bgp_attr_parse_ret_t
1375 0 : bgp_attr_community (struct bgp_attr_parser_args *args)
1376 : {
1377 0 : struct peer *const peer = args->peer;
1378 0 : struct attr *const attr = args->attr;
1379 0 : const bgp_size_t length = args->length;
1380 :
1381 0 : if (length == 0)
1382 : {
1383 0 : attr->community = NULL;
1384 0 : return BGP_ATTR_PARSE_PROCEED;
1385 : }
1386 :
1387 0 : attr->community =
1388 0 : community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1389 :
1390 : /* XXX: fix community_parse to use stream API and remove this */
1391 0 : stream_forward_getp (peer->ibuf, length);
1392 :
1393 0 : if (!attr->community)
1394 0 : return bgp_attr_malformed (args,
1395 : BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1396 0 : args->total);
1397 :
1398 0 : attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1399 :
1400 0 : return BGP_ATTR_PARSE_PROCEED;
1401 : }
1402 :
1403 : /* Originator ID attribute. */
1404 : static bgp_attr_parse_ret_t
1405 0 : bgp_attr_originator_id (struct bgp_attr_parser_args *args)
1406 : {
1407 0 : struct peer *const peer = args->peer;
1408 0 : struct attr *const attr = args->attr;
1409 0 : const bgp_size_t length = args->length;
1410 :
1411 : /* Length check. */
1412 0 : if (length != 4)
1413 : {
1414 0 : zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1415 :
1416 0 : return bgp_attr_malformed (args,
1417 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1418 0 : args->total);
1419 : }
1420 :
1421 0 : (bgp_attr_extra_get (attr))->originator_id.s_addr
1422 0 : = stream_get_ipv4 (peer->ibuf);
1423 :
1424 0 : attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1425 :
1426 0 : return BGP_ATTR_PARSE_PROCEED;
1427 : }
1428 :
1429 : /* Cluster list attribute. */
1430 : static bgp_attr_parse_ret_t
1431 0 : bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
1432 : {
1433 0 : struct peer *const peer = args->peer;
1434 0 : struct attr *const attr = args->attr;
1435 0 : const bgp_size_t length = args->length;
1436 :
1437 : /* Check length. */
1438 0 : if (length % 4)
1439 : {
1440 0 : zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1441 :
1442 0 : return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1443 0 : args->total);
1444 : }
1445 :
1446 0 : (bgp_attr_extra_get (attr))->cluster
1447 0 : = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
1448 :
1449 : /* XXX: Fix cluster_parse to use stream API and then remove this */
1450 0 : stream_forward_getp (peer->ibuf, length);
1451 :
1452 0 : attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1453 :
1454 0 : return BGP_ATTR_PARSE_PROCEED;
1455 : }
1456 :
1457 : /* Multiprotocol reachability information parse. */
1458 : int
1459 14 : bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
1460 : struct bgp_nlri *mp_update)
1461 : {
1462 : afi_t afi;
1463 : safi_t safi;
1464 : bgp_size_t nlri_len;
1465 : size_t start;
1466 : int ret;
1467 : struct stream *s;
1468 14 : struct peer *const peer = args->peer;
1469 14 : struct attr *const attr = args->attr;
1470 14 : const bgp_size_t length = args->length;
1471 14 : struct attr_extra *attre = bgp_attr_extra_get(attr);
1472 :
1473 : /* Set end of packet. */
1474 14 : s = BGP_INPUT(peer);
1475 14 : start = stream_get_getp(s);
1476 :
1477 : /* safe to read statically sized header? */
1478 : #define BGP_MP_REACH_MIN_SIZE 5
1479 : #define LEN_LEFT (length - (stream_get_getp(s) - start))
1480 14 : if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
1481 : {
1482 0 : zlog_info ("%s: %s sent invalid length, %lu",
1483 : __func__, peer->host, (unsigned long)length);
1484 0 : return BGP_ATTR_PARSE_ERROR;
1485 : }
1486 :
1487 : /* Load AFI, SAFI. */
1488 14 : afi = stream_getw (s);
1489 14 : safi = stream_getc (s);
1490 :
1491 : /* Get nexthop length. */
1492 14 : attre->mp_nexthop_len = stream_getc (s);
1493 :
1494 14 : if (LEN_LEFT < attre->mp_nexthop_len)
1495 : {
1496 2 : zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1497 2 : __func__, peer->host, attre->mp_nexthop_len);
1498 2 : return BGP_ATTR_PARSE_ERROR;
1499 : }
1500 :
1501 : /* Nexthop length check. */
1502 12 : switch (attre->mp_nexthop_len)
1503 : {
1504 : case 4:
1505 3 : stream_get (&attre->mp_nexthop_global_in, s, 4);
1506 : /* Probably needed for RFC 2283 */
1507 3 : if (attr->nexthop.s_addr == 0)
1508 3 : memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
1509 3 : break;
1510 : case 12:
1511 1 : stream_getl (s); /* RD high */
1512 1 : stream_getl (s); /* RD low */
1513 1 : stream_get (&attre->mp_nexthop_global_in, s, 4);
1514 1 : break;
1515 : #ifdef HAVE_IPV6
1516 : case 16:
1517 4 : stream_get (&attre->mp_nexthop_global, s, 16);
1518 4 : break;
1519 : case 32:
1520 3 : stream_get (&attre->mp_nexthop_global, s, 16);
1521 3 : stream_get (&attre->mp_nexthop_local, s, 16);
1522 3 : if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
1523 : {
1524 : char buf1[INET6_ADDRSTRLEN];
1525 : char buf2[INET6_ADDRSTRLEN];
1526 :
1527 0 : if (BGP_DEBUG (update, UPDATE_IN))
1528 0 : zlog_debug ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host,
1529 0 : inet_ntop (AF_INET6, &attre->mp_nexthop_global,
1530 : buf1, INET6_ADDRSTRLEN),
1531 0 : inet_ntop (AF_INET6, &attre->mp_nexthop_local,
1532 : buf2, INET6_ADDRSTRLEN));
1533 :
1534 0 : attre->mp_nexthop_len = 16;
1535 : }
1536 3 : break;
1537 : #endif /* HAVE_IPV6 */
1538 : default:
1539 1 : zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1540 1 : __func__, peer->host, attre->mp_nexthop_len);
1541 1 : return BGP_ATTR_PARSE_ERROR;
1542 : }
1543 :
1544 11 : if (!LEN_LEFT)
1545 : {
1546 0 : zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1547 : __func__, peer->host);
1548 0 : return BGP_ATTR_PARSE_ERROR;
1549 : }
1550 :
1551 : {
1552 : u_char val;
1553 11 : if ((val = stream_getc (s)))
1554 2 : zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1555 : peer->host, val);
1556 : }
1557 :
1558 : /* must have nrli_len, what is left of the attribute */
1559 11 : nlri_len = LEN_LEFT;
1560 11 : if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
1561 : {
1562 1 : zlog_info ("%s: (%s) Failed to read NLRI",
1563 : __func__, peer->host);
1564 1 : return BGP_ATTR_PARSE_ERROR;
1565 : }
1566 :
1567 10 : if (safi != SAFI_MPLS_LABELED_VPN)
1568 : {
1569 9 : ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
1570 9 : if (ret < 0)
1571 : {
1572 4 : zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1573 : __func__, peer->host);
1574 4 : return BGP_ATTR_PARSE_ERROR;
1575 : }
1576 : }
1577 :
1578 6 : mp_update->afi = afi;
1579 6 : mp_update->safi = safi;
1580 6 : mp_update->nlri = stream_pnt (s);
1581 6 : mp_update->length = nlri_len;
1582 :
1583 6 : stream_forward_getp (s, nlri_len);
1584 :
1585 6 : return BGP_ATTR_PARSE_PROCEED;
1586 : #undef LEN_LEFT
1587 : }
1588 :
1589 : /* Multiprotocol unreachable parse */
1590 : int
1591 7 : bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
1592 : struct bgp_nlri *mp_withdraw)
1593 : {
1594 : struct stream *s;
1595 : afi_t afi;
1596 : safi_t safi;
1597 : u_int16_t withdraw_len;
1598 : int ret;
1599 7 : struct peer *const peer = args->peer;
1600 7 : const bgp_size_t length = args->length;
1601 :
1602 7 : s = peer->ibuf;
1603 :
1604 : #define BGP_MP_UNREACH_MIN_SIZE 3
1605 7 : if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1606 0 : return BGP_ATTR_PARSE_ERROR;
1607 :
1608 7 : afi = stream_getw (s);
1609 7 : safi = stream_getc (s);
1610 :
1611 7 : withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
1612 :
1613 7 : if (safi != SAFI_MPLS_LABELED_VPN)
1614 : {
1615 6 : ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1616 6 : if (ret < 0)
1617 2 : return BGP_ATTR_PARSE_ERROR;
1618 : }
1619 :
1620 5 : mp_withdraw->afi = afi;
1621 5 : mp_withdraw->safi = safi;
1622 5 : mp_withdraw->nlri = stream_pnt (s);
1623 5 : mp_withdraw->length = withdraw_len;
1624 :
1625 5 : stream_forward_getp (s, withdraw_len);
1626 :
1627 5 : return BGP_ATTR_PARSE_PROCEED;
1628 : }
1629 :
1630 : /* Extended Community attribute. */
1631 : static bgp_attr_parse_ret_t
1632 0 : bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
1633 : {
1634 0 : struct peer *const peer = args->peer;
1635 0 : struct attr *const attr = args->attr;
1636 0 : const bgp_size_t length = args->length;
1637 :
1638 0 : if (length == 0)
1639 : {
1640 0 : if (attr->extra)
1641 0 : attr->extra->ecommunity = NULL;
1642 : /* Empty extcomm doesn't seem to be invalid per se */
1643 0 : return BGP_ATTR_PARSE_PROCEED;
1644 : }
1645 :
1646 0 : (bgp_attr_extra_get (attr))->ecommunity =
1647 0 : ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1648 : /* XXX: fix ecommunity_parse to use stream API */
1649 0 : stream_forward_getp (peer->ibuf, length);
1650 :
1651 0 : if (!attr->extra->ecommunity)
1652 0 : return bgp_attr_malformed (args,
1653 : BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1654 0 : args->total);
1655 :
1656 0 : attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1657 :
1658 0 : return BGP_ATTR_PARSE_PROCEED;
1659 : }
1660 :
1661 : /* BGP unknown attribute treatment. */
1662 : static bgp_attr_parse_ret_t
1663 0 : bgp_attr_unknown (struct bgp_attr_parser_args *args)
1664 : {
1665 0 : bgp_size_t total = args->total;
1666 : struct transit *transit;
1667 : struct attr_extra *attre;
1668 0 : struct peer *const peer = args->peer;
1669 0 : struct attr *const attr = args->attr;
1670 0 : u_char *const startp = args->startp;
1671 0 : const u_char type = args->type;
1672 0 : const u_char flag = args->flags;
1673 0 : const bgp_size_t length = args->length;
1674 :
1675 :
1676 0 : if (BGP_DEBUG (normal, NORMAL))
1677 0 : zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1678 : peer->host, type, length);
1679 :
1680 0 : if (BGP_DEBUG (events, EVENTS))
1681 0 : zlog (peer->log, LOG_DEBUG,
1682 : "Unknown attribute type %d length %d is received", type, length);
1683 :
1684 : /* Forward read pointer of input stream. */
1685 0 : stream_forward_getp (peer->ibuf, length);
1686 :
1687 : /* If any of the mandatory well-known attributes are not recognized,
1688 : then the Error Subcode is set to Unrecognized Well-known
1689 : Attribute. The Data field contains the unrecognized attribute
1690 : (type, length and value). */
1691 0 : if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1692 : {
1693 0 : return bgp_attr_malformed (args,
1694 : BGP_NOTIFY_UPDATE_UNREC_ATTR,
1695 0 : args->total);
1696 : }
1697 :
1698 : /* Unrecognized non-transitive optional attributes must be quietly
1699 : ignored and not passed along to other BGP peers. */
1700 0 : if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1701 0 : return BGP_ATTR_PARSE_PROCEED;
1702 :
1703 : /* If a path with recognized transitive optional attribute is
1704 : accepted and passed along to other BGP peers and the Partial bit
1705 : in the Attribute Flags octet is set to 1 by some previous AS, it
1706 : is not set back to 0 by the current AS. */
1707 0 : SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1708 :
1709 : /* Store transitive attribute to the end of attr->transit. */
1710 0 : if (! ((attre = bgp_attr_extra_get(attr))->transit) )
1711 0 : attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
1712 :
1713 0 : transit = attre->transit;
1714 :
1715 0 : if (transit->val)
1716 0 : transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1717 : transit->length + total);
1718 : else
1719 0 : transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1720 :
1721 0 : memcpy (transit->val + transit->length, startp, total);
1722 0 : transit->length += total;
1723 :
1724 0 : return BGP_ATTR_PARSE_PROCEED;
1725 : }
1726 :
1727 : /* Read attribute of update packet. This function is called from
1728 : bgp_update_receive() in bgp_packet.c. */
1729 : bgp_attr_parse_ret_t
1730 13 : bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1731 : struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1732 : {
1733 : int ret;
1734 13 : u_char flag = 0;
1735 13 : u_char type = 0;
1736 : bgp_size_t length;
1737 : u_char *startp, *endp;
1738 : u_char *attr_endp;
1739 : u_char seen[BGP_ATTR_BITMAP_SIZE];
1740 : /* we need the as4_path only until we have synthesized the as_path with it */
1741 : /* same goes for as4_aggregator */
1742 13 : struct aspath *as4_path = NULL;
1743 13 : as_t as4_aggregator = 0;
1744 13 : struct in_addr as4_aggregator_addr = { 0 };
1745 :
1746 : /* Initialize bitmap. */
1747 13 : memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1748 :
1749 : /* End pointer of BGP attribute. */
1750 13 : endp = BGP_INPUT_PNT (peer) + size;
1751 :
1752 : /* Get attributes to the end of attribute length. */
1753 31 : while (BGP_INPUT_PNT (peer) < endp)
1754 : {
1755 : /* Check remaining length check.*/
1756 14 : if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1757 : {
1758 : /* XXX warning: long int format, int arg (arg 5) */
1759 0 : zlog (peer->log, LOG_WARNING,
1760 : "%s: error BGP attribute length %lu is smaller than min len",
1761 : peer->host,
1762 0 : (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1763 :
1764 0 : bgp_notify_send (peer,
1765 : BGP_NOTIFY_UPDATE_ERR,
1766 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1767 9 : return BGP_ATTR_PARSE_ERROR;
1768 : }
1769 :
1770 : /* Fetch attribute flag and type. */
1771 14 : startp = BGP_INPUT_PNT (peer);
1772 : /* "The lower-order four bits of the Attribute Flags octet are
1773 : unused. They MUST be zero when sent and MUST be ignored when
1774 : received." */
1775 14 : flag = 0xF0 & stream_getc (BGP_INPUT (peer));
1776 14 : type = stream_getc (BGP_INPUT (peer));
1777 :
1778 : /* Check whether Extended-Length applies and is in bounds */
1779 14 : if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1780 0 : && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1781 : {
1782 0 : zlog (peer->log, LOG_WARNING,
1783 : "%s: Extended length set, but just %lu bytes of attr header",
1784 : peer->host,
1785 0 : (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1786 :
1787 0 : bgp_notify_send (peer,
1788 : BGP_NOTIFY_UPDATE_ERR,
1789 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1790 0 : return BGP_ATTR_PARSE_ERROR;
1791 : }
1792 :
1793 : /* Check extended attribue length bit. */
1794 14 : if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1795 0 : length = stream_getw (BGP_INPUT (peer));
1796 : else
1797 14 : length = stream_getc (BGP_INPUT (peer));
1798 :
1799 : /* If any attribute appears more than once in the UPDATE
1800 : message, then the Error Subcode is set to Malformed Attribute
1801 : List. */
1802 :
1803 14 : if (CHECK_BITMAP (seen, type))
1804 : {
1805 0 : zlog (peer->log, LOG_WARNING,
1806 : "%s: error BGP attribute type %d appears twice in a message",
1807 : peer->host, type);
1808 :
1809 0 : bgp_notify_send (peer,
1810 : BGP_NOTIFY_UPDATE_ERR,
1811 : BGP_NOTIFY_UPDATE_MAL_ATTR);
1812 0 : return BGP_ATTR_PARSE_ERROR;
1813 : }
1814 :
1815 : /* Set type to bitmap to check duplicate attribute. `type' is
1816 : unsigned char so it never overflow bitmap range. */
1817 :
1818 14 : SET_BITMAP (seen, type);
1819 :
1820 : /* Overflow check. */
1821 14 : attr_endp = BGP_INPUT_PNT (peer) + length;
1822 :
1823 14 : if (attr_endp > endp)
1824 : {
1825 3 : zlog (peer->log, LOG_WARNING,
1826 : "%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p", peer->host, type, length, size, attr_endp, endp);
1827 3 : bgp_notify_send (peer,
1828 : BGP_NOTIFY_UPDATE_ERR,
1829 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1830 3 : return BGP_ATTR_PARSE_ERROR;
1831 : }
1832 :
1833 22 : struct bgp_attr_parser_args attr_args = {
1834 : .peer = peer,
1835 : .length = length,
1836 : .attr = attr,
1837 : .type = type,
1838 : .flags = flag,
1839 : .startp = startp,
1840 11 : .total = attr_endp - startp,
1841 : };
1842 :
1843 :
1844 : /* If any recognized attribute has Attribute Flags that conflict
1845 : with the Attribute Type Code, then the Error Subcode is set to
1846 : Attribute Flags Error. The Data field contains the erroneous
1847 : attribute (type, length and value). */
1848 11 : if (bgp_attr_flag_invalid (&attr_args))
1849 : {
1850 : bgp_attr_parse_ret_t ret;
1851 2 : ret = bgp_attr_malformed (&attr_args,
1852 : BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1853 2 : attr_args.total);
1854 2 : if (ret == BGP_ATTR_PARSE_PROCEED)
1855 0 : continue;
1856 2 : return ret;
1857 : }
1858 :
1859 : /* OK check attribute and store it's value. */
1860 9 : switch (type)
1861 : {
1862 : case BGP_ATTR_ORIGIN:
1863 0 : ret = bgp_attr_origin (&attr_args);
1864 0 : break;
1865 : case BGP_ATTR_AS_PATH:
1866 5 : ret = bgp_attr_aspath (&attr_args);
1867 5 : break;
1868 : case BGP_ATTR_AS4_PATH:
1869 4 : ret = bgp_attr_as4_path (&attr_args, &as4_path);
1870 4 : break;
1871 : case BGP_ATTR_NEXT_HOP:
1872 0 : ret = bgp_attr_nexthop (&attr_args);
1873 0 : break;
1874 : case BGP_ATTR_MULTI_EXIT_DISC:
1875 0 : ret = bgp_attr_med (&attr_args);
1876 0 : break;
1877 : case BGP_ATTR_LOCAL_PREF:
1878 0 : ret = bgp_attr_local_pref (&attr_args);
1879 0 : break;
1880 : case BGP_ATTR_ATOMIC_AGGREGATE:
1881 0 : ret = bgp_attr_atomic (&attr_args);
1882 0 : break;
1883 : case BGP_ATTR_AGGREGATOR:
1884 0 : ret = bgp_attr_aggregator (&attr_args);
1885 0 : break;
1886 : case BGP_ATTR_AS4_AGGREGATOR:
1887 0 : ret = bgp_attr_as4_aggregator (&attr_args,
1888 : &as4_aggregator,
1889 : &as4_aggregator_addr);
1890 0 : break;
1891 : case BGP_ATTR_COMMUNITIES:
1892 0 : ret = bgp_attr_community (&attr_args);
1893 0 : break;
1894 : case BGP_ATTR_ORIGINATOR_ID:
1895 0 : ret = bgp_attr_originator_id (&attr_args);
1896 0 : break;
1897 : case BGP_ATTR_CLUSTER_LIST:
1898 0 : ret = bgp_attr_cluster_list (&attr_args);
1899 0 : break;
1900 : case BGP_ATTR_MP_REACH_NLRI:
1901 0 : ret = bgp_mp_reach_parse (&attr_args, mp_update);
1902 0 : break;
1903 : case BGP_ATTR_MP_UNREACH_NLRI:
1904 0 : ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw);
1905 0 : break;
1906 : case BGP_ATTR_EXT_COMMUNITIES:
1907 0 : ret = bgp_attr_ext_communities (&attr_args);
1908 0 : break;
1909 : default:
1910 0 : ret = bgp_attr_unknown (&attr_args);
1911 0 : break;
1912 : }
1913 :
1914 : /* If hard error occured immediately return to the caller. */
1915 9 : if (ret == BGP_ATTR_PARSE_ERROR)
1916 : {
1917 4 : zlog (peer->log, LOG_WARNING,
1918 : "%s: Attribute %s, parse error",
1919 : peer->host,
1920 : LOOKUP (attr_str, type));
1921 4 : bgp_notify_send (peer,
1922 : BGP_NOTIFY_UPDATE_ERR,
1923 : BGP_NOTIFY_UPDATE_MAL_ATTR);
1924 4 : if (as4_path)
1925 0 : aspath_unintern (&as4_path);
1926 4 : return ret;
1927 : }
1928 5 : if (ret == BGP_ATTR_PARSE_WITHDRAW)
1929 : {
1930 :
1931 0 : zlog (peer->log, LOG_WARNING,
1932 : "%s: Attribute %s, parse error - treating as withdrawal",
1933 : peer->host,
1934 : LOOKUP (attr_str, type));
1935 0 : if (as4_path)
1936 0 : aspath_unintern (&as4_path);
1937 0 : return ret;
1938 : }
1939 :
1940 : /* Check the fetched length. */
1941 5 : if (BGP_INPUT_PNT (peer) != attr_endp)
1942 : {
1943 0 : zlog (peer->log, LOG_WARNING,
1944 : "%s: BGP attribute %s, fetch error",
1945 : peer->host, LOOKUP (attr_str, type));
1946 0 : bgp_notify_send (peer,
1947 : BGP_NOTIFY_UPDATE_ERR,
1948 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1949 0 : if (as4_path)
1950 0 : aspath_unintern (&as4_path);
1951 0 : return BGP_ATTR_PARSE_ERROR;
1952 : }
1953 : }
1954 :
1955 : /* Check final read pointer is same as end pointer. */
1956 4 : if (BGP_INPUT_PNT (peer) != endp)
1957 : {
1958 0 : zlog (peer->log, LOG_WARNING,
1959 : "%s: BGP attribute %s, length mismatch",
1960 : peer->host, LOOKUP (attr_str, type));
1961 0 : bgp_notify_send (peer,
1962 : BGP_NOTIFY_UPDATE_ERR,
1963 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1964 0 : if (as4_path)
1965 0 : aspath_unintern (&as4_path);
1966 0 : return BGP_ATTR_PARSE_ERROR;
1967 : }
1968 :
1969 : /*
1970 : * At this place we can see whether we got AS4_PATH and/or
1971 : * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1972 : * We can not do this before we've read all attributes because
1973 : * the as4 handling does not say whether AS4_PATH has to be sent
1974 : * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1975 : * in relationship to AGGREGATOR.
1976 : * So, to be defensive, we are not relying on any order and read
1977 : * all attributes first, including these 32bit ones, and now,
1978 : * afterwards, we look what and if something is to be done for as4.
1979 : */
1980 4 : if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1981 : as4_aggregator, &as4_aggregator_addr))
1982 : {
1983 0 : if (as4_path)
1984 0 : aspath_unintern (&as4_path);
1985 0 : return BGP_ATTR_PARSE_ERROR;
1986 : }
1987 :
1988 : /* At this stage, we have done all fiddling with as4, and the
1989 : * resulting info is in attr->aggregator resp. attr->aspath
1990 : * so we can chuck as4_aggregator and as4_path alltogether in
1991 : * order to save memory
1992 : */
1993 4 : if (as4_path)
1994 : {
1995 2 : aspath_unintern (&as4_path); /* unintern - it is in the hash */
1996 : /* The flag that we got this is still there, but that does not
1997 : * do any trouble
1998 : */
1999 : }
2000 : /*
2001 : * The "rest" of the code does nothing with as4_aggregator.
2002 : * there is no memory attached specifically which is not part
2003 : * of the attr.
2004 : * so ignoring just means do nothing.
2005 : */
2006 : /*
2007 : * Finally do the checks on the aspath we did not do yet
2008 : * because we waited for a potentially synthesized aspath.
2009 : */
2010 4 : if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
2011 : {
2012 3 : ret = bgp_attr_aspath_check (peer, attr);
2013 3 : if (ret != BGP_ATTR_PARSE_PROCEED)
2014 0 : return ret;
2015 : }
2016 :
2017 : /* Finally intern unknown attribute. */
2018 4 : if (attr->extra && attr->extra->transit)
2019 0 : attr->extra->transit = transit_intern (attr->extra->transit);
2020 :
2021 4 : return BGP_ATTR_PARSE_PROCEED;
2022 : }
2023 :
2024 : /* Well-known attribute check. */
2025 : int
2026 0 : bgp_attr_check (struct peer *peer, struct attr *attr)
2027 : {
2028 0 : u_char type = 0;
2029 :
2030 0 : if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
2031 0 : type = BGP_ATTR_ORIGIN;
2032 :
2033 0 : if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
2034 0 : type = BGP_ATTR_AS_PATH;
2035 :
2036 0 : if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2037 0 : type = BGP_ATTR_NEXT_HOP;
2038 :
2039 0 : if (peer->sort == BGP_PEER_IBGP
2040 0 : && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2041 0 : type = BGP_ATTR_LOCAL_PREF;
2042 :
2043 0 : if (type)
2044 : {
2045 0 : zlog (peer->log, LOG_WARNING,
2046 : "%s Missing well-known attribute %d.",
2047 : peer->host, type);
2048 0 : bgp_notify_send_with_data (peer,
2049 : BGP_NOTIFY_UPDATE_ERR,
2050 : BGP_NOTIFY_UPDATE_MISS_ATTR,
2051 : &type, 1);
2052 0 : return BGP_ATTR_PARSE_ERROR;
2053 : }
2054 0 : return BGP_ATTR_PARSE_PROCEED;
2055 : }
2056 :
2057 : int stream_put_prefix (struct stream *, struct prefix *);
2058 :
2059 : /* Make attribute packet. */
2060 : bgp_size_t
2061 0 : bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2062 : struct stream *s, struct attr *attr, struct prefix *p,
2063 : afi_t afi, safi_t safi, struct peer *from,
2064 : struct prefix_rd *prd, u_char *tag)
2065 : {
2066 : size_t cp;
2067 : size_t aspath_sizep;
2068 : struct aspath *aspath;
2069 0 : int send_as4_path = 0;
2070 0 : int send_as4_aggregator = 0;
2071 0 : int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
2072 :
2073 0 : if (! bgp)
2074 0 : bgp = bgp_get_default ();
2075 :
2076 : /* Remember current pointer. */
2077 0 : cp = stream_get_endp (s);
2078 :
2079 : /* Origin attribute. */
2080 0 : stream_putc (s, BGP_ATTR_FLAG_TRANS);
2081 0 : stream_putc (s, BGP_ATTR_ORIGIN);
2082 0 : stream_putc (s, 1);
2083 0 : stream_putc (s, attr->origin);
2084 :
2085 : /* AS path attribute. */
2086 :
2087 : /* If remote-peer is EBGP */
2088 0 : if (peer->sort == BGP_PEER_EBGP
2089 0 : && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
2090 0 : || attr->aspath->segments == NULL)
2091 0 : && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
2092 : {
2093 0 : aspath = aspath_dup (attr->aspath);
2094 :
2095 0 : if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2096 : {
2097 : /* Strip the confed info, and then stuff our path CONFED_ID
2098 : on the front */
2099 0 : aspath = aspath_delete_confed_seq (aspath);
2100 0 : aspath = aspath_add_seq (aspath, bgp->confed_id);
2101 : }
2102 : else
2103 : {
2104 0 : if (peer->change_local_as) {
2105 : /* If replace-as is specified, we only use the change_local_as when
2106 : advertising routes. */
2107 0 : if( ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ) {
2108 0 : aspath = aspath_add_seq (aspath, peer->local_as);
2109 : }
2110 0 : aspath = aspath_add_seq (aspath, peer->change_local_as);
2111 : } else {
2112 0 : aspath = aspath_add_seq (aspath, peer->local_as);
2113 : }
2114 : }
2115 : }
2116 0 : else if (peer->sort == BGP_PEER_CONFED)
2117 : {
2118 : /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2119 0 : aspath = aspath_dup (attr->aspath);
2120 0 : aspath = aspath_add_confed_seq (aspath, peer->local_as);
2121 : }
2122 : else
2123 0 : aspath = attr->aspath;
2124 :
2125 : /* If peer is not AS4 capable, then:
2126 : * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2127 : * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2128 : * types are in it (i.e. exclude them if they are there)
2129 : * AND do this only if there is at least one asnum > 65535 in the path!
2130 : * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2131 : * all ASnums > 65535 to BGP_AS_TRANS
2132 : */
2133 :
2134 0 : stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2135 0 : stream_putc (s, BGP_ATTR_AS_PATH);
2136 0 : aspath_sizep = stream_get_endp (s);
2137 0 : stream_putw (s, 0);
2138 0 : stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2139 :
2140 : /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2141 : * in the path
2142 : */
2143 0 : if (!use32bit && aspath_has_as4 (aspath))
2144 0 : send_as4_path = 1; /* we'll do this later, at the correct place */
2145 :
2146 : /* Nexthop attribute. */
2147 0 : if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2148 : {
2149 0 : stream_putc (s, BGP_ATTR_FLAG_TRANS);
2150 0 : stream_putc (s, BGP_ATTR_NEXT_HOP);
2151 0 : stream_putc (s, 4);
2152 0 : if (safi == SAFI_MPLS_VPN)
2153 : {
2154 0 : if (attr->nexthop.s_addr == 0)
2155 0 : stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2156 : else
2157 0 : stream_put_ipv4 (s, attr->nexthop.s_addr);
2158 : }
2159 : else
2160 0 : stream_put_ipv4 (s, attr->nexthop.s_addr);
2161 : }
2162 :
2163 : /* MED attribute. */
2164 0 : if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2165 : {
2166 0 : stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2167 0 : stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2168 0 : stream_putc (s, 4);
2169 0 : stream_putl (s, attr->med);
2170 : }
2171 :
2172 : /* Local preference. */
2173 0 : if (peer->sort == BGP_PEER_IBGP ||
2174 0 : peer->sort == BGP_PEER_CONFED)
2175 : {
2176 0 : stream_putc (s, BGP_ATTR_FLAG_TRANS);
2177 0 : stream_putc (s, BGP_ATTR_LOCAL_PREF);
2178 0 : stream_putc (s, 4);
2179 0 : stream_putl (s, attr->local_pref);
2180 : }
2181 :
2182 : /* Atomic aggregate. */
2183 0 : if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2184 : {
2185 0 : stream_putc (s, BGP_ATTR_FLAG_TRANS);
2186 0 : stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2187 0 : stream_putc (s, 0);
2188 : }
2189 :
2190 : /* Aggregator. */
2191 0 : if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2192 : {
2193 0 : assert (attr->extra);
2194 :
2195 : /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
2196 0 : stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2197 0 : stream_putc (s, BGP_ATTR_AGGREGATOR);
2198 :
2199 0 : if (use32bit)
2200 : {
2201 : /* AS4 capable peer */
2202 0 : stream_putc (s, 8);
2203 0 : stream_putl (s, attr->extra->aggregator_as);
2204 : }
2205 : else
2206 : {
2207 : /* 2-byte AS peer */
2208 0 : stream_putc (s, 6);
2209 :
2210 : /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2211 0 : if ( attr->extra->aggregator_as > 65535 )
2212 : {
2213 0 : stream_putw (s, BGP_AS_TRANS);
2214 :
2215 : /* we have to send AS4_AGGREGATOR, too.
2216 : * we'll do that later in order to send attributes in ascending
2217 : * order.
2218 : */
2219 0 : send_as4_aggregator = 1;
2220 : }
2221 : else
2222 0 : stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2223 : }
2224 0 : stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2225 : }
2226 :
2227 : /* Community attribute. */
2228 0 : if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2229 0 : && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2230 : {
2231 0 : if (attr->community->size * 4 > 255)
2232 : {
2233 0 : stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2234 0 : stream_putc (s, BGP_ATTR_COMMUNITIES);
2235 0 : stream_putw (s, attr->community->size * 4);
2236 : }
2237 : else
2238 : {
2239 0 : stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2240 0 : stream_putc (s, BGP_ATTR_COMMUNITIES);
2241 0 : stream_putc (s, attr->community->size * 4);
2242 : }
2243 0 : stream_put (s, attr->community->val, attr->community->size * 4);
2244 : }
2245 :
2246 : /* Route Reflector. */
2247 0 : if (peer->sort == BGP_PEER_IBGP
2248 0 : && from
2249 0 : && from->sort == BGP_PEER_IBGP)
2250 : {
2251 : /* Originator ID. */
2252 0 : stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2253 0 : stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2254 0 : stream_putc (s, 4);
2255 :
2256 0 : if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
2257 0 : stream_put_in_addr (s, &attr->extra->originator_id);
2258 : else
2259 0 : stream_put_in_addr (s, &from->remote_id);
2260 :
2261 : /* Cluster list. */
2262 0 : stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2263 0 : stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2264 :
2265 0 : if (attr->extra && attr->extra->cluster)
2266 : {
2267 0 : stream_putc (s, attr->extra->cluster->length + 4);
2268 : /* If this peer configuration's parent BGP has cluster_id. */
2269 0 : if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2270 0 : stream_put_in_addr (s, &bgp->cluster_id);
2271 : else
2272 0 : stream_put_in_addr (s, &bgp->router_id);
2273 0 : stream_put (s, attr->extra->cluster->list,
2274 0 : attr->extra->cluster->length);
2275 : }
2276 : else
2277 : {
2278 0 : stream_putc (s, 4);
2279 : /* If this peer configuration's parent BGP has cluster_id. */
2280 0 : if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2281 0 : stream_put_in_addr (s, &bgp->cluster_id);
2282 : else
2283 0 : stream_put_in_addr (s, &bgp->router_id);
2284 : }
2285 : }
2286 :
2287 : #ifdef HAVE_IPV6
2288 : /* If p is IPv6 address put it into attribute. */
2289 0 : if (p->family == AF_INET6)
2290 : {
2291 : unsigned long sizep;
2292 0 : struct attr_extra *attre = attr->extra;
2293 :
2294 0 : assert (attr->extra);
2295 :
2296 0 : stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2297 0 : stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
2298 0 : sizep = stream_get_endp (s);
2299 0 : stream_putc (s, 0); /* Marker: Attribute length. */
2300 0 : stream_putw (s, AFI_IP6); /* AFI */
2301 0 : stream_putc (s, safi); /* SAFI */
2302 :
2303 0 : stream_putc (s, attre->mp_nexthop_len);
2304 :
2305 0 : if (attre->mp_nexthop_len == 16)
2306 0 : stream_put (s, &attre->mp_nexthop_global, 16);
2307 0 : else if (attre->mp_nexthop_len == 32)
2308 : {
2309 0 : stream_put (s, &attre->mp_nexthop_global, 16);
2310 0 : stream_put (s, &attre->mp_nexthop_local, 16);
2311 : }
2312 :
2313 : /* SNPA */
2314 0 : stream_putc (s, 0);
2315 :
2316 : /* Prefix write. */
2317 0 : stream_put_prefix (s, p);
2318 :
2319 : /* Set MP attribute length. */
2320 0 : stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
2321 : }
2322 : #endif /* HAVE_IPV6 */
2323 :
2324 0 : if (p->family == AF_INET && safi == SAFI_MULTICAST)
2325 : {
2326 : unsigned long sizep;
2327 :
2328 0 : stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2329 0 : stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
2330 0 : sizep = stream_get_endp (s);
2331 0 : stream_putc (s, 0); /* Marker: Attribute Length. */
2332 0 : stream_putw (s, AFI_IP); /* AFI */
2333 0 : stream_putc (s, SAFI_MULTICAST); /* SAFI */
2334 :
2335 0 : stream_putc (s, 4);
2336 0 : stream_put_ipv4 (s, attr->nexthop.s_addr);
2337 :
2338 : /* SNPA */
2339 0 : stream_putc (s, 0);
2340 :
2341 : /* Prefix write. */
2342 0 : stream_put_prefix (s, p);
2343 :
2344 : /* Set MP attribute length. */
2345 0 : stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
2346 : }
2347 :
2348 0 : if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2349 : {
2350 : unsigned long sizep;
2351 :
2352 0 : stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2353 0 : stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
2354 0 : sizep = stream_get_endp (s);
2355 0 : stream_putc (s, 0); /* Length of this attribute. */
2356 0 : stream_putw (s, AFI_IP); /* AFI */
2357 0 : stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
2358 :
2359 0 : stream_putc (s, 12);
2360 0 : stream_putl (s, 0);
2361 0 : stream_putl (s, 0);
2362 0 : stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
2363 :
2364 : /* SNPA */
2365 0 : stream_putc (s, 0);
2366 :
2367 : /* Tag, RD, Prefix write. */
2368 0 : stream_putc (s, p->prefixlen + 88);
2369 0 : stream_put (s, tag, 3);
2370 0 : stream_put (s, prd->val, 8);
2371 0 : stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2372 :
2373 : /* Set MP attribute length. */
2374 0 : stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
2375 : }
2376 :
2377 : /* Extended Communities attribute. */
2378 0 : if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2379 0 : && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2380 : {
2381 0 : struct attr_extra *attre = attr->extra;
2382 :
2383 0 : assert (attre);
2384 :
2385 0 : if (peer->sort == BGP_PEER_IBGP
2386 0 : || peer->sort == BGP_PEER_CONFED)
2387 : {
2388 0 : if (attre->ecommunity->size * 8 > 255)
2389 : {
2390 0 : stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2391 0 : stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2392 0 : stream_putw (s, attre->ecommunity->size * 8);
2393 : }
2394 : else
2395 : {
2396 0 : stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2397 0 : stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2398 0 : stream_putc (s, attre->ecommunity->size * 8);
2399 : }
2400 0 : stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
2401 : }
2402 : else
2403 : {
2404 : u_int8_t *pnt;
2405 : int tbit;
2406 0 : int ecom_tr_size = 0;
2407 : int i;
2408 :
2409 0 : for (i = 0; i < attre->ecommunity->size; i++)
2410 : {
2411 0 : pnt = attre->ecommunity->val + (i * 8);
2412 0 : tbit = *pnt;
2413 :
2414 0 : if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2415 0 : continue;
2416 :
2417 0 : ecom_tr_size++;
2418 : }
2419 :
2420 0 : if (ecom_tr_size)
2421 : {
2422 0 : if (ecom_tr_size * 8 > 255)
2423 : {
2424 0 : stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2425 0 : stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2426 0 : stream_putw (s, ecom_tr_size * 8);
2427 : }
2428 : else
2429 : {
2430 0 : stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2431 0 : stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2432 0 : stream_putc (s, ecom_tr_size * 8);
2433 : }
2434 :
2435 0 : for (i = 0; i < attre->ecommunity->size; i++)
2436 : {
2437 0 : pnt = attre->ecommunity->val + (i * 8);
2438 0 : tbit = *pnt;
2439 :
2440 0 : if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2441 0 : continue;
2442 :
2443 0 : stream_put (s, pnt, 8);
2444 : }
2445 : }
2446 : }
2447 : }
2448 :
2449 0 : if ( send_as4_path )
2450 : {
2451 : /* If the peer is NOT As4 capable, AND */
2452 : /* there are ASnums > 65535 in path THEN
2453 : * give out AS4_PATH */
2454 :
2455 : /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2456 : * path segments!
2457 : * Hm, I wonder... confederation things *should* only be at
2458 : * the beginning of an aspath, right? Then we should use
2459 : * aspath_delete_confed_seq for this, because it is already
2460 : * there! (JK)
2461 : * Folks, talk to me: what is reasonable here!?
2462 : */
2463 0 : aspath = aspath_delete_confed_seq (aspath);
2464 :
2465 0 : stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2466 0 : stream_putc (s, BGP_ATTR_AS4_PATH);
2467 0 : aspath_sizep = stream_get_endp (s);
2468 0 : stream_putw (s, 0);
2469 0 : stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2470 : }
2471 :
2472 0 : if (aspath != attr->aspath)
2473 0 : aspath_free (aspath);
2474 :
2475 0 : if ( send_as4_aggregator )
2476 : {
2477 0 : assert (attr->extra);
2478 :
2479 : /* send AS4_AGGREGATOR, at this place */
2480 : /* this section of code moved here in order to ensure the correct
2481 : * *ascending* order of attributes
2482 : */
2483 0 : stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2484 0 : stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2485 0 : stream_putc (s, 8);
2486 0 : stream_putl (s, attr->extra->aggregator_as);
2487 0 : stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2488 : }
2489 :
2490 : /* Unknown transit attribute. */
2491 0 : if (attr->extra && attr->extra->transit)
2492 0 : stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
2493 :
2494 : /* Return total size of attribute. */
2495 0 : return stream_get_endp (s) - cp;
2496 : }
2497 :
2498 : bgp_size_t
2499 0 : bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2500 : afi_t afi, safi_t safi, struct prefix_rd *prd,
2501 : u_char *tag)
2502 : {
2503 : unsigned long cp;
2504 : unsigned long attrlen_pnt;
2505 : bgp_size_t size;
2506 :
2507 0 : cp = stream_get_endp (s);
2508 :
2509 0 : stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2510 0 : stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2511 :
2512 0 : attrlen_pnt = stream_get_endp (s);
2513 0 : stream_putc (s, 0); /* Length of this attribute. */
2514 :
2515 0 : stream_putw (s, family2afi (p->family));
2516 :
2517 0 : if (safi == SAFI_MPLS_VPN)
2518 : {
2519 : /* SAFI */
2520 0 : stream_putc (s, SAFI_MPLS_LABELED_VPN);
2521 :
2522 : /* prefix. */
2523 0 : stream_putc (s, p->prefixlen + 88);
2524 0 : stream_put (s, tag, 3);
2525 0 : stream_put (s, prd->val, 8);
2526 0 : stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2527 : }
2528 : else
2529 : {
2530 : /* SAFI */
2531 0 : stream_putc (s, safi);
2532 :
2533 : /* prefix */
2534 0 : stream_put_prefix (s, p);
2535 : }
2536 :
2537 : /* Set MP attribute length. */
2538 0 : size = stream_get_endp (s) - attrlen_pnt - 1;
2539 0 : stream_putc_at (s, attrlen_pnt, size);
2540 :
2541 0 : return stream_get_endp (s) - cp;
2542 : }
2543 :
2544 : /* Initialization of attribute. */
2545 : void
2546 1 : bgp_attr_init (void)
2547 : {
2548 1 : aspath_init ();
2549 1 : attrhash_init ();
2550 1 : community_init ();
2551 1 : ecommunity_init ();
2552 1 : cluster_init ();
2553 1 : transit_init ();
2554 1 : }
2555 :
2556 : void
2557 0 : bgp_attr_finish (void)
2558 : {
2559 0 : aspath_finish ();
2560 0 : attrhash_finish ();
2561 0 : community_finish ();
2562 0 : ecommunity_finish ();
2563 0 : cluster_finish ();
2564 0 : transit_finish ();
2565 0 : }
2566 :
2567 : /* Make attribute packet. */
2568 : void
2569 0 : bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2570 : struct prefix *prefix)
2571 : {
2572 : unsigned long cp;
2573 : unsigned long len;
2574 : size_t aspath_lenp;
2575 : struct aspath *aspath;
2576 :
2577 : /* Remember current pointer. */
2578 0 : cp = stream_get_endp (s);
2579 :
2580 : /* Place holder of length. */
2581 0 : stream_putw (s, 0);
2582 :
2583 : /* Origin attribute. */
2584 0 : stream_putc (s, BGP_ATTR_FLAG_TRANS);
2585 0 : stream_putc (s, BGP_ATTR_ORIGIN);
2586 0 : stream_putc (s, 1);
2587 0 : stream_putc (s, attr->origin);
2588 :
2589 0 : aspath = attr->aspath;
2590 :
2591 0 : stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2592 0 : stream_putc (s, BGP_ATTR_AS_PATH);
2593 0 : aspath_lenp = stream_get_endp (s);
2594 0 : stream_putw (s, 0);
2595 :
2596 0 : stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
2597 :
2598 : /* Nexthop attribute. */
2599 : /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2600 0 : if(prefix != NULL
2601 : #ifdef HAVE_IPV6
2602 0 : && prefix->family != AF_INET6
2603 : #endif /* HAVE_IPV6 */
2604 : )
2605 : {
2606 0 : stream_putc (s, BGP_ATTR_FLAG_TRANS);
2607 0 : stream_putc (s, BGP_ATTR_NEXT_HOP);
2608 0 : stream_putc (s, 4);
2609 0 : stream_put_ipv4 (s, attr->nexthop.s_addr);
2610 : }
2611 :
2612 : /* MED attribute. */
2613 0 : if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2614 : {
2615 0 : stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2616 0 : stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2617 0 : stream_putc (s, 4);
2618 0 : stream_putl (s, attr->med);
2619 : }
2620 :
2621 : /* Local preference. */
2622 0 : if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2623 : {
2624 0 : stream_putc (s, BGP_ATTR_FLAG_TRANS);
2625 0 : stream_putc (s, BGP_ATTR_LOCAL_PREF);
2626 0 : stream_putc (s, 4);
2627 0 : stream_putl (s, attr->local_pref);
2628 : }
2629 :
2630 : /* Atomic aggregate. */
2631 0 : if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2632 : {
2633 0 : stream_putc (s, BGP_ATTR_FLAG_TRANS);
2634 0 : stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2635 0 : stream_putc (s, 0);
2636 : }
2637 :
2638 : /* Aggregator. */
2639 0 : if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2640 : {
2641 0 : assert (attr->extra);
2642 0 : stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2643 0 : stream_putc (s, BGP_ATTR_AGGREGATOR);
2644 0 : stream_putc (s, 8);
2645 0 : stream_putl (s, attr->extra->aggregator_as);
2646 0 : stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2647 : }
2648 :
2649 : /* Community attribute. */
2650 0 : if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2651 : {
2652 0 : if (attr->community->size * 4 > 255)
2653 : {
2654 0 : stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2655 0 : stream_putc (s, BGP_ATTR_COMMUNITIES);
2656 0 : stream_putw (s, attr->community->size * 4);
2657 : }
2658 : else
2659 : {
2660 0 : stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2661 0 : stream_putc (s, BGP_ATTR_COMMUNITIES);
2662 0 : stream_putc (s, attr->community->size * 4);
2663 : }
2664 0 : stream_put (s, attr->community->val, attr->community->size * 4);
2665 : }
2666 :
2667 : #ifdef HAVE_IPV6
2668 : /* Add a MP_NLRI attribute to dump the IPv6 next hop */
2669 0 : if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2670 0 : (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
2671 : {
2672 : int sizep;
2673 0 : struct attr_extra *attre = attr->extra;
2674 :
2675 0 : stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2676 0 : stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
2677 0 : sizep = stream_get_endp (s);
2678 :
2679 : /* MP header */
2680 0 : stream_putc (s, 0); /* Marker: Attribute length. */
2681 0 : stream_putw(s, AFI_IP6); /* AFI */
2682 0 : stream_putc(s, SAFI_UNICAST); /* SAFI */
2683 :
2684 : /* Next hop */
2685 0 : stream_putc(s, attre->mp_nexthop_len);
2686 0 : stream_put(s, &attre->mp_nexthop_global, 16);
2687 0 : if (attre->mp_nexthop_len == 32)
2688 0 : stream_put(s, &attre->mp_nexthop_local, 16);
2689 :
2690 : /* SNPA */
2691 0 : stream_putc(s, 0);
2692 :
2693 : /* Prefix */
2694 0 : stream_put_prefix(s, prefix);
2695 :
2696 : /* Set MP attribute length. */
2697 0 : stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
2698 : }
2699 : #endif /* HAVE_IPV6 */
2700 :
2701 : /* Return total size of attribute. */
2702 0 : len = stream_get_endp (s) - cp - 2;
2703 0 : stream_putw_at (s, cp, len);
2704 0 : }
|