blob: 9d13ca6ec90f8cf3a38b6684a507e8d998854353 [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)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001010 {
1011 attr->community = NULL;
1012 return 0;
1013 }
paul718e3742002-12-13 20:15:29 +00001014 else
1015 {
paul5228ad22004-06-04 17:58:18 +00001016 attr->community =
1017 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001018 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001019 }
1020
1021 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1022
1023 return 0;
1024}
1025
1026/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001027static int
paul718e3742002-12-13 20:15:29 +00001028bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1029 struct attr *attr, u_char flag)
1030{
1031 if (length != 4)
1032 {
1033 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1034
1035 bgp_notify_send (peer,
1036 BGP_NOTIFY_UPDATE_ERR,
1037 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1038 return -1;
1039 }
1040
Paul Jakmafb982c22007-05-04 20:15:47 +00001041 (bgp_attr_extra_get (attr))->originator_id.s_addr
1042 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001043
1044 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1045
1046 return 0;
1047}
1048
1049/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001050static int
paul718e3742002-12-13 20:15:29 +00001051bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1052 struct attr *attr, u_char flag)
1053{
1054 /* Check length. */
1055 if (length % 4)
1056 {
1057 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1058
1059 bgp_notify_send (peer,
1060 BGP_NOTIFY_UPDATE_ERR,
1061 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1062 return -1;
1063 }
1064
Paul Jakmafb982c22007-05-04 20:15:47 +00001065 (bgp_attr_extra_get (attr))->cluster
1066 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001067
paul9985f832005-02-09 15:51:56 +00001068 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001069
1070 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1071
1072 return 0;
1073}
1074
1075/* Multiprotocol reachability information parse. */
paul94f2b392005-06-28 12:44:16 +00001076static int
paul718e3742002-12-13 20:15:29 +00001077bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1078 struct bgp_nlri *mp_update)
1079{
1080 u_int16_t afi;
1081 u_char safi;
paul718e3742002-12-13 20:15:29 +00001082 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001083 size_t start;
paul718e3742002-12-13 20:15:29 +00001084 int ret;
1085 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001086 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001087
1088 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001089 s = BGP_INPUT(peer);
1090 start = stream_get_getp(s);
1091
1092 /* safe to read statically sized header? */
1093#define BGP_MP_REACH_MIN_SIZE 5
1094 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
1095 return -1;
1096
paul718e3742002-12-13 20:15:29 +00001097 /* Load AFI, SAFI. */
1098 afi = stream_getw (s);
1099 safi = stream_getc (s);
1100
1101 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001102 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001103
Paul Jakmafb982c22007-05-04 20:15:47 +00001104 if (STREAM_READABLE(s) < attre->mp_nexthop_len)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001105 return -1;
1106
paul718e3742002-12-13 20:15:29 +00001107 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001108 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001109 {
1110 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001111 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001112 break;
1113 case 12:
1114 {
1115 u_int32_t rd_high;
1116 u_int32_t rd_low;
1117
1118 rd_high = stream_getl (s);
1119 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001120 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001121 }
1122 break;
1123#ifdef HAVE_IPV6
1124 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001125 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001126 break;
1127 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001128 stream_get (&attre->mp_nexthop_global, s, 16);
1129 stream_get (&attre->mp_nexthop_local, s, 16);
1130 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001131 {
1132 char buf1[INET6_ADDRSTRLEN];
1133 char buf2[INET6_ADDRSTRLEN];
1134
1135 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001136 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 +00001137 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001138 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001139 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001140 buf2, INET6_ADDRSTRLEN));
1141
Paul Jakmafb982c22007-05-04 20:15:47 +00001142 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001143 }
1144 break;
1145#endif /* HAVE_IPV6 */
1146 default:
1147 zlog_info ("Wrong multiprotocol next hop length: %d",
Paul Jakmafb982c22007-05-04 20:15:47 +00001148 attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001149 return -1;
paul718e3742002-12-13 20:15:29 +00001150 }
1151
Paul Jakma6e4ab122007-04-10 19:36:48 +00001152 if (!STREAM_READABLE(s))
1153 return -1;
paul718e3742002-12-13 20:15:29 +00001154
Paul Jakma6e4ab122007-04-10 19:36:48 +00001155 {
1156 u_char val;
1157 if ((val = stream_getc (s)))
1158 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1159 peer->host, val);
1160 }
1161
1162 /* must have nrli_len, what is left of the attribute */
1163 nlri_len = length - (stream_get_getp(s) - start);
1164 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
1165 return -1;
paul718e3742002-12-13 20:15:29 +00001166
1167 if (safi != BGP_SAFI_VPNV4)
1168 {
1169 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
1170 if (ret < 0)
1171 return -1;
1172 }
1173
1174 mp_update->afi = afi;
1175 mp_update->safi = safi;
1176 mp_update->nlri = stream_pnt (s);
1177 mp_update->length = nlri_len;
1178
paul9985f832005-02-09 15:51:56 +00001179 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001180
1181 return 0;
1182}
1183
1184/* Multiprotocol unreachable parse */
paul94f2b392005-06-28 12:44:16 +00001185static int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001186bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001187 struct bgp_nlri *mp_withdraw)
1188{
1189 struct stream *s;
1190 u_int16_t afi;
1191 u_char safi;
paul718e3742002-12-13 20:15:29 +00001192 u_int16_t withdraw_len;
1193 int ret;
1194
1195 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001196
1197#define BGP_MP_UNREACH_MIN_SIZE 3
1198 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1199 return -1;
1200
paul718e3742002-12-13 20:15:29 +00001201 afi = stream_getw (s);
1202 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001203
1204 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001205
1206 if (safi != BGP_SAFI_VPNV4)
1207 {
1208 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1209 if (ret < 0)
1210 return -1;
1211 }
1212
1213 mp_withdraw->afi = afi;
1214 mp_withdraw->safi = safi;
1215 mp_withdraw->nlri = stream_pnt (s);
1216 mp_withdraw->length = withdraw_len;
1217
paul9985f832005-02-09 15:51:56 +00001218 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001219
1220 return 0;
1221}
1222
1223/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001224static int
paul718e3742002-12-13 20:15:29 +00001225bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1226 struct attr *attr, u_char flag)
1227{
1228 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001229 {
1230 if (attr->extra)
1231 attr->extra->ecommunity = NULL;
1232 }
paul718e3742002-12-13 20:15:29 +00001233 else
1234 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001235 (bgp_attr_extra_get (attr))->ecommunity =
paul5228ad22004-06-04 17:58:18 +00001236 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001237 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001238 }
1239 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1240
1241 return 0;
1242}
1243
1244/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001245static int
paul718e3742002-12-13 20:15:29 +00001246bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1247 u_char type, bgp_size_t length, u_char *startp)
1248{
1249 bgp_size_t total;
1250 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001251 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001252
hassof4184462005-02-01 20:13:16 +00001253 if (BGP_DEBUG (normal, NORMAL))
1254 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1255 peer->host, type, length);
1256
paul718e3742002-12-13 20:15:29 +00001257 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001258 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001259 "Unknown attribute type %d length %d is received", type, length);
1260
1261 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001262 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001263
1264 /* Adjest total length to include type and length. */
1265 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1266
1267 /* If any of the mandatory well-known attributes are not recognized,
1268 then the Error Subcode is set to Unrecognized Well-known
1269 Attribute. The Data field contains the unrecognized attribute
1270 (type, length and value). */
1271 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1272 {
1273 /* Adjust startp to do not include flag value. */
1274 bgp_notify_send_with_data (peer,
1275 BGP_NOTIFY_UPDATE_ERR,
1276 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1277 startp, total);
1278 return -1;
1279 }
1280
1281 /* Unrecognized non-transitive optional attributes must be quietly
1282 ignored and not passed along to other BGP peers. */
1283 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1284 return 0;
1285
1286 /* If a path with recognized transitive optional attribute is
1287 accepted and passed along to other BGP peers and the Partial bit
1288 in the Attribute Flags octet is set to 1 by some previous AS, it
1289 is not set back to 0 by the current AS. */
1290 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1291
1292 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001293 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
paul718e3742002-12-13 20:15:29 +00001294 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001295 attre->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit));
1296 memset (attre->transit, 0, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001297 }
1298
Paul Jakmafb982c22007-05-04 20:15:47 +00001299 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001300
1301 if (transit->val)
1302 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1303 transit->length + total);
1304 else
1305 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1306
1307 memcpy (transit->val + transit->length, startp, total);
1308 transit->length += total;
1309
1310 return 0;
1311}
1312
1313/* Read attribute of update packet. This function is called from
1314 bgp_update() in bgpd.c. */
1315int
1316bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1317 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1318{
1319 int ret;
1320 u_char flag;
1321 u_char type;
1322 bgp_size_t length;
1323 u_char *startp, *endp;
1324 u_char *attr_endp;
1325 u_char seen[BGP_ATTR_BITMAP_SIZE];
1326
1327 /* Initialize bitmap. */
1328 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1329
1330 /* End pointer of BGP attribute. */
1331 endp = BGP_INPUT_PNT (peer) + size;
1332
1333 /* Get attributes to the end of attribute length. */
1334 while (BGP_INPUT_PNT (peer) < endp)
1335 {
1336 /* Check remaining length check.*/
1337 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1338 {
gdtc29fdba2004-12-09 14:46:46 +00001339 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001340 zlog (peer->log, LOG_WARNING,
Paul Jakma41367172007-08-06 15:24:51 +00001341 "%s error BGP attribute length %lu is smaller than min len",
paul718e3742002-12-13 20:15:29 +00001342 peer->host, endp - STREAM_PNT (BGP_INPUT (peer)));
1343
1344 bgp_notify_send (peer,
1345 BGP_NOTIFY_UPDATE_ERR,
1346 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1347 return -1;
1348 }
1349
1350 /* Fetch attribute flag and type. */
1351 startp = BGP_INPUT_PNT (peer);
1352 flag = stream_getc (BGP_INPUT (peer));
1353 type = stream_getc (BGP_INPUT (peer));
1354
1355 /* Check extended attribue length bit. */
1356 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1357 length = stream_getw (BGP_INPUT (peer));
1358 else
1359 length = stream_getc (BGP_INPUT (peer));
1360
1361 /* If any attribute appears more than once in the UPDATE
1362 message, then the Error Subcode is set to Malformed Attribute
1363 List. */
1364
1365 if (CHECK_BITMAP (seen, type))
1366 {
1367 zlog (peer->log, LOG_WARNING,
1368 "%s error BGP attribute type %d appears twice in a message",
1369 peer->host, type);
1370
1371 bgp_notify_send (peer,
1372 BGP_NOTIFY_UPDATE_ERR,
1373 BGP_NOTIFY_UPDATE_MAL_ATTR);
1374 return -1;
1375 }
1376
1377 /* Set type to bitmap to check duplicate attribute. `type' is
1378 unsigned char so it never overflow bitmap range. */
1379
1380 SET_BITMAP (seen, type);
1381
1382 /* Overflow check. */
1383 attr_endp = BGP_INPUT_PNT (peer) + length;
1384
1385 if (attr_endp > endp)
1386 {
1387 zlog (peer->log, LOG_WARNING,
1388 "%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);
1389 bgp_notify_send (peer,
1390 BGP_NOTIFY_UPDATE_ERR,
1391 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1392 return -1;
1393 }
1394
1395 /* OK check attribute and store it's value. */
1396 switch (type)
1397 {
1398 case BGP_ATTR_ORIGIN:
1399 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1400 break;
1401 case BGP_ATTR_AS_PATH:
1402 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
1403 break;
1404 case BGP_ATTR_NEXT_HOP:
1405 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1406 break;
1407 case BGP_ATTR_MULTI_EXIT_DISC:
1408 ret = bgp_attr_med (peer, length, attr, flag, startp);
1409 break;
1410 case BGP_ATTR_LOCAL_PREF:
1411 ret = bgp_attr_local_pref (peer, length, attr, flag);
1412 break;
1413 case BGP_ATTR_ATOMIC_AGGREGATE:
1414 ret = bgp_attr_atomic (peer, length, attr, flag);
1415 break;
1416 case BGP_ATTR_AGGREGATOR:
1417 ret = bgp_attr_aggregator (peer, length, attr, flag);
1418 break;
1419 case BGP_ATTR_COMMUNITIES:
1420 ret = bgp_attr_community (peer, length, attr, flag);
1421 break;
1422 case BGP_ATTR_ORIGINATOR_ID:
1423 ret = bgp_attr_originator_id (peer, length, attr, flag);
1424 break;
1425 case BGP_ATTR_CLUSTER_LIST:
1426 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1427 break;
1428 case BGP_ATTR_MP_REACH_NLRI:
1429 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1430 break;
1431 case BGP_ATTR_MP_UNREACH_NLRI:
1432 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1433 break;
1434 case BGP_ATTR_EXT_COMMUNITIES:
1435 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1436 break;
Paul Jakma41367172007-08-06 15:24:51 +00001437 case BGP_ATTR_AS_PATHLIMIT:
1438 ret = bgp_attr_aspathlimit (peer, length, attr, flag, startp);
1439 break;
paul718e3742002-12-13 20:15:29 +00001440 default:
1441 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1442 break;
1443 }
1444
1445 /* If error occured immediately return to the caller. */
1446 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001447 {
1448 zlog (peer->log, LOG_WARNING,
1449 "%s: Attribute %s, parse error",
1450 peer->host,
1451 LOOKUP (attr_str, type));
1452 bgp_notify_send (peer,
1453 BGP_NOTIFY_UPDATE_ERR,
1454 BGP_NOTIFY_UPDATE_MAL_ATTR);
1455 return ret;
1456 }
paul718e3742002-12-13 20:15:29 +00001457
1458 /* Check the fetched length. */
1459 if (BGP_INPUT_PNT (peer) != attr_endp)
1460 {
1461 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001462 "%s: BGP attribute %s, fetch error",
1463 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001464 bgp_notify_send (peer,
1465 BGP_NOTIFY_UPDATE_ERR,
1466 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1467 return -1;
1468 }
1469 }
1470
1471 /* Check final read pointer is same as end pointer. */
1472 if (BGP_INPUT_PNT (peer) != endp)
1473 {
1474 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001475 "%s BGP attribute %s, length mismatch",
1476 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001477 bgp_notify_send (peer,
1478 BGP_NOTIFY_UPDATE_ERR,
1479 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1480 return -1;
1481 }
1482
1483 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001484 if (attr->extra && attr->extra->transit)
1485 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001486
1487 return 0;
1488}
1489
1490/* Well-known attribute check. */
1491int
1492bgp_attr_check (struct peer *peer, struct attr *attr)
1493{
1494 u_char type = 0;
1495
1496 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1497 type = BGP_ATTR_ORIGIN;
1498
1499 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1500 type = BGP_ATTR_AS_PATH;
1501
1502 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1503 type = BGP_ATTR_NEXT_HOP;
1504
1505 if (peer_sort (peer) == BGP_PEER_IBGP
1506 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1507 type = BGP_ATTR_LOCAL_PREF;
1508
1509 if (type)
1510 {
1511 zlog (peer->log, LOG_WARNING,
1512 "%s Missing well-known attribute %d.",
1513 peer->host, type);
1514 bgp_notify_send_with_data (peer,
1515 BGP_NOTIFY_UPDATE_ERR,
1516 BGP_NOTIFY_UPDATE_MISS_ATTR,
1517 &type, 1);
1518 return -1;
1519 }
1520 return 0;
1521}
1522
1523int stream_put_prefix (struct stream *, struct prefix *);
1524
1525/* Make attribute packet. */
1526bgp_size_t
1527bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1528 struct stream *s, struct attr *attr, struct prefix *p,
1529 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001530 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001531{
paulfe69a502005-09-10 16:55:02 +00001532 size_t cp;
1533 unsigned int aspath_data_size;
paul718e3742002-12-13 20:15:29 +00001534 struct aspath *aspath;
1535
1536 if (! bgp)
1537 bgp = bgp_get_default ();
1538
1539 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001540 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001541
1542 /* Origin attribute. */
1543 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1544 stream_putc (s, BGP_ATTR_ORIGIN);
1545 stream_putc (s, 1);
1546 stream_putc (s, attr->origin);
1547
1548 /* AS path attribute. */
1549
1550 /* If remote-peer is EBGP */
1551 if (peer_sort (peer) == BGP_PEER_EBGP
1552 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001553 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001554 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001555 {
1556 aspath = aspath_dup (attr->aspath);
1557
1558 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1559 {
1560 /* Strip the confed info, and then stuff our path CONFED_ID
1561 on the front */
1562 aspath = aspath_delete_confed_seq (aspath);
1563 aspath = aspath_add_seq (aspath, bgp->confed_id);
1564 }
1565 else
1566 {
1567 aspath = aspath_add_seq (aspath, peer->local_as);
1568 if (peer->change_local_as)
1569 aspath = aspath_add_seq (aspath, peer->change_local_as);
1570 }
1571 }
1572 else if (peer_sort (peer) == BGP_PEER_CONFED)
1573 {
1574 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1575 aspath = aspath_dup (attr->aspath);
1576 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1577 }
1578 else
1579 aspath = attr->aspath;
1580
1581 /* AS path attribute extended length bit check. */
paulfe69a502005-09-10 16:55:02 +00001582 aspath_data_size = aspath_size (aspath);
1583 if (aspath_data_size > 255)
paul718e3742002-12-13 20:15:29 +00001584 {
1585 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1586 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001587 stream_putw (s, aspath_data_size);
paul718e3742002-12-13 20:15:29 +00001588 }
1589 else
1590 {
1591 stream_putc (s, BGP_ATTR_FLAG_TRANS);
paulfe69a502005-09-10 16:55:02 +00001592 stream_putc (s, BGP_ATTR_AS_PATH);
1593 stream_putc (s, aspath_data_size);
paul718e3742002-12-13 20:15:29 +00001594 }
paulfe69a502005-09-10 16:55:02 +00001595 aspath_put (s, aspath);
paul718e3742002-12-13 20:15:29 +00001596
1597 if (aspath != attr->aspath)
1598 aspath_free (aspath);
1599
1600 /* Nexthop attribute. */
1601 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1602 {
1603 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1604 stream_putc (s, BGP_ATTR_NEXT_HOP);
1605 stream_putc (s, 4);
1606 if (safi == SAFI_MPLS_VPN)
1607 {
1608 if (attr->nexthop.s_addr == 0)
1609 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1610 else
1611 stream_put_ipv4 (s, attr->nexthop.s_addr);
1612 }
1613 else
1614 stream_put_ipv4 (s, attr->nexthop.s_addr);
1615 }
1616
1617 /* MED attribute. */
1618 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1619 {
1620 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1621 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1622 stream_putc (s, 4);
1623 stream_putl (s, attr->med);
1624 }
1625
1626 /* Local preference. */
1627 if (peer_sort (peer) == BGP_PEER_IBGP ||
1628 peer_sort (peer) == BGP_PEER_CONFED)
1629 {
1630 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1631 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1632 stream_putc (s, 4);
1633 stream_putl (s, attr->local_pref);
1634 }
1635
1636 /* Atomic aggregate. */
1637 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1638 {
1639 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1640 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1641 stream_putc (s, 0);
1642 }
1643
1644 /* Aggregator. */
1645 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1646 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001647 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00001648 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1649 stream_putc (s, BGP_ATTR_AGGREGATOR);
1650 stream_putc (s, 6);
Paul Jakmafb982c22007-05-04 20:15:47 +00001651 stream_putw (s, attr->extra->aggregator_as);
1652 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00001653 }
1654
1655 /* Community attribute. */
1656 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1657 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1658 {
1659 if (attr->community->size * 4 > 255)
1660 {
1661 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1662 stream_putc (s, BGP_ATTR_COMMUNITIES);
1663 stream_putw (s, attr->community->size * 4);
1664 }
1665 else
1666 {
1667 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1668 stream_putc (s, BGP_ATTR_COMMUNITIES);
1669 stream_putc (s, attr->community->size * 4);
1670 }
1671 stream_put (s, attr->community->val, attr->community->size * 4);
1672 }
1673
1674 /* Route Reflector. */
1675 if (peer_sort (peer) == BGP_PEER_IBGP
1676 && from
1677 && peer_sort (from) == BGP_PEER_IBGP)
1678 {
1679 /* Originator ID. */
1680 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1681 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
1682 stream_putc (s, 4);
1683
1684 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00001685 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00001686 else
1687 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00001688
1689 /* Cluster list. */
1690 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1691 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
1692
Paul Jakma9eda90c2007-08-30 13:36:17 +00001693 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00001694 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001695 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00001696 /* If this peer configuration's parent BGP has cluster_id. */
1697 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1698 stream_put_in_addr (s, &bgp->cluster_id);
1699 else
1700 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00001701 stream_put (s, attr->extra->cluster->list,
1702 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00001703 }
1704 else
1705 {
1706 stream_putc (s, 4);
1707 /* If this peer configuration's parent BGP has cluster_id. */
1708 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1709 stream_put_in_addr (s, &bgp->cluster_id);
1710 else
1711 stream_put_in_addr (s, &bgp->router_id);
1712 }
1713 }
1714
1715#ifdef HAVE_IPV6
1716 /* If p is IPv6 address put it into attribute. */
1717 if (p->family == AF_INET6)
1718 {
1719 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00001720 struct attr_extra *attre = attr->extra;
1721
1722 assert (attr->extra);
1723
paul718e3742002-12-13 20:15:29 +00001724 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1725 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001726 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001727 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00001728 stream_putw (s, AFI_IP6); /* AFI */
1729 stream_putc (s, safi); /* SAFI */
1730
Paul Jakmafb982c22007-05-04 20:15:47 +00001731 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001732
Paul Jakmafb982c22007-05-04 20:15:47 +00001733 if (attre->mp_nexthop_len == 16)
1734 stream_put (s, &attre->mp_nexthop_global, 16);
1735 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00001736 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001737 stream_put (s, &attre->mp_nexthop_global, 16);
1738 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00001739 }
1740
1741 /* SNPA */
1742 stream_putc (s, 0);
1743
paul718e3742002-12-13 20:15:29 +00001744 /* Prefix write. */
1745 stream_put_prefix (s, p);
1746
1747 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001748 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001749 }
1750#endif /* HAVE_IPV6 */
1751
1752 if (p->family == AF_INET && safi == SAFI_MULTICAST)
1753 {
1754 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00001755
1756 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1757 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001758 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001759 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00001760 stream_putw (s, AFI_IP); /* AFI */
1761 stream_putc (s, SAFI_MULTICAST); /* SAFI */
1762
1763 stream_putc (s, 4);
1764 stream_put_ipv4 (s, attr->nexthop.s_addr);
1765
1766 /* SNPA */
1767 stream_putc (s, 0);
1768
paul718e3742002-12-13 20:15:29 +00001769 /* Prefix write. */
1770 stream_put_prefix (s, p);
1771
1772 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001773 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001774 }
1775
1776 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
1777 {
1778 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00001779
1780 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1781 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001782 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001783 stream_putc (s, 0); /* Length of this attribute. */
1784 stream_putw (s, AFI_IP); /* AFI */
1785 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
1786
1787 stream_putc (s, 12);
1788 stream_putl (s, 0);
1789 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00001790 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001791
1792 /* SNPA */
1793 stream_putc (s, 0);
1794
paul718e3742002-12-13 20:15:29 +00001795 /* Tag, RD, Prefix write. */
1796 stream_putc (s, p->prefixlen + 88);
1797 stream_put (s, tag, 3);
1798 stream_put (s, prd->val, 8);
1799 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
1800
1801 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001802 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001803 }
1804
1805 /* Extended Communities attribute. */
1806 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
1807 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
1808 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001809 struct attr_extra *attre = attr->extra;
1810
1811 assert (attre);
1812
1813 if (peer_sort (peer) == BGP_PEER_IBGP
1814 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00001815 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001816 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00001817 {
1818 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1819 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00001820 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00001821 }
1822 else
1823 {
1824 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1825 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00001826 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00001827 }
Paul Jakmafb982c22007-05-04 20:15:47 +00001828 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00001829 }
1830 else
1831 {
paul5228ad22004-06-04 17:58:18 +00001832 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00001833 int tbit;
1834 int ecom_tr_size = 0;
1835 int i;
1836
Paul Jakmafb982c22007-05-04 20:15:47 +00001837 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00001838 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001839 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00001840 tbit = *pnt;
1841
1842 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
1843 continue;
1844
1845 ecom_tr_size++;
1846 }
1847
1848 if (ecom_tr_size)
1849 {
1850 if (ecom_tr_size * 8 > 255)
1851 {
1852 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1853 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1854 stream_putw (s, ecom_tr_size * 8);
1855 }
1856 else
1857 {
1858 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1859 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1860 stream_putc (s, ecom_tr_size * 8);
1861 }
1862
Paul Jakmafb982c22007-05-04 20:15:47 +00001863 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00001864 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001865 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00001866 tbit = *pnt;
1867
1868 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
1869 continue;
1870
1871 stream_put (s, pnt, 8);
1872 }
1873 }
paul718e3742002-12-13 20:15:29 +00001874 }
paul718e3742002-12-13 20:15:29 +00001875 }
Paul Jakma41367172007-08-06 15:24:51 +00001876
1877 /* AS-Pathlimit */
1878 if (attr->pathlimit.ttl)
1879 {
1880 u_int32_t as = attr->pathlimit.as;
1881
1882 /* should already have been done in announce_check(),
1883 * but just in case..
1884 */
1885 if (!as)
1886 as = peer->local_as;
1887
1888 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1889 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
1890 stream_putc (s, 5);
1891 stream_putc (s, attr->pathlimit.ttl);
1892 stream_putl (s, as);
1893 }
1894
paul718e3742002-12-13 20:15:29 +00001895 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001896 if (attr->extra && attr->extra->transit)
1897 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00001898
1899 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00001900 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00001901}
1902
1903bgp_size_t
1904bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
1905 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001906 u_char *tag)
paul718e3742002-12-13 20:15:29 +00001907{
1908 unsigned long cp;
1909 unsigned long attrlen_pnt;
1910 bgp_size_t size;
1911
paul9985f832005-02-09 15:51:56 +00001912 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001913
1914 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1915 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
1916
paul9985f832005-02-09 15:51:56 +00001917 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001918 stream_putc (s, 0); /* Length of this attribute. */
1919
1920 stream_putw (s, family2afi (p->family));
1921
1922 if (safi == SAFI_MPLS_VPN)
1923 {
1924 /* SAFI */
1925 stream_putc (s, BGP_SAFI_VPNV4);
1926
1927 /* prefix. */
1928 stream_putc (s, p->prefixlen + 88);
1929 stream_put (s, tag, 3);
1930 stream_put (s, prd->val, 8);
1931 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
1932 }
1933 else
1934 {
1935 /* SAFI */
1936 stream_putc (s, safi);
1937
1938 /* prefix */
1939 stream_put_prefix (s, p);
1940 }
1941
1942 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001943 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00001944 stream_putc_at (s, attrlen_pnt, size);
1945
paul9985f832005-02-09 15:51:56 +00001946 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00001947}
1948
1949/* Initialization of attribute. */
1950void
paulfe69a502005-09-10 16:55:02 +00001951bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00001952{
1953 void attrhash_init ();
1954
1955 aspath_init ();
1956 attrhash_init ();
1957 community_init ();
1958 ecommunity_init ();
1959 cluster_init ();
1960 transit_init ();
1961}
1962
1963/* Make attribute packet. */
1964void
paula3845922003-10-18 01:30:50 +00001965bgp_dump_routes_attr (struct stream *s, struct attr *attr,
1966 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00001967{
1968 unsigned long cp;
1969 unsigned long len;
paulfe69a502005-09-10 16:55:02 +00001970 unsigned int aspathlen;
paul718e3742002-12-13 20:15:29 +00001971 struct aspath *aspath;
1972
1973 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001974 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001975
1976 /* Place holder of length. */
1977 stream_putw (s, 0);
1978
1979 /* Origin attribute. */
1980 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1981 stream_putc (s, BGP_ATTR_ORIGIN);
1982 stream_putc (s, 1);
1983 stream_putc (s, attr->origin);
1984
1985 aspath = attr->aspath;
1986
paulfe69a502005-09-10 16:55:02 +00001987 if ( (aspathlen = aspath_size (aspath)) > 255 )
paul718e3742002-12-13 20:15:29 +00001988 {
1989 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1990 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001991 stream_putw (s, aspathlen);
paul718e3742002-12-13 20:15:29 +00001992 }
1993 else
1994 {
1995 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1996 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001997 stream_putc (s, aspathlen);
paul718e3742002-12-13 20:15:29 +00001998 }
paulfe69a502005-09-10 16:55:02 +00001999 aspath_put (s, aspath);
paul718e3742002-12-13 20:15:29 +00002000
2001 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002002 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2003 if(prefix != NULL
2004#ifdef HAVE_IPV6
2005 && prefix->family != AF_INET6
2006#endif /* HAVE_IPV6 */
2007 )
2008 {
2009 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2010 stream_putc (s, BGP_ATTR_NEXT_HOP);
2011 stream_putc (s, 4);
2012 stream_put_ipv4 (s, attr->nexthop.s_addr);
2013 }
paul718e3742002-12-13 20:15:29 +00002014
2015 /* MED attribute. */
2016 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2017 {
2018 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2019 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2020 stream_putc (s, 4);
2021 stream_putl (s, attr->med);
2022 }
2023
2024 /* Local preference. */
2025 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2026 {
2027 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2028 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2029 stream_putc (s, 4);
2030 stream_putl (s, attr->local_pref);
2031 }
2032
2033 /* Atomic aggregate. */
2034 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2035 {
2036 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2037 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2038 stream_putc (s, 0);
2039 }
2040
2041 /* Aggregator. */
2042 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2043 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002044 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002045 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2046 stream_putc (s, BGP_ATTR_AGGREGATOR);
2047 stream_putc (s, 6);
Paul Jakmafb982c22007-05-04 20:15:47 +00002048 stream_putw (s, attr->extra->aggregator_as);
2049 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002050 }
2051
2052 /* Community attribute. */
2053 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2054 {
2055 if (attr->community->size * 4 > 255)
2056 {
2057 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2058 stream_putc (s, BGP_ATTR_COMMUNITIES);
2059 stream_putw (s, attr->community->size * 4);
2060 }
2061 else
2062 {
2063 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2064 stream_putc (s, BGP_ATTR_COMMUNITIES);
2065 stream_putc (s, attr->community->size * 4);
2066 }
2067 stream_put (s, attr->community->val, attr->community->size * 4);
2068 }
2069
paula3845922003-10-18 01:30:50 +00002070#ifdef HAVE_IPV6
2071 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002072 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2073 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002074 {
2075 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002076 struct attr_extra *attre = attr->extra;
2077
paula3845922003-10-18 01:30:50 +00002078 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2079 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002080 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002081
2082 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002083 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002084 stream_putw(s, AFI_IP6); /* AFI */
2085 stream_putc(s, SAFI_UNICAST); /* SAFI */
2086
2087 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002088 stream_putc(s, attre->mp_nexthop_len);
2089 stream_put(s, &attre->mp_nexthop_global, 16);
2090 if (attre->mp_nexthop_len == 32)
2091 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002092
2093 /* SNPA */
2094 stream_putc(s, 0);
2095
2096 /* Prefix */
2097 stream_put_prefix(s, prefix);
2098
2099 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002100 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002101 }
2102#endif /* HAVE_IPV6 */
2103
Paul Jakma41367172007-08-06 15:24:51 +00002104 /* AS-Pathlimit */
2105 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT))
2106 {
2107 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2108 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2109 stream_putc (s, 5);
2110 stream_putc (s, attr->pathlimit.ttl);
2111 stream_putl (s, attr->pathlimit.as);
2112 }
2113
paul718e3742002-12-13 20:15:29 +00002114 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002115 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002116 stream_putw_at (s, cp, len);
2117}