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