blob: b30c86ae1ed6ce9390a2da145b34b5aee97ae92b [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* BGP attributes management routines.
2 Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-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
32#include "bgpd/bgpd.h"
33#include "bgpd/bgp_attr.h"
34#include "bgpd/bgp_route.h"
35#include "bgpd/bgp_aspath.h"
36#include "bgpd/bgp_community.h"
37#include "bgpd/bgp_debug.h"
38#include "bgpd/bgp_packet.h"
39#include "bgpd/bgp_ecommunity.h"
40
41/* Attribute strings for logging. */
Paul Jakma6e4ab122007-04-10 19:36:48 +000042static struct message attr_str [] =
paul718e3742002-12-13 20:15:29 +000043{
44 { BGP_ATTR_ORIGIN, "ORIGIN" },
45 { BGP_ATTR_AS_PATH, "AS_PATH" },
46 { BGP_ATTR_NEXT_HOP, "NEXT_HOP" },
47 { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
48 { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" },
49 { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
50 { BGP_ATTR_AGGREGATOR, "AGGREGATOR" },
51 { BGP_ATTR_COMMUNITIES, "COMMUNITY" },
52 { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" },
53 { BGP_ATTR_CLUSTER_LIST, "CLUSTERLIST" },
54 { BGP_ATTR_DPA, "DPA" },
55 { BGP_ATTR_ADVERTISER, "ADVERTISER"} ,
56 { BGP_ATTR_RCID_PATH, "RCID_PATH" },
57 { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
58 { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
59 { 0, NULL }
60};
Paul Jakma6e4ab122007-04-10 19:36:48 +000061int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
paul718e3742002-12-13 20:15:29 +000062
63struct hash *cluster_hash;
64
paul94f2b392005-06-28 12:44:16 +000065static void *
Paul Jakma923de652007-04-29 18:25:17 +000066cluster_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +000067{
Paul Jakma923de652007-04-29 18:25:17 +000068 struct cluster_list * val = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +000069 struct cluster_list *cluster;
70
71 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
72 cluster->length = val->length;
73
74 if (cluster->length)
75 {
76 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
77 memcpy (cluster->list, val->list, val->length);
78 }
79 else
80 cluster->list = NULL;
81
82 cluster->refcnt = 0;
83
84 return cluster;
85}
86
87/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +000088static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +000089cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +000090{
91 struct cluster_list tmp;
92 struct cluster_list *cluster;
93
94 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +000095 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +000096
97 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
98 cluster->refcnt++;
99 return cluster;
100}
101
102int
103cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
104{
105 int i;
106
107 for (i = 0; i < cluster->length / 4; i++)
108 if (cluster->list[i].s_addr == originator.s_addr)
109 return 1;
110 return 0;
111}
112
paul94f2b392005-06-28 12:44:16 +0000113static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000114cluster_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000115{
Paul Jakma923de652007-04-29 18:25:17 +0000116 struct cluster_list * cluster = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +0000117 unsigned int key = 0;
118 int length;
119 caddr_t pnt;
120
121 length = cluster->length;
122 pnt = (caddr_t) cluster->list;
123
124 while (length)
125 key += pnt[--length];
126
127 return key;
128}
129
paul94f2b392005-06-28 12:44:16 +0000130static int
Paul Jakma923de652007-04-29 18:25:17 +0000131cluster_hash_cmp (void *p1, void *p2)
paul718e3742002-12-13 20:15:29 +0000132{
Paul Jakma923de652007-04-29 18:25:17 +0000133 struct cluster_list * cluster1 = (struct cluster_list *) p1;
134 struct cluster_list * cluster2 = (struct cluster_list *) p2;
135
paul718e3742002-12-13 20:15:29 +0000136 if (cluster1->length == cluster2->length &&
137 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0)
138 return 1;
139 return 0;
140}
141
paul94f2b392005-06-28 12:44:16 +0000142static void
paul718e3742002-12-13 20:15:29 +0000143cluster_free (struct cluster_list *cluster)
144{
145 if (cluster->list)
146 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
147 XFREE (MTYPE_CLUSTER, cluster);
148}
149
paul94f2b392005-06-28 12:44:16 +0000150static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000151cluster_dup (struct cluster_list *cluster)
152{
153 struct cluster_list *new;
154
155 new = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
156 memset (new, 0, sizeof (struct cluster_list));
157 new->length = cluster->length;
158
159 if (cluster->length)
160 {
161 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
162 memcpy (new->list, cluster->list, cluster->length);
163 }
164 else
165 new->list = NULL;
166
167 return new;
168}
169
paul94f2b392005-06-28 12:44:16 +0000170static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000171cluster_intern (struct cluster_list *cluster)
172{
173 struct cluster_list *find;
174
175 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
176 find->refcnt++;
177
178 return find;
179}
180
181void
182cluster_unintern (struct cluster_list *cluster)
183{
184 struct cluster_list *ret;
185
186 if (cluster->refcnt)
187 cluster->refcnt--;
188
189 if (cluster->refcnt == 0)
190 {
191 ret = hash_release (cluster_hash, cluster);
192 cluster_free (cluster);
193 }
194}
195
paul94f2b392005-06-28 12:44:16 +0000196static void
197cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000198{
199 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
200}
201
202/* Unknown transit attribute. */
203struct hash *transit_hash;
204
paul94f2b392005-06-28 12:44:16 +0000205static void
paul718e3742002-12-13 20:15:29 +0000206transit_free (struct transit *transit)
207{
208 if (transit->val)
209 XFREE (MTYPE_TRANSIT_VAL, transit->val);
210 XFREE (MTYPE_TRANSIT, transit);
211}
212
Paul Jakma923de652007-04-29 18:25:17 +0000213
paul94f2b392005-06-28 12:44:16 +0000214static void *
Paul Jakma923de652007-04-29 18:25:17 +0000215transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000216{
217 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000218 return p;
paul718e3742002-12-13 20:15:29 +0000219}
220
paul94f2b392005-06-28 12:44:16 +0000221static struct transit *
paul718e3742002-12-13 20:15:29 +0000222transit_intern (struct transit *transit)
223{
224 struct transit *find;
225
226 find = hash_get (transit_hash, transit, transit_hash_alloc);
227 if (find != transit)
228 transit_free (transit);
229 find->refcnt++;
230
231 return find;
232}
233
234void
235transit_unintern (struct transit *transit)
236{
237 struct transit *ret;
238
239 if (transit->refcnt)
240 transit->refcnt--;
241
242 if (transit->refcnt == 0)
243 {
244 ret = hash_release (transit_hash, transit);
245 transit_free (transit);
246 }
247}
248
paul94f2b392005-06-28 12:44:16 +0000249static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000250transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000251{
Paul Jakma923de652007-04-29 18:25:17 +0000252 struct transit * transit = (struct transit *) p;
paul718e3742002-12-13 20:15:29 +0000253 unsigned int key = 0;
254 int length;
255 caddr_t pnt;
256
257 length = transit->length;
258 pnt = (caddr_t) transit->val;
259
260 while (length)
261 key += pnt[--length];
262
263 return key;
264}
265
paul94f2b392005-06-28 12:44:16 +0000266static int
Paul Jakma923de652007-04-29 18:25:17 +0000267transit_hash_cmp (void *p1, void *p2)
paul718e3742002-12-13 20:15:29 +0000268{
Paul Jakma923de652007-04-29 18:25:17 +0000269 struct transit * transit1 = (struct transit *) p1;
270 struct transit * transit2 = (struct transit *) p2;
271
paul718e3742002-12-13 20:15:29 +0000272 if (transit1->length == transit2->length &&
273 memcmp (transit1->val, transit2->val, transit1->length) == 0)
274 return 1;
275 return 0;
276}
277
paul94f2b392005-06-28 12:44:16 +0000278static void
paul718e3742002-12-13 20:15:29 +0000279transit_init ()
280{
281 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
282}
283
284/* Attribute hash routines. */
285
286struct hash *attrhash;
287
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000288unsigned long int
289attr_count (void)
290{
291 return attrhash->count;
292}
293
294unsigned long int
295attr_unknown_count (void)
296{
297 return transit_hash->count;
298}
299
paul718e3742002-12-13 20:15:29 +0000300unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000301attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000302{
Paul Jakma923de652007-04-29 18:25:17 +0000303 struct attr * attr = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000304 unsigned int key = 0;
305
306 key += attr->origin;
307 key += attr->nexthop.s_addr;
308 key += attr->med;
309 key += attr->local_pref;
310 key += attr->aggregator_as;
311 key += attr->aggregator_addr.s_addr;
312 key += attr->weight;
313
314 key += attr->mp_nexthop_global_in.s_addr;
315 if (attr->aspath)
316 key += aspath_key_make (attr->aspath);
317 if (attr->community)
318 key += community_hash_make (attr->community);
319 if (attr->ecommunity)
320 key += ecommunity_hash_make (attr->ecommunity);
321 if (attr->cluster)
322 key += cluster_hash_key_make (attr->cluster);
323 if (attr->transit)
324 key += transit_hash_key_make (attr->transit);
325
326#ifdef HAVE_IPV6
327 {
328 int i;
329
330 key += attr->mp_nexthop_len;
331 for (i = 0; i < 16; i++)
332 key += attr->mp_nexthop_global.s6_addr[i];
333 for (i = 0; i < 16; i++)
334 key += attr->mp_nexthop_local.s6_addr[i];
335 }
336#endif /* HAVE_IPV6 */
337
338 return key;
339}
340
341int
Paul Jakma923de652007-04-29 18:25:17 +0000342attrhash_cmp (void *p1, void *p2)
paul718e3742002-12-13 20:15:29 +0000343{
Paul Jakma923de652007-04-29 18:25:17 +0000344 struct attr * attr1 = (struct attr *) p1;
345 struct attr * attr2 = (struct attr *) p2;
346
paul718e3742002-12-13 20:15:29 +0000347 if (attr1->flag == attr2->flag
348 && attr1->origin == attr2->origin
349 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
350 && attr1->med == attr2->med
351 && attr1->local_pref == attr2->local_pref
352 && attr1->aggregator_as == attr2->aggregator_as
353 && attr1->aggregator_addr.s_addr == attr2->aggregator_addr.s_addr
354 && attr1->weight == attr2->weight
355#ifdef HAVE_IPV6
356 && attr1->mp_nexthop_len == attr2->mp_nexthop_len
357 && IPV6_ADDR_SAME (&attr1->mp_nexthop_global, &attr2->mp_nexthop_global)
358 && IPV6_ADDR_SAME (&attr1->mp_nexthop_local, &attr2->mp_nexthop_local)
359#endif /* HAVE_IPV6 */
360 && IPV4_ADDR_SAME (&attr1->mp_nexthop_global_in, &attr2->mp_nexthop_global_in)
361 && attr1->aspath == attr2->aspath
362 && attr1->community == attr2->community
363 && attr1->ecommunity == attr2->ecommunity
364 && attr1->cluster == attr2->cluster
365 && attr1->transit == attr2->transit)
366 return 1;
367 else
368 return 0;
369}
370
paul94f2b392005-06-28 12:44:16 +0000371static void
paul718e3742002-12-13 20:15:29 +0000372attrhash_init ()
373{
374 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
375}
376
paul94f2b392005-06-28 12:44:16 +0000377static void
paul718e3742002-12-13 20:15:29 +0000378attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
379{
380 struct attr *attr = backet->data;
381
382 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
383 inet_ntoa (attr->nexthop), VTY_NEWLINE);
384}
385
386void
387attr_show_all (struct vty *vty)
388{
389 hash_iterate (attrhash,
390 (void (*)(struct hash_backet *, void *))
391 attr_show_all_iterator,
392 vty);
393}
394
paul94f2b392005-06-28 12:44:16 +0000395static void *
Paul Jakma923de652007-04-29 18:25:17 +0000396bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000397{
Paul Jakma923de652007-04-29 18:25:17 +0000398 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000399 struct attr *attr;
400
401 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
402 *attr = *val;
403 attr->refcnt = 0;
404 return attr;
405}
406
407/* Internet argument attribute. */
408struct attr *
409bgp_attr_intern (struct attr *attr)
410{
411 struct attr *find;
412
413 /* Intern referenced strucutre. */
414 if (attr->aspath)
415 {
416 if (! attr->aspath->refcnt)
417 attr->aspath = aspath_intern (attr->aspath);
418 else
419 attr->aspath->refcnt++;
420 }
421 if (attr->community)
422 {
423 if (! attr->community->refcnt)
424 attr->community = community_intern (attr->community);
425 else
426 attr->community->refcnt++;
427 }
428 if (attr->ecommunity)
429 {
430 if (! attr->ecommunity->refcnt)
431 attr->ecommunity = ecommunity_intern (attr->ecommunity);
432 else
433 attr->ecommunity->refcnt++;
434 }
435 if (attr->cluster)
436 {
437 if (! attr->cluster->refcnt)
438 attr->cluster = cluster_intern (attr->cluster);
439 else
440 attr->cluster->refcnt++;
441 }
442 if (attr->transit)
443 {
444 if (! attr->transit->refcnt)
445 attr->transit = transit_intern (attr->transit);
446 else
447 attr->transit->refcnt++;
448 }
449
450 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
451 find->refcnt++;
452
453 return find;
454}
455
456/* Make network statement's attribute. */
457struct attr *
458bgp_attr_default_set (struct attr *attr, u_char origin)
459{
460 memset (attr, 0, sizeof (struct attr));
461
462 attr->origin = origin;
463 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
464 attr->aspath = aspath_empty ();
465 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
466 attr->weight = 32768;
467 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
468#ifdef HAVE_IPV6
469 attr->mp_nexthop_len = 16;
470#endif
471 return attr;
472}
473
474/* Make network statement's attribute. */
475struct attr *
476bgp_attr_default_intern (u_char origin)
477{
478 struct attr attr;
479 struct attr *new;
480
481 memset (&attr, 0, sizeof (struct attr));
482
483 attr.origin = origin;
484 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
485 attr.aspath = aspath_empty ();
486 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
487 attr.weight = 32768;
488 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
489#ifdef HAVE_IPV6
490 attr.mp_nexthop_len = 16;
491#endif
492
493 new = bgp_attr_intern (&attr);
494 aspath_unintern (new->aspath);
495 return new;
496}
497
498struct attr *
499bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
500 struct aspath *aspath,
501 struct community *community, int as_set)
502{
503 struct attr attr;
504 struct attr *new;
505
506 memset (&attr, 0, sizeof (struct attr));
507
508 /* Origin attribute. */
509 attr.origin = origin;
510 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
511
512 /* AS path attribute. */
513 if (aspath)
514 attr.aspath = aspath_intern (aspath);
515 else
516 attr.aspath = aspath_empty ();
517 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
518
519 /* Next hop attribute. */
520 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
521
522 if (community)
523 {
524 attr.community = community;
525 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
526 }
527
528 attr.weight = 32768;
529#ifdef HAVE_IPV6
530 attr.mp_nexthop_len = 16;
531#endif
532 if (! as_set)
533 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
534 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
535 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
536 attr.aggregator_as = bgp->confed_id;
537 else
538 attr.aggregator_as = bgp->as;
539 attr.aggregator_addr = bgp->router_id;
540
541 new = bgp_attr_intern (&attr);
542 aspath_unintern (new->aspath);
543 return new;
544}
545
546/* Free bgp attribute and aspath. */
547void
548bgp_attr_unintern (struct attr *attr)
549{
550 struct attr *ret;
551 struct aspath *aspath;
552 struct community *community;
553 struct ecommunity *ecommunity;
554 struct cluster_list *cluster;
555 struct transit *transit;
556
557 /* Decrement attribute reference. */
558 attr->refcnt--;
559 aspath = attr->aspath;
560 community = attr->community;
561 ecommunity = attr->ecommunity;
562 cluster = attr->cluster;
563 transit = attr->transit;
564
565 /* If reference becomes zero then free attribute object. */
566 if (attr->refcnt == 0)
567 {
568 ret = hash_release (attrhash, attr);
569 assert (ret != NULL);
570 XFREE (MTYPE_ATTR, attr);
571 }
572
573 /* aspath refcount shoud be decrement. */
574 if (aspath)
575 aspath_unintern (aspath);
576 if (community)
577 community_unintern (community);
578 if (ecommunity)
579 ecommunity_unintern (ecommunity);
580 if (cluster)
581 cluster_unintern (cluster);
582 if (transit)
583 transit_unintern (transit);
584}
585
586void
587bgp_attr_flush (struct attr *attr)
588{
589 if (attr->aspath && ! attr->aspath->refcnt)
590 aspath_free (attr->aspath);
591 if (attr->community && ! attr->community->refcnt)
592 community_free (attr->community);
593 if (attr->ecommunity && ! attr->ecommunity->refcnt)
594 ecommunity_free (attr->ecommunity);
595 if (attr->cluster && ! attr->cluster->refcnt)
596 cluster_free (attr->cluster);
597 if (attr->transit && ! attr->transit->refcnt)
598 transit_free (attr->transit);
599}
600
601/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000602static int
paul718e3742002-12-13 20:15:29 +0000603bgp_attr_origin (struct peer *peer, bgp_size_t length,
604 struct attr *attr, u_char flag, u_char *startp)
605{
606 bgp_size_t total;
607
608 /* total is entire attribute length include Attribute Flags (1),
609 Attribute Type code (1) and Attribute length (1 or 2). */
610 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
611
612 /* If any recognized attribute has Attribute Flags that conflict
613 with the Attribute Type Code, then the Error Subcode is set to
614 Attribute Flags Error. The Data field contains the erroneous
615 attribute (type, length and value). */
616 if (flag != BGP_ATTR_FLAG_TRANS)
617 {
618 zlog (peer->log, LOG_ERR,
619 "Origin attribute flag isn't transitive %d", flag);
620 bgp_notify_send_with_data (peer,
621 BGP_NOTIFY_UPDATE_ERR,
622 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
623 startp, total);
624 return -1;
625 }
626
627 /* If any recognized attribute has Attribute Length that conflicts
628 with the expected length (based on the attribute type code), then
629 the Error Subcode is set to Attribute Length Error. The Data
630 field contains the erroneous attribute (type, length and
631 value). */
632 if (length != 1)
633 {
634 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
635 length);
636 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
637 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
638 startp, total);
639 return -1;
640 }
641
642 /* Fetch origin attribute. */
643 attr->origin = stream_getc (BGP_INPUT (peer));
644
645 /* If the ORIGIN attribute has an undefined value, then the Error
646 Subcode is set to Invalid Origin Attribute. The Data field
647 contains the unrecognized attribute (type, length and value). */
648 if ((attr->origin != BGP_ORIGIN_IGP)
649 && (attr->origin != BGP_ORIGIN_EGP)
650 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
651 {
652 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
653 attr->origin);
654
655 bgp_notify_send_with_data (peer,
656 BGP_NOTIFY_UPDATE_ERR,
657 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
658 startp, total);
659 return -1;
660 }
661
662 /* Set oring attribute flag. */
663 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
664
665 return 0;
666}
667
668/* Parse AS path information. This function is wrapper of
669 aspath_parse. */
paul94f2b392005-06-28 12:44:16 +0000670static int
paul718e3742002-12-13 20:15:29 +0000671bgp_attr_aspath (struct peer *peer, bgp_size_t length,
672 struct attr *attr, u_char flag, u_char *startp)
673{
674 struct bgp *bgp;
675 struct aspath *aspath;
676 bgp_size_t total;
677
678 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
679
680 /* Flag check. */
681 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
682 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
683 {
684 zlog (peer->log, LOG_ERR,
685 "Origin attribute flag isn't transitive %d", flag);
686 bgp_notify_send_with_data (peer,
687 BGP_NOTIFY_UPDATE_ERR,
688 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
689 startp, total);
690 return -1;
691 }
692
693 /* In case of IBGP, length will be zero. */
paulfe69a502005-09-10 16:55:02 +0000694 attr->aspath = aspath_parse (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000695 if (! attr->aspath)
696 {
697 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
698 bgp_notify_send (peer,
699 BGP_NOTIFY_UPDATE_ERR,
700 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
701 return -1;
702 }
703
704 bgp = peer->bgp;
705
706 /* First AS check for EBGP. */
707 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
708 {
709 if (peer_sort (peer) == BGP_PEER_EBGP
710 && ! aspath_firstas_check (attr->aspath, peer->as))
711 {
712 zlog (peer->log, LOG_ERR,
713 "%s incorrect first AS (must be %d)", peer->host, peer->as);
714 bgp_notify_send (peer,
715 BGP_NOTIFY_UPDATE_ERR,
716 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
717 return -1;
718 }
719 }
720
721 /* local-as prepend */
722 if (peer->change_local_as &&
723 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
724 {
725 aspath = aspath_dup (attr->aspath);
726 aspath = aspath_add_seq (aspath, peer->change_local_as);
727 aspath_unintern (attr->aspath);
728 attr->aspath = aspath_intern (aspath);
729 }
730
731 /* Forward pointer. */
paulfe69a502005-09-10 16:55:02 +0000732/* stream_forward_getp (peer->ibuf, length);*/
paul718e3742002-12-13 20:15:29 +0000733
734 /* Set aspath attribute flag. */
735 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
736
737 return 0;
738}
739
740/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000741static int
paul718e3742002-12-13 20:15:29 +0000742bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
743 struct attr *attr, u_char flag, u_char *startp)
744{
745 bgp_size_t total;
746
747 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
748
749 /* Flag check. */
750 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
751 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
752 {
753 zlog (peer->log, LOG_ERR,
754 "Origin attribute flag isn't transitive %d", flag);
755 bgp_notify_send_with_data (peer,
756 BGP_NOTIFY_UPDATE_ERR,
757 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
758 startp, total);
759 return -1;
760 }
761
762 /* Check nexthop attribute length. */
763 if (length != 4)
764 {
765 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
766 length);
767
768 bgp_notify_send_with_data (peer,
769 BGP_NOTIFY_UPDATE_ERR,
770 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
771 startp, total);
772 return -1;
773 }
774
775 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
776 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
777
778 return 0;
779}
780
781/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000782static int
paul718e3742002-12-13 20:15:29 +0000783bgp_attr_med (struct peer *peer, bgp_size_t length,
784 struct attr *attr, u_char flag, u_char *startp)
785{
786 bgp_size_t total;
787
788 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
789
790 /* Length check. */
791 if (length != 4)
792 {
793 zlog (peer->log, LOG_ERR,
794 "MED attribute length isn't four [%d]", length);
795
796 bgp_notify_send_with_data (peer,
797 BGP_NOTIFY_UPDATE_ERR,
798 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
799 startp, total);
800 return -1;
801 }
802
803 attr->med = stream_getl (peer->ibuf);
804
805 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
806
807 return 0;
808}
809
810/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000811static int
paul718e3742002-12-13 20:15:29 +0000812bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
813 struct attr *attr, u_char flag)
814{
815 /* If it is contained in an UPDATE message that is received from an
816 external peer, then this attribute MUST be ignored by the
817 receiving speaker. */
818 if (peer_sort (peer) == BGP_PEER_EBGP)
819 {
paul9985f832005-02-09 15:51:56 +0000820 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000821 return 0;
822 }
823
824 if (length == 4)
825 attr->local_pref = stream_getl (peer->ibuf);
826 else
827 attr->local_pref = 0;
828
829 /* Set atomic aggregate flag. */
830 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
831
832 return 0;
833}
834
835/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +0000836static int
paul718e3742002-12-13 20:15:29 +0000837bgp_attr_atomic (struct peer *peer, bgp_size_t length,
838 struct attr *attr, u_char flag)
839{
840 if (length != 0)
841 {
842 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
843
844 bgp_notify_send (peer,
845 BGP_NOTIFY_UPDATE_ERR,
846 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
847 return -1;
848 }
849
850 /* Set atomic aggregate flag. */
851 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
852
853 return 0;
854}
855
856/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +0000857static int
paul718e3742002-12-13 20:15:29 +0000858bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
859 struct attr *attr, u_char flag)
860{
861 if (length != 6)
862 {
863 zlog (peer->log, LOG_ERR, "Aggregator length is not 6 [%d]", length);
864
865 bgp_notify_send (peer,
866 BGP_NOTIFY_UPDATE_ERR,
867 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
868 return -1;
869 }
870 attr->aggregator_as = stream_getw (peer->ibuf);
871 attr->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
872
873 /* Set atomic aggregate flag. */
874 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
875
876 return 0;
877}
878
879/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +0000880static int
paul718e3742002-12-13 20:15:29 +0000881bgp_attr_community (struct peer *peer, bgp_size_t length,
882 struct attr *attr, u_char flag)
883{
884 if (length == 0)
885 attr->community = NULL;
886 else
887 {
paul5228ad22004-06-04 17:58:18 +0000888 attr->community =
889 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +0000890 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000891 }
892
893 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
894
895 return 0;
896}
897
898/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +0000899static int
paul718e3742002-12-13 20:15:29 +0000900bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
901 struct attr *attr, u_char flag)
902{
903 if (length != 4)
904 {
905 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
906
907 bgp_notify_send (peer,
908 BGP_NOTIFY_UPDATE_ERR,
909 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
910 return -1;
911 }
912
913 attr->originator_id.s_addr = stream_get_ipv4 (peer->ibuf);
914
915 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
916
917 return 0;
918}
919
920/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +0000921static int
paul718e3742002-12-13 20:15:29 +0000922bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
923 struct attr *attr, u_char flag)
924{
925 /* Check length. */
926 if (length % 4)
927 {
928 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
929
930 bgp_notify_send (peer,
931 BGP_NOTIFY_UPDATE_ERR,
932 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
933 return -1;
934 }
935
paul5228ad22004-06-04 17:58:18 +0000936 attr->cluster = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf),
937 length);
paul718e3742002-12-13 20:15:29 +0000938
paul9985f832005-02-09 15:51:56 +0000939 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +0000940
941 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
942
943 return 0;
944}
945
946/* Multiprotocol reachability information parse. */
paul94f2b392005-06-28 12:44:16 +0000947static int
paul718e3742002-12-13 20:15:29 +0000948bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
949 struct bgp_nlri *mp_update)
950{
951 u_int16_t afi;
952 u_char safi;
paul718e3742002-12-13 20:15:29 +0000953 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +0000954 size_t start;
paul718e3742002-12-13 20:15:29 +0000955 int ret;
956 struct stream *s;
957
958 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +0000959 s = BGP_INPUT(peer);
960 start = stream_get_getp(s);
961
962 /* safe to read statically sized header? */
963#define BGP_MP_REACH_MIN_SIZE 5
964 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
965 return -1;
966
paul718e3742002-12-13 20:15:29 +0000967 /* Load AFI, SAFI. */
968 afi = stream_getw (s);
969 safi = stream_getc (s);
970
971 /* Get nexthop length. */
972 attr->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +0000973
974 if (STREAM_READABLE(s) < attr->mp_nexthop_len)
975 return -1;
976
paul718e3742002-12-13 20:15:29 +0000977 /* Nexthop length check. */
978 switch (attr->mp_nexthop_len)
979 {
980 case 4:
981 stream_get (&attr->mp_nexthop_global_in, s, 4);
982 break;
983 case 12:
984 {
985 u_int32_t rd_high;
986 u_int32_t rd_low;
987
988 rd_high = stream_getl (s);
989 rd_low = stream_getl (s);
990 stream_get (&attr->mp_nexthop_global_in, s, 4);
991 }
992 break;
993#ifdef HAVE_IPV6
994 case 16:
995 stream_get (&attr->mp_nexthop_global, s, 16);
996 break;
997 case 32:
998 stream_get (&attr->mp_nexthop_global, s, 16);
999 stream_get (&attr->mp_nexthop_local, s, 16);
1000 if (! IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local))
1001 {
1002 char buf1[INET6_ADDRSTRLEN];
1003 char buf2[INET6_ADDRSTRLEN];
1004
1005 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001006 zlog_debug ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host,
paul718e3742002-12-13 20:15:29 +00001007 inet_ntop (AF_INET6, &attr->mp_nexthop_global,
1008 buf1, INET6_ADDRSTRLEN),
1009 inet_ntop (AF_INET6, &attr->mp_nexthop_local,
1010 buf2, INET6_ADDRSTRLEN));
1011
1012 attr->mp_nexthop_len = 16;
1013 }
1014 break;
1015#endif /* HAVE_IPV6 */
1016 default:
1017 zlog_info ("Wrong multiprotocol next hop length: %d",
1018 attr->mp_nexthop_len);
1019 return -1;
paul718e3742002-12-13 20:15:29 +00001020 }
1021
Paul Jakma6e4ab122007-04-10 19:36:48 +00001022 if (!STREAM_READABLE(s))
1023 return -1;
paul718e3742002-12-13 20:15:29 +00001024
Paul Jakma6e4ab122007-04-10 19:36:48 +00001025 {
1026 u_char val;
1027 if ((val = stream_getc (s)))
1028 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1029 peer->host, val);
1030 }
1031
1032 /* must have nrli_len, what is left of the attribute */
1033 nlri_len = length - (stream_get_getp(s) - start);
1034 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
1035 return -1;
paul718e3742002-12-13 20:15:29 +00001036
1037 if (safi != BGP_SAFI_VPNV4)
1038 {
1039 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
1040 if (ret < 0)
1041 return -1;
1042 }
1043
1044 mp_update->afi = afi;
1045 mp_update->safi = safi;
1046 mp_update->nlri = stream_pnt (s);
1047 mp_update->length = nlri_len;
1048
paul9985f832005-02-09 15:51:56 +00001049 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001050
1051 return 0;
1052}
1053
1054/* Multiprotocol unreachable parse */
paul94f2b392005-06-28 12:44:16 +00001055static int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001056bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001057 struct bgp_nlri *mp_withdraw)
1058{
1059 struct stream *s;
1060 u_int16_t afi;
1061 u_char safi;
paul718e3742002-12-13 20:15:29 +00001062 u_int16_t withdraw_len;
1063 int ret;
1064
1065 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001066
1067#define BGP_MP_UNREACH_MIN_SIZE 3
1068 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1069 return -1;
1070
paul718e3742002-12-13 20:15:29 +00001071 afi = stream_getw (s);
1072 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001073
1074 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001075
1076 if (safi != BGP_SAFI_VPNV4)
1077 {
1078 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1079 if (ret < 0)
1080 return -1;
1081 }
1082
1083 mp_withdraw->afi = afi;
1084 mp_withdraw->safi = safi;
1085 mp_withdraw->nlri = stream_pnt (s);
1086 mp_withdraw->length = withdraw_len;
1087
paul9985f832005-02-09 15:51:56 +00001088 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001089
1090 return 0;
1091}
1092
1093/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001094static int
paul718e3742002-12-13 20:15:29 +00001095bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1096 struct attr *attr, u_char flag)
1097{
1098 if (length == 0)
1099 attr->ecommunity = NULL;
1100 else
1101 {
paul5228ad22004-06-04 17:58:18 +00001102 attr->ecommunity =
1103 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001104 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001105 }
1106 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1107
1108 return 0;
1109}
1110
1111/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001112static int
paul718e3742002-12-13 20:15:29 +00001113bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1114 u_char type, bgp_size_t length, u_char *startp)
1115{
1116 bgp_size_t total;
1117 struct transit *transit;
1118
hassof4184462005-02-01 20:13:16 +00001119 if (BGP_DEBUG (normal, NORMAL))
1120 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1121 peer->host, type, length);
1122
paul718e3742002-12-13 20:15:29 +00001123 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001124 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001125 "Unknown attribute type %d length %d is received", type, length);
1126
1127 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001128 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001129
1130 /* Adjest total length to include type and length. */
1131 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1132
1133 /* If any of the mandatory well-known attributes are not recognized,
1134 then the Error Subcode is set to Unrecognized Well-known
1135 Attribute. The Data field contains the unrecognized attribute
1136 (type, length and value). */
1137 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1138 {
1139 /* Adjust startp to do not include flag value. */
1140 bgp_notify_send_with_data (peer,
1141 BGP_NOTIFY_UPDATE_ERR,
1142 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1143 startp, total);
1144 return -1;
1145 }
1146
1147 /* Unrecognized non-transitive optional attributes must be quietly
1148 ignored and not passed along to other BGP peers. */
1149 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1150 return 0;
1151
1152 /* If a path with recognized transitive optional attribute is
1153 accepted and passed along to other BGP peers and the Partial bit
1154 in the Attribute Flags octet is set to 1 by some previous AS, it
1155 is not set back to 0 by the current AS. */
1156 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1157
1158 /* Store transitive attribute to the end of attr->transit. */
1159 if (! attr->transit)
1160 {
1161 attr->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit));
1162 memset (attr->transit, 0, sizeof (struct transit));
1163 }
1164
1165 transit = attr->transit;
1166
1167 if (transit->val)
1168 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1169 transit->length + total);
1170 else
1171 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1172
1173 memcpy (transit->val + transit->length, startp, total);
1174 transit->length += total;
1175
1176 return 0;
1177}
1178
1179/* Read attribute of update packet. This function is called from
1180 bgp_update() in bgpd.c. */
1181int
1182bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1183 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1184{
1185 int ret;
1186 u_char flag;
1187 u_char type;
1188 bgp_size_t length;
1189 u_char *startp, *endp;
1190 u_char *attr_endp;
1191 u_char seen[BGP_ATTR_BITMAP_SIZE];
1192
1193 /* Initialize bitmap. */
1194 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1195
1196 /* End pointer of BGP attribute. */
1197 endp = BGP_INPUT_PNT (peer) + size;
1198
1199 /* Get attributes to the end of attribute length. */
1200 while (BGP_INPUT_PNT (peer) < endp)
1201 {
1202 /* Check remaining length check.*/
1203 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1204 {
gdtc29fdba2004-12-09 14:46:46 +00001205 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001206 zlog (peer->log, LOG_WARNING,
paula2b1ecd2004-10-31 18:58:09 +00001207 "%s error BGP attribute length %ld is smaller than min len",
paul718e3742002-12-13 20:15:29 +00001208 peer->host, endp - STREAM_PNT (BGP_INPUT (peer)));
1209
1210 bgp_notify_send (peer,
1211 BGP_NOTIFY_UPDATE_ERR,
1212 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1213 return -1;
1214 }
1215
1216 /* Fetch attribute flag and type. */
1217 startp = BGP_INPUT_PNT (peer);
1218 flag = stream_getc (BGP_INPUT (peer));
1219 type = stream_getc (BGP_INPUT (peer));
1220
1221 /* Check extended attribue length bit. */
1222 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1223 length = stream_getw (BGP_INPUT (peer));
1224 else
1225 length = stream_getc (BGP_INPUT (peer));
1226
1227 /* If any attribute appears more than once in the UPDATE
1228 message, then the Error Subcode is set to Malformed Attribute
1229 List. */
1230
1231 if (CHECK_BITMAP (seen, type))
1232 {
1233 zlog (peer->log, LOG_WARNING,
1234 "%s error BGP attribute type %d appears twice in a message",
1235 peer->host, type);
1236
1237 bgp_notify_send (peer,
1238 BGP_NOTIFY_UPDATE_ERR,
1239 BGP_NOTIFY_UPDATE_MAL_ATTR);
1240 return -1;
1241 }
1242
1243 /* Set type to bitmap to check duplicate attribute. `type' is
1244 unsigned char so it never overflow bitmap range. */
1245
1246 SET_BITMAP (seen, type);
1247
1248 /* Overflow check. */
1249 attr_endp = BGP_INPUT_PNT (peer) + length;
1250
1251 if (attr_endp > endp)
1252 {
1253 zlog (peer->log, LOG_WARNING,
1254 "%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);
1255 bgp_notify_send (peer,
1256 BGP_NOTIFY_UPDATE_ERR,
1257 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1258 return -1;
1259 }
1260
1261 /* OK check attribute and store it's value. */
1262 switch (type)
1263 {
1264 case BGP_ATTR_ORIGIN:
1265 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1266 break;
1267 case BGP_ATTR_AS_PATH:
1268 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
1269 break;
1270 case BGP_ATTR_NEXT_HOP:
1271 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1272 break;
1273 case BGP_ATTR_MULTI_EXIT_DISC:
1274 ret = bgp_attr_med (peer, length, attr, flag, startp);
1275 break;
1276 case BGP_ATTR_LOCAL_PREF:
1277 ret = bgp_attr_local_pref (peer, length, attr, flag);
1278 break;
1279 case BGP_ATTR_ATOMIC_AGGREGATE:
1280 ret = bgp_attr_atomic (peer, length, attr, flag);
1281 break;
1282 case BGP_ATTR_AGGREGATOR:
1283 ret = bgp_attr_aggregator (peer, length, attr, flag);
1284 break;
1285 case BGP_ATTR_COMMUNITIES:
1286 ret = bgp_attr_community (peer, length, attr, flag);
1287 break;
1288 case BGP_ATTR_ORIGINATOR_ID:
1289 ret = bgp_attr_originator_id (peer, length, attr, flag);
1290 break;
1291 case BGP_ATTR_CLUSTER_LIST:
1292 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1293 break;
1294 case BGP_ATTR_MP_REACH_NLRI:
1295 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1296 break;
1297 case BGP_ATTR_MP_UNREACH_NLRI:
1298 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1299 break;
1300 case BGP_ATTR_EXT_COMMUNITIES:
1301 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1302 break;
1303 default:
1304 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1305 break;
1306 }
1307
1308 /* If error occured immediately return to the caller. */
1309 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001310 {
1311 zlog (peer->log, LOG_WARNING,
1312 "%s: Attribute %s, parse error",
1313 peer->host,
1314 LOOKUP (attr_str, type));
1315 bgp_notify_send (peer,
1316 BGP_NOTIFY_UPDATE_ERR,
1317 BGP_NOTIFY_UPDATE_MAL_ATTR);
1318 return ret;
1319 }
paul718e3742002-12-13 20:15:29 +00001320
1321 /* Check the fetched length. */
1322 if (BGP_INPUT_PNT (peer) != attr_endp)
1323 {
1324 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001325 "%s: BGP attribute %s, fetch error",
1326 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001327 bgp_notify_send (peer,
1328 BGP_NOTIFY_UPDATE_ERR,
1329 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1330 return -1;
1331 }
1332 }
1333
1334 /* Check final read pointer is same as end pointer. */
1335 if (BGP_INPUT_PNT (peer) != endp)
1336 {
1337 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001338 "%s BGP attribute %s, length mismatch",
1339 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001340 bgp_notify_send (peer,
1341 BGP_NOTIFY_UPDATE_ERR,
1342 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1343 return -1;
1344 }
1345
1346 /* Finally intern unknown attribute. */
1347 if (attr->transit)
1348 attr->transit = transit_intern (attr->transit);
1349
1350 return 0;
1351}
1352
1353/* Well-known attribute check. */
1354int
1355bgp_attr_check (struct peer *peer, struct attr *attr)
1356{
1357 u_char type = 0;
1358
1359 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1360 type = BGP_ATTR_ORIGIN;
1361
1362 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1363 type = BGP_ATTR_AS_PATH;
1364
1365 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1366 type = BGP_ATTR_NEXT_HOP;
1367
1368 if (peer_sort (peer) == BGP_PEER_IBGP
1369 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1370 type = BGP_ATTR_LOCAL_PREF;
1371
1372 if (type)
1373 {
1374 zlog (peer->log, LOG_WARNING,
1375 "%s Missing well-known attribute %d.",
1376 peer->host, type);
1377 bgp_notify_send_with_data (peer,
1378 BGP_NOTIFY_UPDATE_ERR,
1379 BGP_NOTIFY_UPDATE_MISS_ATTR,
1380 &type, 1);
1381 return -1;
1382 }
1383 return 0;
1384}
1385
1386int stream_put_prefix (struct stream *, struct prefix *);
1387
1388/* Make attribute packet. */
1389bgp_size_t
1390bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1391 struct stream *s, struct attr *attr, struct prefix *p,
1392 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001393 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001394{
paulfe69a502005-09-10 16:55:02 +00001395 size_t cp;
1396 unsigned int aspath_data_size;
paul718e3742002-12-13 20:15:29 +00001397 struct aspath *aspath;
1398
1399 if (! bgp)
1400 bgp = bgp_get_default ();
1401
1402 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001403 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001404
1405 /* Origin attribute. */
1406 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1407 stream_putc (s, BGP_ATTR_ORIGIN);
1408 stream_putc (s, 1);
1409 stream_putc (s, attr->origin);
1410
1411 /* AS path attribute. */
1412
1413 /* If remote-peer is EBGP */
1414 if (peer_sort (peer) == BGP_PEER_EBGP
1415 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001416 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001417 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001418 {
1419 aspath = aspath_dup (attr->aspath);
1420
1421 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1422 {
1423 /* Strip the confed info, and then stuff our path CONFED_ID
1424 on the front */
1425 aspath = aspath_delete_confed_seq (aspath);
1426 aspath = aspath_add_seq (aspath, bgp->confed_id);
1427 }
1428 else
1429 {
1430 aspath = aspath_add_seq (aspath, peer->local_as);
1431 if (peer->change_local_as)
1432 aspath = aspath_add_seq (aspath, peer->change_local_as);
1433 }
1434 }
1435 else if (peer_sort (peer) == BGP_PEER_CONFED)
1436 {
1437 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1438 aspath = aspath_dup (attr->aspath);
1439 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1440 }
1441 else
1442 aspath = attr->aspath;
1443
1444 /* AS path attribute extended length bit check. */
paulfe69a502005-09-10 16:55:02 +00001445 aspath_data_size = aspath_size (aspath);
1446 if (aspath_data_size > 255)
paul718e3742002-12-13 20:15:29 +00001447 {
1448 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1449 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001450 stream_putw (s, aspath_data_size);
paul718e3742002-12-13 20:15:29 +00001451 }
1452 else
1453 {
1454 stream_putc (s, BGP_ATTR_FLAG_TRANS);
paulfe69a502005-09-10 16:55:02 +00001455 stream_putc (s, BGP_ATTR_AS_PATH);
1456 stream_putc (s, aspath_data_size);
paul718e3742002-12-13 20:15:29 +00001457 }
paulfe69a502005-09-10 16:55:02 +00001458 aspath_put (s, aspath);
paul718e3742002-12-13 20:15:29 +00001459
1460 if (aspath != attr->aspath)
1461 aspath_free (aspath);
1462
1463 /* Nexthop attribute. */
1464 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1465 {
1466 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1467 stream_putc (s, BGP_ATTR_NEXT_HOP);
1468 stream_putc (s, 4);
1469 if (safi == SAFI_MPLS_VPN)
1470 {
1471 if (attr->nexthop.s_addr == 0)
1472 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1473 else
1474 stream_put_ipv4 (s, attr->nexthop.s_addr);
1475 }
1476 else
1477 stream_put_ipv4 (s, attr->nexthop.s_addr);
1478 }
1479
1480 /* MED attribute. */
1481 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1482 {
1483 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1484 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1485 stream_putc (s, 4);
1486 stream_putl (s, attr->med);
1487 }
1488
1489 /* Local preference. */
1490 if (peer_sort (peer) == BGP_PEER_IBGP ||
1491 peer_sort (peer) == BGP_PEER_CONFED)
1492 {
1493 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1494 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1495 stream_putc (s, 4);
1496 stream_putl (s, attr->local_pref);
1497 }
1498
1499 /* Atomic aggregate. */
1500 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1501 {
1502 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1503 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1504 stream_putc (s, 0);
1505 }
1506
1507 /* Aggregator. */
1508 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1509 {
1510 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1511 stream_putc (s, BGP_ATTR_AGGREGATOR);
1512 stream_putc (s, 6);
1513 stream_putw (s, attr->aggregator_as);
1514 stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
1515 }
1516
1517 /* Community attribute. */
1518 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1519 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1520 {
1521 if (attr->community->size * 4 > 255)
1522 {
1523 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1524 stream_putc (s, BGP_ATTR_COMMUNITIES);
1525 stream_putw (s, attr->community->size * 4);
1526 }
1527 else
1528 {
1529 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1530 stream_putc (s, BGP_ATTR_COMMUNITIES);
1531 stream_putc (s, attr->community->size * 4);
1532 }
1533 stream_put (s, attr->community->val, attr->community->size * 4);
1534 }
1535
1536 /* Route Reflector. */
1537 if (peer_sort (peer) == BGP_PEER_IBGP
1538 && from
1539 && peer_sort (from) == BGP_PEER_IBGP)
1540 {
1541 /* Originator ID. */
1542 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1543 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
1544 stream_putc (s, 4);
1545
1546 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
1547 stream_put_in_addr (s, &attr->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00001548 else
1549 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00001550
1551 /* Cluster list. */
1552 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1553 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
1554
1555 if (attr->cluster)
1556 {
1557 stream_putc (s, attr->cluster->length + 4);
1558 /* If this peer configuration's parent BGP has cluster_id. */
1559 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1560 stream_put_in_addr (s, &bgp->cluster_id);
1561 else
1562 stream_put_in_addr (s, &bgp->router_id);
1563 stream_put (s, attr->cluster->list, attr->cluster->length);
1564 }
1565 else
1566 {
1567 stream_putc (s, 4);
1568 /* If this peer configuration's parent BGP has cluster_id. */
1569 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1570 stream_put_in_addr (s, &bgp->cluster_id);
1571 else
1572 stream_put_in_addr (s, &bgp->router_id);
1573 }
1574 }
1575
1576#ifdef HAVE_IPV6
1577 /* If p is IPv6 address put it into attribute. */
1578 if (p->family == AF_INET6)
1579 {
1580 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00001581
1582 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1583 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001584 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001585 stream_putc (s, 0); /* Length of this attribute. */
1586 stream_putw (s, AFI_IP6); /* AFI */
1587 stream_putc (s, safi); /* SAFI */
1588
1589 stream_putc (s, attr->mp_nexthop_len);
1590
1591 if (attr->mp_nexthop_len == 16)
1592 stream_put (s, &attr->mp_nexthop_global, 16);
1593 else if (attr->mp_nexthop_len == 32)
1594 {
1595 stream_put (s, &attr->mp_nexthop_global, 16);
1596 stream_put (s, &attr->mp_nexthop_local, 16);
1597 }
1598
1599 /* SNPA */
1600 stream_putc (s, 0);
1601
paul718e3742002-12-13 20:15:29 +00001602 /* Prefix write. */
1603 stream_put_prefix (s, p);
1604
1605 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001606 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001607 }
1608#endif /* HAVE_IPV6 */
1609
1610 if (p->family == AF_INET && safi == SAFI_MULTICAST)
1611 {
1612 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00001613
1614 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1615 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001616 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001617 stream_putc (s, 0); /* Length of this attribute. */
1618 stream_putw (s, AFI_IP); /* AFI */
1619 stream_putc (s, SAFI_MULTICAST); /* SAFI */
1620
1621 stream_putc (s, 4);
1622 stream_put_ipv4 (s, attr->nexthop.s_addr);
1623
1624 /* SNPA */
1625 stream_putc (s, 0);
1626
paul718e3742002-12-13 20:15:29 +00001627 /* Prefix write. */
1628 stream_put_prefix (s, p);
1629
1630 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001631 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001632 }
1633
1634 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
1635 {
1636 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00001637
1638 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1639 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001640 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001641 stream_putc (s, 0); /* Length of this attribute. */
1642 stream_putw (s, AFI_IP); /* AFI */
1643 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
1644
1645 stream_putc (s, 12);
1646 stream_putl (s, 0);
1647 stream_putl (s, 0);
1648 stream_put (s, &attr->mp_nexthop_global_in, 4);
1649
1650 /* SNPA */
1651 stream_putc (s, 0);
1652
paul718e3742002-12-13 20:15:29 +00001653 /* Tag, RD, Prefix write. */
1654 stream_putc (s, p->prefixlen + 88);
1655 stream_put (s, tag, 3);
1656 stream_put (s, prd->val, 8);
1657 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
1658
1659 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001660 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001661 }
1662
1663 /* Extended Communities attribute. */
1664 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
1665 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
1666 {
hasso4372df72004-05-20 10:20:02 +00001667 if (peer_sort (peer) == BGP_PEER_IBGP || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00001668 {
hasso4372df72004-05-20 10:20:02 +00001669 if (attr->ecommunity->size * 8 > 255)
1670 {
1671 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1672 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1673 stream_putw (s, attr->ecommunity->size * 8);
1674 }
1675 else
1676 {
1677 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1678 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1679 stream_putc (s, attr->ecommunity->size * 8);
1680 }
1681 stream_put (s, attr->ecommunity->val, attr->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00001682 }
1683 else
1684 {
paul5228ad22004-06-04 17:58:18 +00001685 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00001686 int tbit;
1687 int ecom_tr_size = 0;
1688 int i;
1689
1690 for (i = 0; i < attr->ecommunity->size; i++)
1691 {
1692 pnt = attr->ecommunity->val + (i * 8);
1693 tbit = *pnt;
1694
1695 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
1696 continue;
1697
1698 ecom_tr_size++;
1699 }
1700
1701 if (ecom_tr_size)
1702 {
1703 if (ecom_tr_size * 8 > 255)
1704 {
1705 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1706 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1707 stream_putw (s, ecom_tr_size * 8);
1708 }
1709 else
1710 {
1711 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1712 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1713 stream_putc (s, ecom_tr_size * 8);
1714 }
1715
1716 for (i = 0; i < attr->ecommunity->size; i++)
1717 {
1718 pnt = attr->ecommunity->val + (i * 8);
1719 tbit = *pnt;
1720
1721 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
1722 continue;
1723
1724 stream_put (s, pnt, 8);
1725 }
1726 }
paul718e3742002-12-13 20:15:29 +00001727 }
paul718e3742002-12-13 20:15:29 +00001728 }
1729
1730 /* Unknown transit attribute. */
1731 if (attr->transit)
1732 stream_put (s, attr->transit->val, attr->transit->length);
1733
1734 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00001735 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00001736}
1737
1738bgp_size_t
1739bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
1740 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001741 u_char *tag)
paul718e3742002-12-13 20:15:29 +00001742{
1743 unsigned long cp;
1744 unsigned long attrlen_pnt;
1745 bgp_size_t size;
1746
paul9985f832005-02-09 15:51:56 +00001747 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001748
1749 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1750 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
1751
paul9985f832005-02-09 15:51:56 +00001752 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001753 stream_putc (s, 0); /* Length of this attribute. */
1754
1755 stream_putw (s, family2afi (p->family));
1756
1757 if (safi == SAFI_MPLS_VPN)
1758 {
1759 /* SAFI */
1760 stream_putc (s, BGP_SAFI_VPNV4);
1761
1762 /* prefix. */
1763 stream_putc (s, p->prefixlen + 88);
1764 stream_put (s, tag, 3);
1765 stream_put (s, prd->val, 8);
1766 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
1767 }
1768 else
1769 {
1770 /* SAFI */
1771 stream_putc (s, safi);
1772
1773 /* prefix */
1774 stream_put_prefix (s, p);
1775 }
1776
1777 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001778 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00001779 stream_putc_at (s, attrlen_pnt, size);
1780
paul9985f832005-02-09 15:51:56 +00001781 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00001782}
1783
1784/* Initialization of attribute. */
1785void
paulfe69a502005-09-10 16:55:02 +00001786bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00001787{
1788 void attrhash_init ();
1789
1790 aspath_init ();
1791 attrhash_init ();
1792 community_init ();
1793 ecommunity_init ();
1794 cluster_init ();
1795 transit_init ();
1796}
1797
1798/* Make attribute packet. */
1799void
paula3845922003-10-18 01:30:50 +00001800bgp_dump_routes_attr (struct stream *s, struct attr *attr,
1801 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00001802{
1803 unsigned long cp;
1804 unsigned long len;
paulfe69a502005-09-10 16:55:02 +00001805 unsigned int aspathlen;
paul718e3742002-12-13 20:15:29 +00001806 struct aspath *aspath;
1807
1808 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001809 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001810
1811 /* Place holder of length. */
1812 stream_putw (s, 0);
1813
1814 /* Origin attribute. */
1815 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1816 stream_putc (s, BGP_ATTR_ORIGIN);
1817 stream_putc (s, 1);
1818 stream_putc (s, attr->origin);
1819
1820 aspath = attr->aspath;
1821
paulfe69a502005-09-10 16:55:02 +00001822 if ( (aspathlen = aspath_size (aspath)) > 255 )
paul718e3742002-12-13 20:15:29 +00001823 {
1824 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1825 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001826 stream_putw (s, aspathlen);
paul718e3742002-12-13 20:15:29 +00001827 }
1828 else
1829 {
1830 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1831 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001832 stream_putc (s, aspathlen);
paul718e3742002-12-13 20:15:29 +00001833 }
paulfe69a502005-09-10 16:55:02 +00001834 aspath_put (s, aspath);
paul718e3742002-12-13 20:15:29 +00001835
1836 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00001837 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
1838 if(prefix != NULL
1839#ifdef HAVE_IPV6
1840 && prefix->family != AF_INET6
1841#endif /* HAVE_IPV6 */
1842 )
1843 {
1844 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1845 stream_putc (s, BGP_ATTR_NEXT_HOP);
1846 stream_putc (s, 4);
1847 stream_put_ipv4 (s, attr->nexthop.s_addr);
1848 }
paul718e3742002-12-13 20:15:29 +00001849
1850 /* MED attribute. */
1851 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1852 {
1853 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1854 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1855 stream_putc (s, 4);
1856 stream_putl (s, attr->med);
1857 }
1858
1859 /* Local preference. */
1860 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
1861 {
1862 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1863 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1864 stream_putc (s, 4);
1865 stream_putl (s, attr->local_pref);
1866 }
1867
1868 /* Atomic aggregate. */
1869 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1870 {
1871 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1872 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1873 stream_putc (s, 0);
1874 }
1875
1876 /* Aggregator. */
1877 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1878 {
1879 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1880 stream_putc (s, BGP_ATTR_AGGREGATOR);
1881 stream_putc (s, 6);
1882 stream_putw (s, attr->aggregator_as);
1883 stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
1884 }
1885
1886 /* Community attribute. */
1887 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
1888 {
1889 if (attr->community->size * 4 > 255)
1890 {
1891 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1892 stream_putc (s, BGP_ATTR_COMMUNITIES);
1893 stream_putw (s, attr->community->size * 4);
1894 }
1895 else
1896 {
1897 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1898 stream_putc (s, BGP_ATTR_COMMUNITIES);
1899 stream_putc (s, attr->community->size * 4);
1900 }
1901 stream_put (s, attr->community->val, attr->community->size * 4);
1902 }
1903
paula3845922003-10-18 01:30:50 +00001904#ifdef HAVE_IPV6
1905 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
1906 if(prefix != NULL && prefix->family == AF_INET6 &&
1907 (attr->mp_nexthop_len == 16 || attr->mp_nexthop_len == 32) )
1908 {
1909 int sizep;
1910
1911 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
1912 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001913 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00001914
1915 /* MP header */
1916 stream_putc (s, 0); /* Length of this attribute. */
1917 stream_putw(s, AFI_IP6); /* AFI */
1918 stream_putc(s, SAFI_UNICAST); /* SAFI */
1919
1920 /* Next hop */
1921 stream_putc(s, attr->mp_nexthop_len);
1922 stream_put(s, &attr->mp_nexthop_global, 16);
1923 if(attr->mp_nexthop_len == 32)
1924 stream_put(s, &attr->mp_nexthop_local, 16);
1925
1926 /* SNPA */
1927 stream_putc(s, 0);
1928
1929 /* Prefix */
1930 stream_put_prefix(s, prefix);
1931
1932 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001933 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00001934 }
1935#endif /* HAVE_IPV6 */
1936
paul718e3742002-12-13 20:15:29 +00001937 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00001938 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00001939 stream_putw_at (s, cp, len);
1940}