blob: 23d958658a621fbaad8a11a8834e943dfaeaae85 [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" },
Paul Jakma41367172007-08-06 15:24:51 +000059 { BGP_ATTR_EXT_COMMUNITIES, "BGP_ATTR_EXT_COMMUNITIES" },
60 { BGP_ATTR_AS_PATHLIMIT, "BGP_ATTR_AS_PATHLIMIT" },
paul718e3742002-12-13 20:15:29 +000061 { 0, NULL }
62};
Paul Jakma6e4ab122007-04-10 19:36:48 +000063int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
paul718e3742002-12-13 20:15:29 +000064
65struct hash *cluster_hash;
66
paul94f2b392005-06-28 12:44:16 +000067static void *
Paul Jakma923de652007-04-29 18:25:17 +000068cluster_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +000069{
Paul Jakma923de652007-04-29 18:25:17 +000070 struct cluster_list * val = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +000071 struct cluster_list *cluster;
72
73 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
74 cluster->length = val->length;
75
76 if (cluster->length)
77 {
78 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
79 memcpy (cluster->list, val->list, val->length);
80 }
81 else
82 cluster->list = NULL;
83
84 cluster->refcnt = 0;
85
86 return cluster;
87}
88
89/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +000090static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +000091cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +000092{
93 struct cluster_list tmp;
94 struct cluster_list *cluster;
95
96 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +000097 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +000098
99 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
100 cluster->refcnt++;
101 return cluster;
102}
103
104int
105cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
106{
107 int i;
108
109 for (i = 0; i < cluster->length / 4; i++)
110 if (cluster->list[i].s_addr == originator.s_addr)
111 return 1;
112 return 0;
113}
114
paul94f2b392005-06-28 12:44:16 +0000115static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000116cluster_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000117{
Paul Jakma923de652007-04-29 18:25:17 +0000118 struct cluster_list * cluster = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +0000119 unsigned int key = 0;
120 int length;
121 caddr_t pnt;
122
123 length = cluster->length;
124 pnt = (caddr_t) cluster->list;
125
126 while (length)
127 key += pnt[--length];
128
129 return key;
130}
131
paul94f2b392005-06-28 12:44:16 +0000132static int
Paul Jakma923de652007-04-29 18:25:17 +0000133cluster_hash_cmp (void *p1, void *p2)
paul718e3742002-12-13 20:15:29 +0000134{
Paul Jakma923de652007-04-29 18:25:17 +0000135 struct cluster_list * cluster1 = (struct cluster_list *) p1;
136 struct cluster_list * cluster2 = (struct cluster_list *) p2;
137
paul718e3742002-12-13 20:15:29 +0000138 if (cluster1->length == cluster2->length &&
139 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0)
140 return 1;
141 return 0;
142}
143
paul94f2b392005-06-28 12:44:16 +0000144static void
paul718e3742002-12-13 20:15:29 +0000145cluster_free (struct cluster_list *cluster)
146{
147 if (cluster->list)
148 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
149 XFREE (MTYPE_CLUSTER, cluster);
150}
151
paul94f2b392005-06-28 12:44:16 +0000152static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000153cluster_dup (struct cluster_list *cluster)
154{
155 struct cluster_list *new;
156
157 new = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
158 memset (new, 0, sizeof (struct cluster_list));
159 new->length = cluster->length;
160
161 if (cluster->length)
162 {
163 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
164 memcpy (new->list, cluster->list, cluster->length);
165 }
166 else
167 new->list = NULL;
168
169 return new;
170}
171
paul94f2b392005-06-28 12:44:16 +0000172static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000173cluster_intern (struct cluster_list *cluster)
174{
175 struct cluster_list *find;
176
177 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
178 find->refcnt++;
179
180 return find;
181}
182
183void
184cluster_unintern (struct cluster_list *cluster)
185{
186 struct cluster_list *ret;
187
188 if (cluster->refcnt)
189 cluster->refcnt--;
190
191 if (cluster->refcnt == 0)
192 {
193 ret = hash_release (cluster_hash, cluster);
194 cluster_free (cluster);
195 }
196}
197
paul94f2b392005-06-28 12:44:16 +0000198static void
199cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000200{
201 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
202}
203
204/* Unknown transit attribute. */
205struct hash *transit_hash;
206
paul94f2b392005-06-28 12:44:16 +0000207static void
paul718e3742002-12-13 20:15:29 +0000208transit_free (struct transit *transit)
209{
210 if (transit->val)
211 XFREE (MTYPE_TRANSIT_VAL, transit->val);
212 XFREE (MTYPE_TRANSIT, transit);
213}
214
Paul Jakma923de652007-04-29 18:25:17 +0000215
paul94f2b392005-06-28 12:44:16 +0000216static void *
Paul Jakma923de652007-04-29 18:25:17 +0000217transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000218{
219 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000220 return p;
paul718e3742002-12-13 20:15:29 +0000221}
222
paul94f2b392005-06-28 12:44:16 +0000223static struct transit *
paul718e3742002-12-13 20:15:29 +0000224transit_intern (struct transit *transit)
225{
226 struct transit *find;
227
228 find = hash_get (transit_hash, transit, transit_hash_alloc);
229 if (find != transit)
230 transit_free (transit);
231 find->refcnt++;
232
233 return find;
234}
235
236void
237transit_unintern (struct transit *transit)
238{
239 struct transit *ret;
240
241 if (transit->refcnt)
242 transit->refcnt--;
243
244 if (transit->refcnt == 0)
245 {
246 ret = hash_release (transit_hash, transit);
247 transit_free (transit);
248 }
249}
250
paul94f2b392005-06-28 12:44:16 +0000251static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000252transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000253{
Paul Jakma923de652007-04-29 18:25:17 +0000254 struct transit * transit = (struct transit *) p;
paul718e3742002-12-13 20:15:29 +0000255 unsigned int key = 0;
256 int length;
257 caddr_t pnt;
258
259 length = transit->length;
260 pnt = (caddr_t) transit->val;
261
262 while (length)
263 key += pnt[--length];
264
265 return key;
266}
267
paul94f2b392005-06-28 12:44:16 +0000268static int
Paul Jakma923de652007-04-29 18:25:17 +0000269transit_hash_cmp (void *p1, void *p2)
paul718e3742002-12-13 20:15:29 +0000270{
Paul Jakma923de652007-04-29 18:25:17 +0000271 struct transit * transit1 = (struct transit *) p1;
272 struct transit * transit2 = (struct transit *) p2;
273
paul718e3742002-12-13 20:15:29 +0000274 if (transit1->length == transit2->length &&
275 memcmp (transit1->val, transit2->val, transit1->length) == 0)
276 return 1;
277 return 0;
278}
279
paul94f2b392005-06-28 12:44:16 +0000280static void
paul718e3742002-12-13 20:15:29 +0000281transit_init ()
282{
283 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
284}
285
286/* Attribute hash routines. */
paul718e3742002-12-13 20:15:29 +0000287struct hash *attrhash;
288
Paul Jakmafb982c22007-05-04 20:15:47 +0000289static struct attr_extra *
290bgp_attr_extra_new (void)
291{
292 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
293}
294
295void
296bgp_attr_extra_free (struct attr *attr)
297{
298 if (attr->extra)
299 {
300 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
301 attr->extra = NULL;
302 }
303}
304
305struct attr_extra *
306bgp_attr_extra_get (struct attr *attr)
307{
308 if (!attr->extra)
309 attr->extra = bgp_attr_extra_new();
310 return attr->extra;
311}
312
313/* Shallow copy of an attribute
314 * Though, not so shallow that it doesn't copy the contents
315 * of the attr_extra pointed to by 'extra'
316 */
317void
318bgp_attr_dup (struct attr *new, struct attr *orig)
319{
320 *new = *orig;
321 if (orig->extra)
322 {
323 new->extra = bgp_attr_extra_new();
324 *new->extra = *orig->extra;
325 }
326}
327
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000328unsigned long int
329attr_count (void)
330{
331 return attrhash->count;
332}
333
334unsigned long int
335attr_unknown_count (void)
336{
337 return transit_hash->count;
338}
339
paul718e3742002-12-13 20:15:29 +0000340unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000341attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000342{
Paul Jakma923de652007-04-29 18:25:17 +0000343 struct attr * attr = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000344 unsigned int key = 0;
345
346 key += attr->origin;
347 key += attr->nexthop.s_addr;
348 key += attr->med;
349 key += attr->local_pref;
Paul Jakma41367172007-08-06 15:24:51 +0000350 if (attr->pathlimit.as)
351 {
352 key += attr->pathlimit.ttl;
353 key += attr->pathlimit.as;
354 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000355
356 if (attr->extra)
357 {
358 key += attr->extra->aggregator_as;
359 key += attr->extra->aggregator_addr.s_addr;
360 key += attr->extra->weight;
361 key += attr->extra->mp_nexthop_global_in.s_addr;
362 }
363
paul718e3742002-12-13 20:15:29 +0000364 if (attr->aspath)
365 key += aspath_key_make (attr->aspath);
366 if (attr->community)
367 key += community_hash_make (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000368
369 if (attr->extra)
370 {
371 if (attr->extra->ecommunity)
372 key += ecommunity_hash_make (attr->extra->ecommunity);
373 if (attr->extra->cluster)
374 key += cluster_hash_key_make (attr->extra->cluster);
375 if (attr->extra->transit)
376 key += transit_hash_key_make (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +0000377
378#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000379 {
380 int i;
381
382 key += attr->extra->mp_nexthop_len;
383 for (i = 0; i < 16; i++)
384 key += attr->extra->mp_nexthop_global.s6_addr[i];
385 for (i = 0; i < 16; i++)
386 key += attr->extra->mp_nexthop_local.s6_addr[i];
387 }
paul718e3742002-12-13 20:15:29 +0000388#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000389 }
paul718e3742002-12-13 20:15:29 +0000390
391 return key;
392}
393
394int
Paul Jakma923de652007-04-29 18:25:17 +0000395attrhash_cmp (void *p1, void *p2)
paul718e3742002-12-13 20:15:29 +0000396{
Paul Jakma923de652007-04-29 18:25:17 +0000397 struct attr * attr1 = (struct attr *) p1;
398 struct attr * attr2 = (struct attr *) p2;
399
paul718e3742002-12-13 20:15:29 +0000400 if (attr1->flag == attr2->flag
401 && attr1->origin == attr2->origin
402 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000403 && attr1->aspath == attr2->aspath
404 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000405 && attr1->med == attr2->med
Paul Jakma41367172007-08-06 15:24:51 +0000406 && attr1->local_pref == attr2->local_pref
407 && attr1->pathlimit.ttl == attr2->pathlimit.ttl
408 && attr1->pathlimit.as == attr2->pathlimit.as)
Paul Jakmafb982c22007-05-04 20:15:47 +0000409 {
410 struct attr_extra *ae1 = attr1->extra;
411 struct attr_extra *ae2 = attr2->extra;
412
413 if (ae1 && ae2
414 && ae1->aggregator_as == ae2->aggregator_as
415 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
416 && ae1->weight == ae2->weight
417#ifdef HAVE_IPV6
418 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
419 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
420 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
421#endif /* HAVE_IPV6 */
422 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
423 && ae1->ecommunity == ae2->ecommunity
424 && ae1->cluster == ae2->cluster
425 && ae1->transit == ae2->transit)
426 return 1;
427 else if (ae1 || ae2)
428 return 0;
429 /* neither attribute has extra attributes, so they're same */
430 return 1;
431 }
paul718e3742002-12-13 20:15:29 +0000432 else
433 return 0;
434}
435
paul94f2b392005-06-28 12:44:16 +0000436static void
paul718e3742002-12-13 20:15:29 +0000437attrhash_init ()
438{
439 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
440}
441
paul94f2b392005-06-28 12:44:16 +0000442static void
paul718e3742002-12-13 20:15:29 +0000443attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
444{
445 struct attr *attr = backet->data;
446
447 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
448 inet_ntoa (attr->nexthop), VTY_NEWLINE);
449}
450
451void
452attr_show_all (struct vty *vty)
453{
454 hash_iterate (attrhash,
455 (void (*)(struct hash_backet *, void *))
456 attr_show_all_iterator,
457 vty);
458}
459
paul94f2b392005-06-28 12:44:16 +0000460static void *
Paul Jakma923de652007-04-29 18:25:17 +0000461bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000462{
Paul Jakma923de652007-04-29 18:25:17 +0000463 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000464 struct attr *attr;
465
466 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
467 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000468 if (val->extra)
469 {
470 attr->extra = bgp_attr_extra_new ();
471 *attr->extra = *val->extra;
472 }
paul718e3742002-12-13 20:15:29 +0000473 attr->refcnt = 0;
474 return attr;
475}
476
477/* Internet argument attribute. */
478struct attr *
479bgp_attr_intern (struct attr *attr)
480{
481 struct attr *find;
482
483 /* Intern referenced strucutre. */
484 if (attr->aspath)
485 {
486 if (! attr->aspath->refcnt)
487 attr->aspath = aspath_intern (attr->aspath);
488 else
489 attr->aspath->refcnt++;
490 }
491 if (attr->community)
492 {
493 if (! attr->community->refcnt)
494 attr->community = community_intern (attr->community);
495 else
496 attr->community->refcnt++;
497 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000498 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000499 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000500 struct attr_extra *attre = attr->extra;
501
502 if (attre->ecommunity)
503 {
504 if (! attre->ecommunity->refcnt)
505 attre->ecommunity = ecommunity_intern (attre->ecommunity);
506 else
507 attre->ecommunity->refcnt++;
508 }
509 if (attre->cluster)
510 {
511 if (! attre->cluster->refcnt)
512 attre->cluster = cluster_intern (attre->cluster);
513 else
514 attre->cluster->refcnt++;
515 }
516 if (attre->transit)
517 {
518 if (! attre->transit->refcnt)
519 attre->transit = transit_intern (attre->transit);
520 else
521 attre->transit->refcnt++;
522 }
paul718e3742002-12-13 20:15:29 +0000523 }
524
525 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
526 find->refcnt++;
527
528 return find;
529}
530
Paul Jakma03e214c2007-04-29 18:31:07 +0000531
paul718e3742002-12-13 20:15:29 +0000532/* Make network statement's attribute. */
533struct attr *
534bgp_attr_default_set (struct attr *attr, u_char origin)
535{
536 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000537 bgp_attr_extra_get (attr);
538
paul718e3742002-12-13 20:15:29 +0000539 attr->origin = origin;
540 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
541 attr->aspath = aspath_empty ();
542 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000543 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000544 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
545#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000546 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000547#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000548
paul718e3742002-12-13 20:15:29 +0000549 return attr;
550}
551
Paul Jakma03e214c2007-04-29 18:31:07 +0000552
paul718e3742002-12-13 20:15:29 +0000553/* Make network statement's attribute. */
554struct attr *
555bgp_attr_default_intern (u_char origin)
556{
557 struct attr attr;
558 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000559 struct attr_extra *attre;
560
561 memset (&attr, 0, sizeof (struct attr));
562 attre = bgp_attr_extra_get (&attr);
563
Paul Jakma03e214c2007-04-29 18:31:07 +0000564 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000565
566 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000567 bgp_attr_extra_free (&attr);
568
paul718e3742002-12-13 20:15:29 +0000569 aspath_unintern (new->aspath);
570 return new;
571}
572
573struct attr *
574bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
575 struct aspath *aspath,
576 struct community *community, int as_set)
577{
578 struct attr attr;
579 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000580 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000581
582 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000583 attre = bgp_attr_extra_get (&attr);
584
paul718e3742002-12-13 20:15:29 +0000585 /* Origin attribute. */
586 attr.origin = origin;
587 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
588
589 /* AS path attribute. */
590 if (aspath)
591 attr.aspath = aspath_intern (aspath);
592 else
593 attr.aspath = aspath_empty ();
594 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
595
596 /* Next hop attribute. */
597 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
598
599 if (community)
600 {
601 attr.community = community;
602 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
603 }
604
Paul Jakmafb982c22007-05-04 20:15:47 +0000605 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000606#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000607 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000608#endif
609 if (! as_set)
610 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
611 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
612 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000613 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000614 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000615 attre->aggregator_as = bgp->as;
616 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000617
618 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000619 bgp_attr_extra_free (&attr);
620
paul718e3742002-12-13 20:15:29 +0000621 aspath_unintern (new->aspath);
622 return new;
623}
624
625/* Free bgp attribute and aspath. */
626void
627bgp_attr_unintern (struct attr *attr)
628{
629 struct attr *ret;
630 struct aspath *aspath;
631 struct community *community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000632 struct ecommunity *ecommunity = NULL;
633 struct cluster_list *cluster = NULL;
634 struct transit *transit = NULL;
paul718e3742002-12-13 20:15:29 +0000635
636 /* Decrement attribute reference. */
637 attr->refcnt--;
638 aspath = attr->aspath;
639 community = attr->community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000640 if (attr->extra)
641 {
642 ecommunity = attr->extra->ecommunity;
643 cluster = attr->extra->cluster;
644 transit = attr->extra->transit;
645 }
paul718e3742002-12-13 20:15:29 +0000646
647 /* If reference becomes zero then free attribute object. */
648 if (attr->refcnt == 0)
649 {
650 ret = hash_release (attrhash, attr);
651 assert (ret != NULL);
Paul Jakmafb982c22007-05-04 20:15:47 +0000652 bgp_attr_extra_free (attr);
paul718e3742002-12-13 20:15:29 +0000653 XFREE (MTYPE_ATTR, attr);
654 }
655
656 /* aspath refcount shoud be decrement. */
657 if (aspath)
658 aspath_unintern (aspath);
659 if (community)
660 community_unintern (community);
661 if (ecommunity)
662 ecommunity_unintern (ecommunity);
663 if (cluster)
664 cluster_unintern (cluster);
665 if (transit)
666 transit_unintern (transit);
667}
668
669void
670bgp_attr_flush (struct attr *attr)
671{
672 if (attr->aspath && ! attr->aspath->refcnt)
673 aspath_free (attr->aspath);
674 if (attr->community && ! attr->community->refcnt)
675 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000676 if (attr->extra)
677 {
678 struct attr_extra *attre = attr->extra;
679 if (attre->ecommunity && ! attre->ecommunity->refcnt)
680 ecommunity_free (attre->ecommunity);
681 if (attre->cluster && ! attre->cluster->refcnt)
682 cluster_free (attre->cluster);
683 if (attre->transit && ! attre->transit->refcnt)
684 transit_free (attre->transit);
685 }
paul718e3742002-12-13 20:15:29 +0000686}
687
Paul Jakma41367172007-08-06 15:24:51 +0000688/* Parse AS_PATHLIMIT attribute in an UPDATE */
689static int
690bgp_attr_aspathlimit (struct peer *peer, bgp_size_t length,
691 struct attr *attr, u_char flag, u_char *startp)
692{
693 bgp_size_t total;
694
695 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
696
697 if (flag != (BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL))
698 {
699 zlog (peer->log, LOG_ERR,
700 "AS-Pathlimit attribute flag isn't transitive %d", flag);
701 bgp_notify_send_with_data (peer,
702 BGP_NOTIFY_UPDATE_ERR,
703 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
704 startp, total);
705 return -1;
706 }
707
708 if (length != 5)
709 {
710 zlog (peer->log, LOG_ERR,
711 "AS-Pathlimit length, %u, is not 5", length);
712 bgp_notify_send_with_data (peer,
713 BGP_NOTIFY_UPDATE_ERR,
714 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
715 startp, total);
716 return -1;
717 }
718
719 attr->pathlimit.ttl = stream_getc (BGP_INPUT(peer));
720 attr->pathlimit.as = stream_getl (BGP_INPUT(peer));
721 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT);
722 return 0;
723}
paul718e3742002-12-13 20:15:29 +0000724/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000725static int
paul718e3742002-12-13 20:15:29 +0000726bgp_attr_origin (struct peer *peer, bgp_size_t length,
727 struct attr *attr, u_char flag, u_char *startp)
728{
729 bgp_size_t total;
730
731 /* total is entire attribute length include Attribute Flags (1),
732 Attribute Type code (1) and Attribute length (1 or 2). */
733 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
734
735 /* If any recognized attribute has Attribute Flags that conflict
736 with the Attribute Type Code, then the Error Subcode is set to
737 Attribute Flags Error. The Data field contains the erroneous
738 attribute (type, length and value). */
739 if (flag != BGP_ATTR_FLAG_TRANS)
740 {
741 zlog (peer->log, LOG_ERR,
742 "Origin attribute flag isn't transitive %d", flag);
743 bgp_notify_send_with_data (peer,
744 BGP_NOTIFY_UPDATE_ERR,
745 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
746 startp, total);
747 return -1;
748 }
749
750 /* If any recognized attribute has Attribute Length that conflicts
751 with the expected length (based on the attribute type code), then
752 the Error Subcode is set to Attribute Length Error. The Data
753 field contains the erroneous attribute (type, length and
754 value). */
755 if (length != 1)
756 {
757 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
758 length);
759 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
760 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
761 startp, total);
762 return -1;
763 }
764
765 /* Fetch origin attribute. */
766 attr->origin = stream_getc (BGP_INPUT (peer));
767
768 /* If the ORIGIN attribute has an undefined value, then the Error
769 Subcode is set to Invalid Origin Attribute. The Data field
770 contains the unrecognized attribute (type, length and value). */
771 if ((attr->origin != BGP_ORIGIN_IGP)
772 && (attr->origin != BGP_ORIGIN_EGP)
773 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
774 {
775 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
776 attr->origin);
777
778 bgp_notify_send_with_data (peer,
779 BGP_NOTIFY_UPDATE_ERR,
780 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
781 startp, total);
782 return -1;
783 }
784
785 /* Set oring attribute flag. */
786 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
787
788 return 0;
789}
790
791/* Parse AS path information. This function is wrapper of
792 aspath_parse. */
paul94f2b392005-06-28 12:44:16 +0000793static int
paul718e3742002-12-13 20:15:29 +0000794bgp_attr_aspath (struct peer *peer, bgp_size_t length,
795 struct attr *attr, u_char flag, u_char *startp)
796{
797 struct bgp *bgp;
798 struct aspath *aspath;
799 bgp_size_t total;
800
801 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
802
803 /* Flag check. */
804 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
805 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
806 {
807 zlog (peer->log, LOG_ERR,
808 "Origin attribute flag isn't transitive %d", flag);
809 bgp_notify_send_with_data (peer,
810 BGP_NOTIFY_UPDATE_ERR,
811 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
812 startp, total);
813 return -1;
814 }
815
816 /* In case of IBGP, length will be zero. */
paulfe69a502005-09-10 16:55:02 +0000817 attr->aspath = aspath_parse (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000818 if (! attr->aspath)
819 {
820 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
821 bgp_notify_send (peer,
822 BGP_NOTIFY_UPDATE_ERR,
823 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
824 return -1;
825 }
826
827 bgp = peer->bgp;
828
829 /* First AS check for EBGP. */
830 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
831 {
832 if (peer_sort (peer) == BGP_PEER_EBGP
833 && ! aspath_firstas_check (attr->aspath, peer->as))
834 {
835 zlog (peer->log, LOG_ERR,
836 "%s incorrect first AS (must be %d)", peer->host, peer->as);
837 bgp_notify_send (peer,
838 BGP_NOTIFY_UPDATE_ERR,
839 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
840 return -1;
841 }
842 }
843
844 /* local-as prepend */
845 if (peer->change_local_as &&
846 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
847 {
848 aspath = aspath_dup (attr->aspath);
849 aspath = aspath_add_seq (aspath, peer->change_local_as);
850 aspath_unintern (attr->aspath);
851 attr->aspath = aspath_intern (aspath);
852 }
853
854 /* Forward pointer. */
paulfe69a502005-09-10 16:55:02 +0000855/* stream_forward_getp (peer->ibuf, length);*/
paul718e3742002-12-13 20:15:29 +0000856
857 /* Set aspath attribute flag. */
858 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
859
860 return 0;
861}
862
863/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000864static int
paul718e3742002-12-13 20:15:29 +0000865bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
866 struct attr *attr, u_char flag, u_char *startp)
867{
868 bgp_size_t total;
869
870 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
871
872 /* Flag check. */
873 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
874 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
875 {
876 zlog (peer->log, LOG_ERR,
877 "Origin attribute flag isn't transitive %d", flag);
878 bgp_notify_send_with_data (peer,
879 BGP_NOTIFY_UPDATE_ERR,
880 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
881 startp, total);
882 return -1;
883 }
884
885 /* Check nexthop attribute length. */
886 if (length != 4)
887 {
888 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
889 length);
890
891 bgp_notify_send_with_data (peer,
892 BGP_NOTIFY_UPDATE_ERR,
893 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
894 startp, total);
895 return -1;
896 }
897
898 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
899 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
900
901 return 0;
902}
903
904/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000905static int
paul718e3742002-12-13 20:15:29 +0000906bgp_attr_med (struct peer *peer, bgp_size_t length,
907 struct attr *attr, u_char flag, u_char *startp)
908{
909 bgp_size_t total;
910
911 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
912
913 /* Length check. */
914 if (length != 4)
915 {
916 zlog (peer->log, LOG_ERR,
917 "MED attribute length isn't four [%d]", length);
918
919 bgp_notify_send_with_data (peer,
920 BGP_NOTIFY_UPDATE_ERR,
921 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
922 startp, total);
923 return -1;
924 }
925
926 attr->med = stream_getl (peer->ibuf);
927
928 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
929
930 return 0;
931}
932
933/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000934static int
paul718e3742002-12-13 20:15:29 +0000935bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
936 struct attr *attr, u_char flag)
937{
938 /* If it is contained in an UPDATE message that is received from an
939 external peer, then this attribute MUST be ignored by the
940 receiving speaker. */
941 if (peer_sort (peer) == BGP_PEER_EBGP)
942 {
paul9985f832005-02-09 15:51:56 +0000943 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000944 return 0;
945 }
946
947 if (length == 4)
948 attr->local_pref = stream_getl (peer->ibuf);
949 else
950 attr->local_pref = 0;
951
952 /* Set atomic aggregate flag. */
953 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
954
955 return 0;
956}
957
958/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +0000959static int
paul718e3742002-12-13 20:15:29 +0000960bgp_attr_atomic (struct peer *peer, bgp_size_t length,
961 struct attr *attr, u_char flag)
962{
963 if (length != 0)
964 {
965 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
966
967 bgp_notify_send (peer,
968 BGP_NOTIFY_UPDATE_ERR,
969 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
970 return -1;
971 }
972
973 /* Set atomic aggregate flag. */
974 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
975
976 return 0;
977}
978
979/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +0000980static int
paul718e3742002-12-13 20:15:29 +0000981bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
982 struct attr *attr, u_char flag)
983{
Paul Jakmafb982c22007-05-04 20:15:47 +0000984 struct attr_extra *attre = bgp_attr_extra_get (attr);
985
paul718e3742002-12-13 20:15:29 +0000986 if (length != 6)
987 {
988 zlog (peer->log, LOG_ERR, "Aggregator length is not 6 [%d]", length);
989
990 bgp_notify_send (peer,
991 BGP_NOTIFY_UPDATE_ERR,
992 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
993 return -1;
994 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000995 attre->aggregator_as = stream_getw (peer->ibuf);
996 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +0000997
998 /* Set atomic aggregate flag. */
999 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1000
1001 return 0;
1002}
1003
1004/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001005static int
paul718e3742002-12-13 20:15:29 +00001006bgp_attr_community (struct peer *peer, bgp_size_t length,
1007 struct attr *attr, u_char flag)
1008{
1009 if (length == 0)
1010 attr->community = NULL;
1011 else
1012 {
paul5228ad22004-06-04 17:58:18 +00001013 attr->community =
1014 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001015 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001016 }
1017
1018 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1019
1020 return 0;
1021}
1022
1023/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001024static int
paul718e3742002-12-13 20:15:29 +00001025bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1026 struct attr *attr, u_char flag)
1027{
1028 if (length != 4)
1029 {
1030 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1031
1032 bgp_notify_send (peer,
1033 BGP_NOTIFY_UPDATE_ERR,
1034 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1035 return -1;
1036 }
1037
Paul Jakmafb982c22007-05-04 20:15:47 +00001038 (bgp_attr_extra_get (attr))->originator_id.s_addr
1039 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001040
1041 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1042
1043 return 0;
1044}
1045
1046/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001047static int
paul718e3742002-12-13 20:15:29 +00001048bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1049 struct attr *attr, u_char flag)
1050{
1051 /* Check length. */
1052 if (length % 4)
1053 {
1054 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1055
1056 bgp_notify_send (peer,
1057 BGP_NOTIFY_UPDATE_ERR,
1058 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1059 return -1;
1060 }
1061
Paul Jakmafb982c22007-05-04 20:15:47 +00001062 (bgp_attr_extra_get (attr))->cluster
1063 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001064
paul9985f832005-02-09 15:51:56 +00001065 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001066
1067 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1068
1069 return 0;
1070}
1071
1072/* Multiprotocol reachability information parse. */
paul94f2b392005-06-28 12:44:16 +00001073static int
paul718e3742002-12-13 20:15:29 +00001074bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1075 struct bgp_nlri *mp_update)
1076{
1077 u_int16_t afi;
1078 u_char safi;
paul718e3742002-12-13 20:15:29 +00001079 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001080 size_t start;
paul718e3742002-12-13 20:15:29 +00001081 int ret;
1082 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001083 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001084
1085 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001086 s = BGP_INPUT(peer);
1087 start = stream_get_getp(s);
1088
1089 /* safe to read statically sized header? */
1090#define BGP_MP_REACH_MIN_SIZE 5
1091 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
1092 return -1;
1093
paul718e3742002-12-13 20:15:29 +00001094 /* Load AFI, SAFI. */
1095 afi = stream_getw (s);
1096 safi = stream_getc (s);
1097
1098 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001099 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001100
Paul Jakmafb982c22007-05-04 20:15:47 +00001101 if (STREAM_READABLE(s) < attre->mp_nexthop_len)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001102 return -1;
1103
paul718e3742002-12-13 20:15:29 +00001104 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001105 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001106 {
1107 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001108 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001109 break;
1110 case 12:
1111 {
1112 u_int32_t rd_high;
1113 u_int32_t rd_low;
1114
1115 rd_high = stream_getl (s);
1116 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001117 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001118 }
1119 break;
1120#ifdef HAVE_IPV6
1121 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001122 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001123 break;
1124 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001125 stream_get (&attre->mp_nexthop_global, s, 16);
1126 stream_get (&attre->mp_nexthop_local, s, 16);
1127 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001128 {
1129 char buf1[INET6_ADDRSTRLEN];
1130 char buf2[INET6_ADDRSTRLEN];
1131
1132 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001133 zlog_debug ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host,
Paul Jakmafb982c22007-05-04 20:15:47 +00001134 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001135 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001136 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001137 buf2, INET6_ADDRSTRLEN));
1138
Paul Jakmafb982c22007-05-04 20:15:47 +00001139 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001140 }
1141 break;
1142#endif /* HAVE_IPV6 */
1143 default:
1144 zlog_info ("Wrong multiprotocol next hop length: %d",
Paul Jakmafb982c22007-05-04 20:15:47 +00001145 attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001146 return -1;
paul718e3742002-12-13 20:15:29 +00001147 }
1148
Paul Jakma6e4ab122007-04-10 19:36:48 +00001149 if (!STREAM_READABLE(s))
1150 return -1;
paul718e3742002-12-13 20:15:29 +00001151
Paul Jakma6e4ab122007-04-10 19:36:48 +00001152 {
1153 u_char val;
1154 if ((val = stream_getc (s)))
1155 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1156 peer->host, val);
1157 }
1158
1159 /* must have nrli_len, what is left of the attribute */
1160 nlri_len = length - (stream_get_getp(s) - start);
1161 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
1162 return -1;
paul718e3742002-12-13 20:15:29 +00001163
1164 if (safi != BGP_SAFI_VPNV4)
1165 {
1166 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
1167 if (ret < 0)
1168 return -1;
1169 }
1170
1171 mp_update->afi = afi;
1172 mp_update->safi = safi;
1173 mp_update->nlri = stream_pnt (s);
1174 mp_update->length = nlri_len;
1175
paul9985f832005-02-09 15:51:56 +00001176 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001177
1178 return 0;
1179}
1180
1181/* Multiprotocol unreachable parse */
paul94f2b392005-06-28 12:44:16 +00001182static int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001183bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001184 struct bgp_nlri *mp_withdraw)
1185{
1186 struct stream *s;
1187 u_int16_t afi;
1188 u_char safi;
paul718e3742002-12-13 20:15:29 +00001189 u_int16_t withdraw_len;
1190 int ret;
1191
1192 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001193
1194#define BGP_MP_UNREACH_MIN_SIZE 3
1195 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1196 return -1;
1197
paul718e3742002-12-13 20:15:29 +00001198 afi = stream_getw (s);
1199 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001200
1201 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001202
1203 if (safi != BGP_SAFI_VPNV4)
1204 {
1205 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1206 if (ret < 0)
1207 return -1;
1208 }
1209
1210 mp_withdraw->afi = afi;
1211 mp_withdraw->safi = safi;
1212 mp_withdraw->nlri = stream_pnt (s);
1213 mp_withdraw->length = withdraw_len;
1214
paul9985f832005-02-09 15:51:56 +00001215 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001216
1217 return 0;
1218}
1219
1220/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001221static int
paul718e3742002-12-13 20:15:29 +00001222bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1223 struct attr *attr, u_char flag)
1224{
1225 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001226 {
1227 if (attr->extra)
1228 attr->extra->ecommunity = NULL;
1229 }
paul718e3742002-12-13 20:15:29 +00001230 else
1231 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001232 (bgp_attr_extra_get (attr))->ecommunity =
paul5228ad22004-06-04 17:58:18 +00001233 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001234 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001235 }
1236 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1237
1238 return 0;
1239}
1240
1241/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001242static int
paul718e3742002-12-13 20:15:29 +00001243bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1244 u_char type, bgp_size_t length, u_char *startp)
1245{
1246 bgp_size_t total;
1247 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001248 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001249
hassof4184462005-02-01 20:13:16 +00001250 if (BGP_DEBUG (normal, NORMAL))
1251 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1252 peer->host, type, length);
1253
paul718e3742002-12-13 20:15:29 +00001254 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001255 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001256 "Unknown attribute type %d length %d is received", type, length);
1257
1258 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001259 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001260
1261 /* Adjest total length to include type and length. */
1262 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1263
1264 /* If any of the mandatory well-known attributes are not recognized,
1265 then the Error Subcode is set to Unrecognized Well-known
1266 Attribute. The Data field contains the unrecognized attribute
1267 (type, length and value). */
1268 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1269 {
1270 /* Adjust startp to do not include flag value. */
1271 bgp_notify_send_with_data (peer,
1272 BGP_NOTIFY_UPDATE_ERR,
1273 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1274 startp, total);
1275 return -1;
1276 }
1277
1278 /* Unrecognized non-transitive optional attributes must be quietly
1279 ignored and not passed along to other BGP peers. */
1280 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1281 return 0;
1282
1283 /* If a path with recognized transitive optional attribute is
1284 accepted and passed along to other BGP peers and the Partial bit
1285 in the Attribute Flags octet is set to 1 by some previous AS, it
1286 is not set back to 0 by the current AS. */
1287 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1288
1289 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001290 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
paul718e3742002-12-13 20:15:29 +00001291 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001292 attre->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit));
1293 memset (attre->transit, 0, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001294 }
1295
Paul Jakmafb982c22007-05-04 20:15:47 +00001296 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001297
1298 if (transit->val)
1299 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1300 transit->length + total);
1301 else
1302 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1303
1304 memcpy (transit->val + transit->length, startp, total);
1305 transit->length += total;
1306
1307 return 0;
1308}
1309
1310/* Read attribute of update packet. This function is called from
1311 bgp_update() in bgpd.c. */
1312int
1313bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1314 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1315{
1316 int ret;
1317 u_char flag;
1318 u_char type;
1319 bgp_size_t length;
1320 u_char *startp, *endp;
1321 u_char *attr_endp;
1322 u_char seen[BGP_ATTR_BITMAP_SIZE];
1323
1324 /* Initialize bitmap. */
1325 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1326
1327 /* End pointer of BGP attribute. */
1328 endp = BGP_INPUT_PNT (peer) + size;
1329
1330 /* Get attributes to the end of attribute length. */
1331 while (BGP_INPUT_PNT (peer) < endp)
1332 {
1333 /* Check remaining length check.*/
1334 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1335 {
gdtc29fdba2004-12-09 14:46:46 +00001336 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001337 zlog (peer->log, LOG_WARNING,
Paul Jakma41367172007-08-06 15:24:51 +00001338 "%s error BGP attribute length %lu is smaller than min len",
paul718e3742002-12-13 20:15:29 +00001339 peer->host, endp - STREAM_PNT (BGP_INPUT (peer)));
1340
1341 bgp_notify_send (peer,
1342 BGP_NOTIFY_UPDATE_ERR,
1343 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1344 return -1;
1345 }
1346
1347 /* Fetch attribute flag and type. */
1348 startp = BGP_INPUT_PNT (peer);
1349 flag = stream_getc (BGP_INPUT (peer));
1350 type = stream_getc (BGP_INPUT (peer));
1351
1352 /* Check extended attribue length bit. */
1353 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1354 length = stream_getw (BGP_INPUT (peer));
1355 else
1356 length = stream_getc (BGP_INPUT (peer));
1357
1358 /* If any attribute appears more than once in the UPDATE
1359 message, then the Error Subcode is set to Malformed Attribute
1360 List. */
1361
1362 if (CHECK_BITMAP (seen, type))
1363 {
1364 zlog (peer->log, LOG_WARNING,
1365 "%s error BGP attribute type %d appears twice in a message",
1366 peer->host, type);
1367
1368 bgp_notify_send (peer,
1369 BGP_NOTIFY_UPDATE_ERR,
1370 BGP_NOTIFY_UPDATE_MAL_ATTR);
1371 return -1;
1372 }
1373
1374 /* Set type to bitmap to check duplicate attribute. `type' is
1375 unsigned char so it never overflow bitmap range. */
1376
1377 SET_BITMAP (seen, type);
1378
1379 /* Overflow check. */
1380 attr_endp = BGP_INPUT_PNT (peer) + length;
1381
1382 if (attr_endp > endp)
1383 {
1384 zlog (peer->log, LOG_WARNING,
1385 "%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);
1386 bgp_notify_send (peer,
1387 BGP_NOTIFY_UPDATE_ERR,
1388 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1389 return -1;
1390 }
1391
1392 /* OK check attribute and store it's value. */
1393 switch (type)
1394 {
1395 case BGP_ATTR_ORIGIN:
1396 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1397 break;
1398 case BGP_ATTR_AS_PATH:
1399 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
1400 break;
1401 case BGP_ATTR_NEXT_HOP:
1402 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1403 break;
1404 case BGP_ATTR_MULTI_EXIT_DISC:
1405 ret = bgp_attr_med (peer, length, attr, flag, startp);
1406 break;
1407 case BGP_ATTR_LOCAL_PREF:
1408 ret = bgp_attr_local_pref (peer, length, attr, flag);
1409 break;
1410 case BGP_ATTR_ATOMIC_AGGREGATE:
1411 ret = bgp_attr_atomic (peer, length, attr, flag);
1412 break;
1413 case BGP_ATTR_AGGREGATOR:
1414 ret = bgp_attr_aggregator (peer, length, attr, flag);
1415 break;
1416 case BGP_ATTR_COMMUNITIES:
1417 ret = bgp_attr_community (peer, length, attr, flag);
1418 break;
1419 case BGP_ATTR_ORIGINATOR_ID:
1420 ret = bgp_attr_originator_id (peer, length, attr, flag);
1421 break;
1422 case BGP_ATTR_CLUSTER_LIST:
1423 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1424 break;
1425 case BGP_ATTR_MP_REACH_NLRI:
1426 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1427 break;
1428 case BGP_ATTR_MP_UNREACH_NLRI:
1429 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1430 break;
1431 case BGP_ATTR_EXT_COMMUNITIES:
1432 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1433 break;
Paul Jakma41367172007-08-06 15:24:51 +00001434 case BGP_ATTR_AS_PATHLIMIT:
1435 ret = bgp_attr_aspathlimit (peer, length, attr, flag, startp);
1436 break;
paul718e3742002-12-13 20:15:29 +00001437 default:
1438 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1439 break;
1440 }
1441
1442 /* If error occured immediately return to the caller. */
1443 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001444 {
1445 zlog (peer->log, LOG_WARNING,
1446 "%s: Attribute %s, parse error",
1447 peer->host,
1448 LOOKUP (attr_str, type));
1449 bgp_notify_send (peer,
1450 BGP_NOTIFY_UPDATE_ERR,
1451 BGP_NOTIFY_UPDATE_MAL_ATTR);
1452 return ret;
1453 }
paul718e3742002-12-13 20:15:29 +00001454
1455 /* Check the fetched length. */
1456 if (BGP_INPUT_PNT (peer) != attr_endp)
1457 {
1458 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001459 "%s: BGP attribute %s, fetch error",
1460 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001461 bgp_notify_send (peer,
1462 BGP_NOTIFY_UPDATE_ERR,
1463 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1464 return -1;
1465 }
1466 }
1467
1468 /* Check final read pointer is same as end pointer. */
1469 if (BGP_INPUT_PNT (peer) != endp)
1470 {
1471 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001472 "%s BGP attribute %s, length mismatch",
1473 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001474 bgp_notify_send (peer,
1475 BGP_NOTIFY_UPDATE_ERR,
1476 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1477 return -1;
1478 }
1479
1480 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001481 if (attr->extra && attr->extra->transit)
1482 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001483
1484 return 0;
1485}
1486
1487/* Well-known attribute check. */
1488int
1489bgp_attr_check (struct peer *peer, struct attr *attr)
1490{
1491 u_char type = 0;
1492
1493 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1494 type = BGP_ATTR_ORIGIN;
1495
1496 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1497 type = BGP_ATTR_AS_PATH;
1498
1499 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1500 type = BGP_ATTR_NEXT_HOP;
1501
1502 if (peer_sort (peer) == BGP_PEER_IBGP
1503 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1504 type = BGP_ATTR_LOCAL_PREF;
1505
1506 if (type)
1507 {
1508 zlog (peer->log, LOG_WARNING,
1509 "%s Missing well-known attribute %d.",
1510 peer->host, type);
1511 bgp_notify_send_with_data (peer,
1512 BGP_NOTIFY_UPDATE_ERR,
1513 BGP_NOTIFY_UPDATE_MISS_ATTR,
1514 &type, 1);
1515 return -1;
1516 }
1517 return 0;
1518}
1519
1520int stream_put_prefix (struct stream *, struct prefix *);
1521
1522/* Make attribute packet. */
1523bgp_size_t
1524bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1525 struct stream *s, struct attr *attr, struct prefix *p,
1526 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001527 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001528{
paulfe69a502005-09-10 16:55:02 +00001529 size_t cp;
1530 unsigned int aspath_data_size;
paul718e3742002-12-13 20:15:29 +00001531 struct aspath *aspath;
1532
1533 if (! bgp)
1534 bgp = bgp_get_default ();
1535
1536 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001537 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001538
1539 /* Origin attribute. */
1540 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1541 stream_putc (s, BGP_ATTR_ORIGIN);
1542 stream_putc (s, 1);
1543 stream_putc (s, attr->origin);
1544
1545 /* AS path attribute. */
1546
1547 /* If remote-peer is EBGP */
1548 if (peer_sort (peer) == BGP_PEER_EBGP
1549 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001550 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001551 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001552 {
1553 aspath = aspath_dup (attr->aspath);
1554
1555 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1556 {
1557 /* Strip the confed info, and then stuff our path CONFED_ID
1558 on the front */
1559 aspath = aspath_delete_confed_seq (aspath);
1560 aspath = aspath_add_seq (aspath, bgp->confed_id);
1561 }
1562 else
1563 {
1564 aspath = aspath_add_seq (aspath, peer->local_as);
1565 if (peer->change_local_as)
1566 aspath = aspath_add_seq (aspath, peer->change_local_as);
1567 }
1568 }
1569 else if (peer_sort (peer) == BGP_PEER_CONFED)
1570 {
1571 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1572 aspath = aspath_dup (attr->aspath);
1573 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1574 }
1575 else
1576 aspath = attr->aspath;
1577
1578 /* AS path attribute extended length bit check. */
paulfe69a502005-09-10 16:55:02 +00001579 aspath_data_size = aspath_size (aspath);
1580 if (aspath_data_size > 255)
paul718e3742002-12-13 20:15:29 +00001581 {
1582 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1583 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001584 stream_putw (s, aspath_data_size);
paul718e3742002-12-13 20:15:29 +00001585 }
1586 else
1587 {
1588 stream_putc (s, BGP_ATTR_FLAG_TRANS);
paulfe69a502005-09-10 16:55:02 +00001589 stream_putc (s, BGP_ATTR_AS_PATH);
1590 stream_putc (s, aspath_data_size);
paul718e3742002-12-13 20:15:29 +00001591 }
paulfe69a502005-09-10 16:55:02 +00001592 aspath_put (s, aspath);
paul718e3742002-12-13 20:15:29 +00001593
1594 if (aspath != attr->aspath)
1595 aspath_free (aspath);
1596
1597 /* Nexthop attribute. */
1598 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1599 {
1600 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1601 stream_putc (s, BGP_ATTR_NEXT_HOP);
1602 stream_putc (s, 4);
1603 if (safi == SAFI_MPLS_VPN)
1604 {
1605 if (attr->nexthop.s_addr == 0)
1606 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1607 else
1608 stream_put_ipv4 (s, attr->nexthop.s_addr);
1609 }
1610 else
1611 stream_put_ipv4 (s, attr->nexthop.s_addr);
1612 }
1613
1614 /* MED attribute. */
1615 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1616 {
1617 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1618 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1619 stream_putc (s, 4);
1620 stream_putl (s, attr->med);
1621 }
1622
1623 /* Local preference. */
1624 if (peer_sort (peer) == BGP_PEER_IBGP ||
1625 peer_sort (peer) == BGP_PEER_CONFED)
1626 {
1627 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1628 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1629 stream_putc (s, 4);
1630 stream_putl (s, attr->local_pref);
1631 }
1632
1633 /* Atomic aggregate. */
1634 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1635 {
1636 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1637 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1638 stream_putc (s, 0);
1639 }
1640
1641 /* Aggregator. */
1642 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1643 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001644 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00001645 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1646 stream_putc (s, BGP_ATTR_AGGREGATOR);
1647 stream_putc (s, 6);
Paul Jakmafb982c22007-05-04 20:15:47 +00001648 stream_putw (s, attr->extra->aggregator_as);
1649 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00001650 }
1651
1652 /* Community attribute. */
1653 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1654 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1655 {
1656 if (attr->community->size * 4 > 255)
1657 {
1658 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1659 stream_putc (s, BGP_ATTR_COMMUNITIES);
1660 stream_putw (s, attr->community->size * 4);
1661 }
1662 else
1663 {
1664 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1665 stream_putc (s, BGP_ATTR_COMMUNITIES);
1666 stream_putc (s, attr->community->size * 4);
1667 }
1668 stream_put (s, attr->community->val, attr->community->size * 4);
1669 }
1670
1671 /* Route Reflector. */
1672 if (peer_sort (peer) == BGP_PEER_IBGP
1673 && from
1674 && peer_sort (from) == BGP_PEER_IBGP)
1675 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001676 assert (attr->extra);
1677
paul718e3742002-12-13 20:15:29 +00001678 /* Originator ID. */
1679 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1680 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
1681 stream_putc (s, 4);
1682
1683 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00001684 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00001685 else
1686 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00001687
1688 /* Cluster list. */
1689 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1690 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
1691
Paul Jakmafb982c22007-05-04 20:15:47 +00001692 if (attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00001693 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001694 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00001695 /* If this peer configuration's parent BGP has cluster_id. */
1696 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1697 stream_put_in_addr (s, &bgp->cluster_id);
1698 else
1699 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00001700 stream_put (s, attr->extra->cluster->list,
1701 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00001702 }
1703 else
1704 {
1705 stream_putc (s, 4);
1706 /* If this peer configuration's parent BGP has cluster_id. */
1707 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1708 stream_put_in_addr (s, &bgp->cluster_id);
1709 else
1710 stream_put_in_addr (s, &bgp->router_id);
1711 }
1712 }
1713
1714#ifdef HAVE_IPV6
1715 /* If p is IPv6 address put it into attribute. */
1716 if (p->family == AF_INET6)
1717 {
1718 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00001719 struct attr_extra *attre = attr->extra;
1720
1721 assert (attr->extra);
1722
paul718e3742002-12-13 20:15:29 +00001723 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1724 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001725 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001726 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00001727 stream_putw (s, AFI_IP6); /* AFI */
1728 stream_putc (s, safi); /* SAFI */
1729
Paul Jakmafb982c22007-05-04 20:15:47 +00001730 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001731
Paul Jakmafb982c22007-05-04 20:15:47 +00001732 if (attre->mp_nexthop_len == 16)
1733 stream_put (s, &attre->mp_nexthop_global, 16);
1734 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00001735 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001736 stream_put (s, &attre->mp_nexthop_global, 16);
1737 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00001738 }
1739
1740 /* SNPA */
1741 stream_putc (s, 0);
1742
paul718e3742002-12-13 20:15:29 +00001743 /* Prefix write. */
1744 stream_put_prefix (s, p);
1745
1746 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001747 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001748 }
1749#endif /* HAVE_IPV6 */
1750
1751 if (p->family == AF_INET && safi == SAFI_MULTICAST)
1752 {
1753 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00001754
1755 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1756 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001757 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001758 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00001759 stream_putw (s, AFI_IP); /* AFI */
1760 stream_putc (s, SAFI_MULTICAST); /* SAFI */
1761
1762 stream_putc (s, 4);
1763 stream_put_ipv4 (s, attr->nexthop.s_addr);
1764
1765 /* SNPA */
1766 stream_putc (s, 0);
1767
paul718e3742002-12-13 20:15:29 +00001768 /* Prefix write. */
1769 stream_put_prefix (s, p);
1770
1771 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001772 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001773 }
1774
1775 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
1776 {
1777 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00001778
1779 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1780 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001781 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001782 stream_putc (s, 0); /* Length of this attribute. */
1783 stream_putw (s, AFI_IP); /* AFI */
1784 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
1785
1786 stream_putc (s, 12);
1787 stream_putl (s, 0);
1788 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00001789 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001790
1791 /* SNPA */
1792 stream_putc (s, 0);
1793
paul718e3742002-12-13 20:15:29 +00001794 /* Tag, RD, Prefix write. */
1795 stream_putc (s, p->prefixlen + 88);
1796 stream_put (s, tag, 3);
1797 stream_put (s, prd->val, 8);
1798 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
1799
1800 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001801 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001802 }
1803
1804 /* Extended Communities attribute. */
1805 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
1806 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
1807 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001808 struct attr_extra *attre = attr->extra;
1809
1810 assert (attre);
1811
1812 if (peer_sort (peer) == BGP_PEER_IBGP
1813 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00001814 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001815 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00001816 {
1817 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1818 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00001819 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00001820 }
1821 else
1822 {
1823 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1824 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00001825 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00001826 }
Paul Jakmafb982c22007-05-04 20:15:47 +00001827 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00001828 }
1829 else
1830 {
paul5228ad22004-06-04 17:58:18 +00001831 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00001832 int tbit;
1833 int ecom_tr_size = 0;
1834 int i;
1835
Paul Jakmafb982c22007-05-04 20:15:47 +00001836 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00001837 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001838 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00001839 tbit = *pnt;
1840
1841 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
1842 continue;
1843
1844 ecom_tr_size++;
1845 }
1846
1847 if (ecom_tr_size)
1848 {
1849 if (ecom_tr_size * 8 > 255)
1850 {
1851 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1852 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1853 stream_putw (s, ecom_tr_size * 8);
1854 }
1855 else
1856 {
1857 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1858 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1859 stream_putc (s, ecom_tr_size * 8);
1860 }
1861
Paul Jakmafb982c22007-05-04 20:15:47 +00001862 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00001863 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001864 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00001865 tbit = *pnt;
1866
1867 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
1868 continue;
1869
1870 stream_put (s, pnt, 8);
1871 }
1872 }
paul718e3742002-12-13 20:15:29 +00001873 }
paul718e3742002-12-13 20:15:29 +00001874 }
Paul Jakma41367172007-08-06 15:24:51 +00001875
1876 /* AS-Pathlimit */
1877 if (attr->pathlimit.ttl)
1878 {
1879 u_int32_t as = attr->pathlimit.as;
1880
1881 /* should already have been done in announce_check(),
1882 * but just in case..
1883 */
1884 if (!as)
1885 as = peer->local_as;
1886
1887 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1888 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
1889 stream_putc (s, 5);
1890 stream_putc (s, attr->pathlimit.ttl);
1891 stream_putl (s, as);
1892 }
1893
paul718e3742002-12-13 20:15:29 +00001894 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001895 if (attr->extra && attr->extra->transit)
1896 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00001897
1898 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00001899 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00001900}
1901
1902bgp_size_t
1903bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
1904 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001905 u_char *tag)
paul718e3742002-12-13 20:15:29 +00001906{
1907 unsigned long cp;
1908 unsigned long attrlen_pnt;
1909 bgp_size_t size;
1910
paul9985f832005-02-09 15:51:56 +00001911 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001912
1913 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1914 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
1915
paul9985f832005-02-09 15:51:56 +00001916 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001917 stream_putc (s, 0); /* Length of this attribute. */
1918
1919 stream_putw (s, family2afi (p->family));
1920
1921 if (safi == SAFI_MPLS_VPN)
1922 {
1923 /* SAFI */
1924 stream_putc (s, BGP_SAFI_VPNV4);
1925
1926 /* prefix. */
1927 stream_putc (s, p->prefixlen + 88);
1928 stream_put (s, tag, 3);
1929 stream_put (s, prd->val, 8);
1930 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
1931 }
1932 else
1933 {
1934 /* SAFI */
1935 stream_putc (s, safi);
1936
1937 /* prefix */
1938 stream_put_prefix (s, p);
1939 }
1940
1941 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001942 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00001943 stream_putc_at (s, attrlen_pnt, size);
1944
paul9985f832005-02-09 15:51:56 +00001945 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00001946}
1947
1948/* Initialization of attribute. */
1949void
paulfe69a502005-09-10 16:55:02 +00001950bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00001951{
1952 void attrhash_init ();
1953
1954 aspath_init ();
1955 attrhash_init ();
1956 community_init ();
1957 ecommunity_init ();
1958 cluster_init ();
1959 transit_init ();
1960}
1961
1962/* Make attribute packet. */
1963void
paula3845922003-10-18 01:30:50 +00001964bgp_dump_routes_attr (struct stream *s, struct attr *attr,
1965 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00001966{
1967 unsigned long cp;
1968 unsigned long len;
paulfe69a502005-09-10 16:55:02 +00001969 unsigned int aspathlen;
paul718e3742002-12-13 20:15:29 +00001970 struct aspath *aspath;
1971
1972 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001973 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001974
1975 /* Place holder of length. */
1976 stream_putw (s, 0);
1977
1978 /* Origin attribute. */
1979 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1980 stream_putc (s, BGP_ATTR_ORIGIN);
1981 stream_putc (s, 1);
1982 stream_putc (s, attr->origin);
1983
1984 aspath = attr->aspath;
1985
paulfe69a502005-09-10 16:55:02 +00001986 if ( (aspathlen = aspath_size (aspath)) > 255 )
paul718e3742002-12-13 20:15:29 +00001987 {
1988 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1989 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001990 stream_putw (s, aspathlen);
paul718e3742002-12-13 20:15:29 +00001991 }
1992 else
1993 {
1994 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1995 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001996 stream_putc (s, aspathlen);
paul718e3742002-12-13 20:15:29 +00001997 }
paulfe69a502005-09-10 16:55:02 +00001998 aspath_put (s, aspath);
paul718e3742002-12-13 20:15:29 +00001999
2000 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002001 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2002 if(prefix != NULL
2003#ifdef HAVE_IPV6
2004 && prefix->family != AF_INET6
2005#endif /* HAVE_IPV6 */
2006 )
2007 {
2008 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2009 stream_putc (s, BGP_ATTR_NEXT_HOP);
2010 stream_putc (s, 4);
2011 stream_put_ipv4 (s, attr->nexthop.s_addr);
2012 }
paul718e3742002-12-13 20:15:29 +00002013
2014 /* MED attribute. */
2015 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2016 {
2017 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2018 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2019 stream_putc (s, 4);
2020 stream_putl (s, attr->med);
2021 }
2022
2023 /* Local preference. */
2024 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2025 {
2026 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2027 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2028 stream_putc (s, 4);
2029 stream_putl (s, attr->local_pref);
2030 }
2031
2032 /* Atomic aggregate. */
2033 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2034 {
2035 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2036 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2037 stream_putc (s, 0);
2038 }
2039
2040 /* Aggregator. */
2041 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2042 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002043 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002044 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2045 stream_putc (s, BGP_ATTR_AGGREGATOR);
2046 stream_putc (s, 6);
Paul Jakmafb982c22007-05-04 20:15:47 +00002047 stream_putw (s, attr->extra->aggregator_as);
2048 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002049 }
2050
2051 /* Community attribute. */
2052 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2053 {
2054 if (attr->community->size * 4 > 255)
2055 {
2056 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2057 stream_putc (s, BGP_ATTR_COMMUNITIES);
2058 stream_putw (s, attr->community->size * 4);
2059 }
2060 else
2061 {
2062 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2063 stream_putc (s, BGP_ATTR_COMMUNITIES);
2064 stream_putc (s, attr->community->size * 4);
2065 }
2066 stream_put (s, attr->community->val, attr->community->size * 4);
2067 }
2068
paula3845922003-10-18 01:30:50 +00002069#ifdef HAVE_IPV6
2070 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002071 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2072 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002073 {
2074 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002075 struct attr_extra *attre = attr->extra;
2076
paula3845922003-10-18 01:30:50 +00002077 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2078 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002079 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002080
2081 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002082 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002083 stream_putw(s, AFI_IP6); /* AFI */
2084 stream_putc(s, SAFI_UNICAST); /* SAFI */
2085
2086 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002087 stream_putc(s, attre->mp_nexthop_len);
2088 stream_put(s, &attre->mp_nexthop_global, 16);
2089 if (attre->mp_nexthop_len == 32)
2090 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002091
2092 /* SNPA */
2093 stream_putc(s, 0);
2094
2095 /* Prefix */
2096 stream_put_prefix(s, prefix);
2097
2098 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002099 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002100 }
2101#endif /* HAVE_IPV6 */
2102
Paul Jakma41367172007-08-06 15:24:51 +00002103 /* AS-Pathlimit */
2104 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT))
2105 {
2106 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2107 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2108 stream_putc (s, 5);
2109 stream_putc (s, attr->pathlimit.ttl);
2110 stream_putl (s, attr->pathlimit.as);
2111 }
2112
paul718e3742002-12-13 20:15:29 +00002113 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002114 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002115 stream_putw_at (s, cp, len);
2116}