blob: 28f01609cb1c8f7c8a4403382f98911fb5ae3534 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* BGP attributes management routines.
2 Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
20
21#include <zebra.h>
22
23#include "linklist.h"
24#include "prefix.h"
25#include "memory.h"
26#include "vector.h"
27#include "vty.h"
28#include "stream.h"
29#include "log.h"
30#include "hash.h"
31
32#include "bgpd/bgpd.h"
33#include "bgpd/bgp_attr.h"
34#include "bgpd/bgp_route.h"
35#include "bgpd/bgp_aspath.h"
36#include "bgpd/bgp_community.h"
37#include "bgpd/bgp_debug.h"
38#include "bgpd/bgp_packet.h"
39#include "bgpd/bgp_ecommunity.h"
40
41/* Attribute strings for logging. */
Paul Jakma6e4ab122007-04-10 19:36:48 +000042static struct message attr_str [] =
paul718e3742002-12-13 20:15:29 +000043{
44 { BGP_ATTR_ORIGIN, "ORIGIN" },
45 { BGP_ATTR_AS_PATH, "AS_PATH" },
46 { BGP_ATTR_NEXT_HOP, "NEXT_HOP" },
47 { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
48 { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" },
49 { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
50 { BGP_ATTR_AGGREGATOR, "AGGREGATOR" },
51 { BGP_ATTR_COMMUNITIES, "COMMUNITY" },
52 { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" },
53 { BGP_ATTR_CLUSTER_LIST, "CLUSTERLIST" },
54 { BGP_ATTR_DPA, "DPA" },
55 { BGP_ATTR_ADVERTISER, "ADVERTISER"} ,
56 { BGP_ATTR_RCID_PATH, "RCID_PATH" },
57 { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
58 { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
59 { 0, NULL }
60};
Paul Jakma6e4ab122007-04-10 19:36:48 +000061int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
paul718e3742002-12-13 20:15:29 +000062
63struct hash *cluster_hash;
64
paul94f2b392005-06-28 12:44:16 +000065static void *
Paul Jakma923de652007-04-29 18:25:17 +000066cluster_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +000067{
Paul Jakma923de652007-04-29 18:25:17 +000068 struct cluster_list * val = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +000069 struct cluster_list *cluster;
70
71 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
72 cluster->length = val->length;
73
74 if (cluster->length)
75 {
76 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
77 memcpy (cluster->list, val->list, val->length);
78 }
79 else
80 cluster->list = NULL;
81
82 cluster->refcnt = 0;
83
84 return cluster;
85}
86
87/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +000088static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +000089cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +000090{
91 struct cluster_list tmp;
92 struct cluster_list *cluster;
93
94 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +000095 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +000096
97 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
98 cluster->refcnt++;
99 return cluster;
100}
101
102int
103cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
104{
105 int i;
106
107 for (i = 0; i < cluster->length / 4; i++)
108 if (cluster->list[i].s_addr == originator.s_addr)
109 return 1;
110 return 0;
111}
112
paul94f2b392005-06-28 12:44:16 +0000113static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000114cluster_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000115{
Paul Jakma923de652007-04-29 18:25:17 +0000116 struct cluster_list * cluster = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +0000117 unsigned int key = 0;
118 int length;
119 caddr_t pnt;
120
121 length = cluster->length;
122 pnt = (caddr_t) cluster->list;
123
124 while (length)
125 key += pnt[--length];
126
127 return key;
128}
129
paul94f2b392005-06-28 12:44:16 +0000130static int
Paul Jakma923de652007-04-29 18:25:17 +0000131cluster_hash_cmp (void *p1, void *p2)
paul718e3742002-12-13 20:15:29 +0000132{
Paul Jakma923de652007-04-29 18:25:17 +0000133 struct cluster_list * cluster1 = (struct cluster_list *) p1;
134 struct cluster_list * cluster2 = (struct cluster_list *) p2;
135
paul718e3742002-12-13 20:15:29 +0000136 if (cluster1->length == cluster2->length &&
137 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0)
138 return 1;
139 return 0;
140}
141
paul94f2b392005-06-28 12:44:16 +0000142static void
paul718e3742002-12-13 20:15:29 +0000143cluster_free (struct cluster_list *cluster)
144{
145 if (cluster->list)
146 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
147 XFREE (MTYPE_CLUSTER, cluster);
148}
149
paul94f2b392005-06-28 12:44:16 +0000150static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000151cluster_dup (struct cluster_list *cluster)
152{
153 struct cluster_list *new;
154
155 new = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
156 memset (new, 0, sizeof (struct cluster_list));
157 new->length = cluster->length;
158
159 if (cluster->length)
160 {
161 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
162 memcpy (new->list, cluster->list, cluster->length);
163 }
164 else
165 new->list = NULL;
166
167 return new;
168}
169
paul94f2b392005-06-28 12:44:16 +0000170static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000171cluster_intern (struct cluster_list *cluster)
172{
173 struct cluster_list *find;
174
175 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
176 find->refcnt++;
177
178 return find;
179}
180
181void
182cluster_unintern (struct cluster_list *cluster)
183{
184 struct cluster_list *ret;
185
186 if (cluster->refcnt)
187 cluster->refcnt--;
188
189 if (cluster->refcnt == 0)
190 {
191 ret = hash_release (cluster_hash, cluster);
192 cluster_free (cluster);
193 }
194}
195
paul94f2b392005-06-28 12:44:16 +0000196static void
197cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000198{
199 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
200}
201
202/* Unknown transit attribute. */
203struct hash *transit_hash;
204
paul94f2b392005-06-28 12:44:16 +0000205static void
paul718e3742002-12-13 20:15:29 +0000206transit_free (struct transit *transit)
207{
208 if (transit->val)
209 XFREE (MTYPE_TRANSIT_VAL, transit->val);
210 XFREE (MTYPE_TRANSIT, transit);
211}
212
Paul Jakma923de652007-04-29 18:25:17 +0000213
paul94f2b392005-06-28 12:44:16 +0000214static void *
Paul Jakma923de652007-04-29 18:25:17 +0000215transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000216{
217 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000218 return p;
paul718e3742002-12-13 20:15:29 +0000219}
220
paul94f2b392005-06-28 12:44:16 +0000221static struct transit *
paul718e3742002-12-13 20:15:29 +0000222transit_intern (struct transit *transit)
223{
224 struct transit *find;
225
226 find = hash_get (transit_hash, transit, transit_hash_alloc);
227 if (find != transit)
228 transit_free (transit);
229 find->refcnt++;
230
231 return find;
232}
233
234void
235transit_unintern (struct transit *transit)
236{
237 struct transit *ret;
238
239 if (transit->refcnt)
240 transit->refcnt--;
241
242 if (transit->refcnt == 0)
243 {
244 ret = hash_release (transit_hash, transit);
245 transit_free (transit);
246 }
247}
248
paul94f2b392005-06-28 12:44:16 +0000249static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000250transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000251{
Paul Jakma923de652007-04-29 18:25:17 +0000252 struct transit * transit = (struct transit *) p;
paul718e3742002-12-13 20:15:29 +0000253 unsigned int key = 0;
254 int length;
255 caddr_t pnt;
256
257 length = transit->length;
258 pnt = (caddr_t) transit->val;
259
260 while (length)
261 key += pnt[--length];
262
263 return key;
264}
265
paul94f2b392005-06-28 12:44:16 +0000266static int
Paul Jakma923de652007-04-29 18:25:17 +0000267transit_hash_cmp (void *p1, void *p2)
paul718e3742002-12-13 20:15:29 +0000268{
Paul Jakma923de652007-04-29 18:25:17 +0000269 struct transit * transit1 = (struct transit *) p1;
270 struct transit * transit2 = (struct transit *) p2;
271
paul718e3742002-12-13 20:15:29 +0000272 if (transit1->length == transit2->length &&
273 memcmp (transit1->val, transit2->val, transit1->length) == 0)
274 return 1;
275 return 0;
276}
277
paul94f2b392005-06-28 12:44:16 +0000278static void
paul718e3742002-12-13 20:15:29 +0000279transit_init ()
280{
281 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
282}
283
284/* Attribute hash routines. */
285
286struct hash *attrhash;
287
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000288unsigned long int
289attr_count (void)
290{
291 return attrhash->count;
292}
293
294unsigned long int
295attr_unknown_count (void)
296{
297 return transit_hash->count;
298}
299
paul718e3742002-12-13 20:15:29 +0000300unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000301attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000302{
Paul Jakma923de652007-04-29 18:25:17 +0000303 struct attr * attr = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000304 unsigned int key = 0;
305
306 key += attr->origin;
307 key += attr->nexthop.s_addr;
308 key += attr->med;
309 key += attr->local_pref;
310 key += attr->aggregator_as;
311 key += attr->aggregator_addr.s_addr;
312 key += attr->weight;
313
314 key += attr->mp_nexthop_global_in.s_addr;
315 if (attr->aspath)
316 key += aspath_key_make (attr->aspath);
317 if (attr->community)
318 key += community_hash_make (attr->community);
319 if (attr->ecommunity)
320 key += ecommunity_hash_make (attr->ecommunity);
321 if (attr->cluster)
322 key += cluster_hash_key_make (attr->cluster);
323 if (attr->transit)
324 key += transit_hash_key_make (attr->transit);
325
326#ifdef HAVE_IPV6
327 {
328 int i;
329
330 key += attr->mp_nexthop_len;
331 for (i = 0; i < 16; i++)
332 key += attr->mp_nexthop_global.s6_addr[i];
333 for (i = 0; i < 16; i++)
334 key += attr->mp_nexthop_local.s6_addr[i];
335 }
336#endif /* HAVE_IPV6 */
337
338 return key;
339}
340
341int
Paul Jakma923de652007-04-29 18:25:17 +0000342attrhash_cmp (void *p1, void *p2)
paul718e3742002-12-13 20:15:29 +0000343{
Paul Jakma923de652007-04-29 18:25:17 +0000344 struct attr * attr1 = (struct attr *) p1;
345 struct attr * attr2 = (struct attr *) p2;
346
paul718e3742002-12-13 20:15:29 +0000347 if (attr1->flag == attr2->flag
348 && attr1->origin == attr2->origin
349 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
350 && attr1->med == attr2->med
351 && attr1->local_pref == attr2->local_pref
352 && attr1->aggregator_as == attr2->aggregator_as
353 && attr1->aggregator_addr.s_addr == attr2->aggregator_addr.s_addr
354 && attr1->weight == attr2->weight
355#ifdef HAVE_IPV6
356 && attr1->mp_nexthop_len == attr2->mp_nexthop_len
357 && IPV6_ADDR_SAME (&attr1->mp_nexthop_global, &attr2->mp_nexthop_global)
358 && IPV6_ADDR_SAME (&attr1->mp_nexthop_local, &attr2->mp_nexthop_local)
359#endif /* HAVE_IPV6 */
360 && IPV4_ADDR_SAME (&attr1->mp_nexthop_global_in, &attr2->mp_nexthop_global_in)
361 && attr1->aspath == attr2->aspath
362 && attr1->community == attr2->community
363 && attr1->ecommunity == attr2->ecommunity
364 && attr1->cluster == attr2->cluster
365 && attr1->transit == attr2->transit)
366 return 1;
367 else
368 return 0;
369}
370
paul94f2b392005-06-28 12:44:16 +0000371static void
paul718e3742002-12-13 20:15:29 +0000372attrhash_init ()
373{
374 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
375}
376
paul94f2b392005-06-28 12:44:16 +0000377static void
paul718e3742002-12-13 20:15:29 +0000378attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
379{
380 struct attr *attr = backet->data;
381
382 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
383 inet_ntoa (attr->nexthop), VTY_NEWLINE);
384}
385
386void
387attr_show_all (struct vty *vty)
388{
389 hash_iterate (attrhash,
390 (void (*)(struct hash_backet *, void *))
391 attr_show_all_iterator,
392 vty);
393}
394
paul94f2b392005-06-28 12:44:16 +0000395static void *
Paul Jakma923de652007-04-29 18:25:17 +0000396bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000397{
Paul Jakma923de652007-04-29 18:25:17 +0000398 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000399 struct attr *attr;
400
401 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
402 *attr = *val;
403 attr->refcnt = 0;
404 return attr;
405}
406
407/* Internet argument attribute. */
408struct attr *
409bgp_attr_intern (struct attr *attr)
410{
411 struct attr *find;
412
413 /* Intern referenced strucutre. */
414 if (attr->aspath)
415 {
416 if (! attr->aspath->refcnt)
417 attr->aspath = aspath_intern (attr->aspath);
418 else
419 attr->aspath->refcnt++;
420 }
421 if (attr->community)
422 {
423 if (! attr->community->refcnt)
424 attr->community = community_intern (attr->community);
425 else
426 attr->community->refcnt++;
427 }
428 if (attr->ecommunity)
429 {
430 if (! attr->ecommunity->refcnt)
431 attr->ecommunity = ecommunity_intern (attr->ecommunity);
432 else
433 attr->ecommunity->refcnt++;
434 }
435 if (attr->cluster)
436 {
437 if (! attr->cluster->refcnt)
438 attr->cluster = cluster_intern (attr->cluster);
439 else
440 attr->cluster->refcnt++;
441 }
442 if (attr->transit)
443 {
444 if (! attr->transit->refcnt)
445 attr->transit = transit_intern (attr->transit);
446 else
447 attr->transit->refcnt++;
448 }
449
450 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
451 find->refcnt++;
452
453 return find;
454}
455
Paul Jakma03e214c2007-04-29 18:31:07 +0000456
paul718e3742002-12-13 20:15:29 +0000457/* Make network statement's attribute. */
458struct attr *
459bgp_attr_default_set (struct attr *attr, u_char origin)
460{
461 memset (attr, 0, sizeof (struct attr));
462
463 attr->origin = origin;
464 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
465 attr->aspath = aspath_empty ();
466 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakma03e214c2007-04-29 18:31:07 +0000467 attr->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000468 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
469#ifdef HAVE_IPV6
Paul Jakma03e214c2007-04-29 18:31:07 +0000470 attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000471#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000472
paul718e3742002-12-13 20:15:29 +0000473 return attr;
474}
475
Paul Jakma03e214c2007-04-29 18:31:07 +0000476
paul718e3742002-12-13 20:15:29 +0000477/* Make network statement's attribute. */
478struct attr *
479bgp_attr_default_intern (u_char origin)
480{
481 struct attr attr;
482 struct attr *new;
483
Paul Jakma03e214c2007-04-29 18:31:07 +0000484 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000485
486 new = bgp_attr_intern (&attr);
487 aspath_unintern (new->aspath);
488 return new;
489}
490
491struct attr *
492bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
493 struct aspath *aspath,
494 struct community *community, int as_set)
495{
496 struct attr attr;
497 struct attr *new;
498
499 memset (&attr, 0, sizeof (struct attr));
500
501 /* Origin attribute. */
502 attr.origin = origin;
503 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
504
505 /* AS path attribute. */
506 if (aspath)
507 attr.aspath = aspath_intern (aspath);
508 else
509 attr.aspath = aspath_empty ();
510 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
511
512 /* Next hop attribute. */
513 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
514
515 if (community)
516 {
517 attr.community = community;
518 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
519 }
520
Paul Jakma03e214c2007-04-29 18:31:07 +0000521 attr.weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000522#ifdef HAVE_IPV6
Paul Jakma03e214c2007-04-29 18:31:07 +0000523 attr.mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000524#endif
525 if (! as_set)
526 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
527 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
528 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
529 attr.aggregator_as = bgp->confed_id;
530 else
531 attr.aggregator_as = bgp->as;
532 attr.aggregator_addr = bgp->router_id;
533
534 new = bgp_attr_intern (&attr);
535 aspath_unintern (new->aspath);
536 return new;
537}
538
539/* Free bgp attribute and aspath. */
540void
541bgp_attr_unintern (struct attr *attr)
542{
543 struct attr *ret;
544 struct aspath *aspath;
545 struct community *community;
546 struct ecommunity *ecommunity;
547 struct cluster_list *cluster;
548 struct transit *transit;
549
550 /* Decrement attribute reference. */
551 attr->refcnt--;
552 aspath = attr->aspath;
553 community = attr->community;
554 ecommunity = attr->ecommunity;
555 cluster = attr->cluster;
556 transit = attr->transit;
557
558 /* If reference becomes zero then free attribute object. */
559 if (attr->refcnt == 0)
560 {
561 ret = hash_release (attrhash, attr);
562 assert (ret != NULL);
563 XFREE (MTYPE_ATTR, attr);
564 }
565
566 /* aspath refcount shoud be decrement. */
567 if (aspath)
568 aspath_unintern (aspath);
569 if (community)
570 community_unintern (community);
571 if (ecommunity)
572 ecommunity_unintern (ecommunity);
573 if (cluster)
574 cluster_unintern (cluster);
575 if (transit)
576 transit_unintern (transit);
577}
578
579void
580bgp_attr_flush (struct attr *attr)
581{
582 if (attr->aspath && ! attr->aspath->refcnt)
583 aspath_free (attr->aspath);
584 if (attr->community && ! attr->community->refcnt)
585 community_free (attr->community);
586 if (attr->ecommunity && ! attr->ecommunity->refcnt)
587 ecommunity_free (attr->ecommunity);
588 if (attr->cluster && ! attr->cluster->refcnt)
589 cluster_free (attr->cluster);
590 if (attr->transit && ! attr->transit->refcnt)
591 transit_free (attr->transit);
592}
593
594/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000595static int
paul718e3742002-12-13 20:15:29 +0000596bgp_attr_origin (struct peer *peer, bgp_size_t length,
597 struct attr *attr, u_char flag, u_char *startp)
598{
599 bgp_size_t total;
600
601 /* total is entire attribute length include Attribute Flags (1),
602 Attribute Type code (1) and Attribute length (1 or 2). */
603 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
604
605 /* If any recognized attribute has Attribute Flags that conflict
606 with the Attribute Type Code, then the Error Subcode is set to
607 Attribute Flags Error. The Data field contains the erroneous
608 attribute (type, length and value). */
609 if (flag != BGP_ATTR_FLAG_TRANS)
610 {
611 zlog (peer->log, LOG_ERR,
612 "Origin attribute flag isn't transitive %d", flag);
613 bgp_notify_send_with_data (peer,
614 BGP_NOTIFY_UPDATE_ERR,
615 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
616 startp, total);
617 return -1;
618 }
619
620 /* If any recognized attribute has Attribute Length that conflicts
621 with the expected length (based on the attribute type code), then
622 the Error Subcode is set to Attribute Length Error. The Data
623 field contains the erroneous attribute (type, length and
624 value). */
625 if (length != 1)
626 {
627 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
628 length);
629 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
630 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
631 startp, total);
632 return -1;
633 }
634
635 /* Fetch origin attribute. */
636 attr->origin = stream_getc (BGP_INPUT (peer));
637
638 /* If the ORIGIN attribute has an undefined value, then the Error
639 Subcode is set to Invalid Origin Attribute. The Data field
640 contains the unrecognized attribute (type, length and value). */
641 if ((attr->origin != BGP_ORIGIN_IGP)
642 && (attr->origin != BGP_ORIGIN_EGP)
643 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
644 {
645 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
646 attr->origin);
647
648 bgp_notify_send_with_data (peer,
649 BGP_NOTIFY_UPDATE_ERR,
650 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
651 startp, total);
652 return -1;
653 }
654
655 /* Set oring attribute flag. */
656 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
657
658 return 0;
659}
660
661/* Parse AS path information. This function is wrapper of
662 aspath_parse. */
paul94f2b392005-06-28 12:44:16 +0000663static int
paul718e3742002-12-13 20:15:29 +0000664bgp_attr_aspath (struct peer *peer, bgp_size_t length,
665 struct attr *attr, u_char flag, u_char *startp)
666{
667 struct bgp *bgp;
668 struct aspath *aspath;
669 bgp_size_t total;
670
671 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
672
673 /* Flag check. */
674 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
675 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
676 {
677 zlog (peer->log, LOG_ERR,
678 "Origin attribute flag isn't transitive %d", flag);
679 bgp_notify_send_with_data (peer,
680 BGP_NOTIFY_UPDATE_ERR,
681 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
682 startp, total);
683 return -1;
684 }
685
686 /* In case of IBGP, length will be zero. */
paulfe69a502005-09-10 16:55:02 +0000687 attr->aspath = aspath_parse (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000688 if (! attr->aspath)
689 {
690 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
691 bgp_notify_send (peer,
692 BGP_NOTIFY_UPDATE_ERR,
693 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
694 return -1;
695 }
696
697 bgp = peer->bgp;
698
699 /* First AS check for EBGP. */
700 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
701 {
702 if (peer_sort (peer) == BGP_PEER_EBGP
703 && ! aspath_firstas_check (attr->aspath, peer->as))
704 {
705 zlog (peer->log, LOG_ERR,
706 "%s incorrect first AS (must be %d)", peer->host, peer->as);
707 bgp_notify_send (peer,
708 BGP_NOTIFY_UPDATE_ERR,
709 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
710 return -1;
711 }
712 }
713
714 /* local-as prepend */
715 if (peer->change_local_as &&
716 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
717 {
718 aspath = aspath_dup (attr->aspath);
719 aspath = aspath_add_seq (aspath, peer->change_local_as);
720 aspath_unintern (attr->aspath);
721 attr->aspath = aspath_intern (aspath);
722 }
723
724 /* Forward pointer. */
paulfe69a502005-09-10 16:55:02 +0000725/* stream_forward_getp (peer->ibuf, length);*/
paul718e3742002-12-13 20:15:29 +0000726
727 /* Set aspath attribute flag. */
728 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
729
730 return 0;
731}
732
733/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000734static int
paul718e3742002-12-13 20:15:29 +0000735bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
736 struct attr *attr, u_char flag, u_char *startp)
737{
738 bgp_size_t total;
739
740 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
741
742 /* Flag check. */
743 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
744 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
745 {
746 zlog (peer->log, LOG_ERR,
747 "Origin attribute flag isn't transitive %d", flag);
748 bgp_notify_send_with_data (peer,
749 BGP_NOTIFY_UPDATE_ERR,
750 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
751 startp, total);
752 return -1;
753 }
754
755 /* Check nexthop attribute length. */
756 if (length != 4)
757 {
758 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
759 length);
760
761 bgp_notify_send_with_data (peer,
762 BGP_NOTIFY_UPDATE_ERR,
763 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
764 startp, total);
765 return -1;
766 }
767
768 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
769 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
770
771 return 0;
772}
773
774/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000775static int
paul718e3742002-12-13 20:15:29 +0000776bgp_attr_med (struct peer *peer, bgp_size_t length,
777 struct attr *attr, u_char flag, u_char *startp)
778{
779 bgp_size_t total;
780
781 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
782
783 /* Length check. */
784 if (length != 4)
785 {
786 zlog (peer->log, LOG_ERR,
787 "MED attribute length isn't four [%d]", length);
788
789 bgp_notify_send_with_data (peer,
790 BGP_NOTIFY_UPDATE_ERR,
791 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
792 startp, total);
793 return -1;
794 }
795
796 attr->med = stream_getl (peer->ibuf);
797
798 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
799
800 return 0;
801}
802
803/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000804static int
paul718e3742002-12-13 20:15:29 +0000805bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
806 struct attr *attr, u_char flag)
807{
808 /* If it is contained in an UPDATE message that is received from an
809 external peer, then this attribute MUST be ignored by the
810 receiving speaker. */
811 if (peer_sort (peer) == BGP_PEER_EBGP)
812 {
paul9985f832005-02-09 15:51:56 +0000813 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000814 return 0;
815 }
816
817 if (length == 4)
818 attr->local_pref = stream_getl (peer->ibuf);
819 else
820 attr->local_pref = 0;
821
822 /* Set atomic aggregate flag. */
823 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
824
825 return 0;
826}
827
828/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +0000829static int
paul718e3742002-12-13 20:15:29 +0000830bgp_attr_atomic (struct peer *peer, bgp_size_t length,
831 struct attr *attr, u_char flag)
832{
833 if (length != 0)
834 {
835 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
836
837 bgp_notify_send (peer,
838 BGP_NOTIFY_UPDATE_ERR,
839 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
840 return -1;
841 }
842
843 /* Set atomic aggregate flag. */
844 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
845
846 return 0;
847}
848
849/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +0000850static int
paul718e3742002-12-13 20:15:29 +0000851bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
852 struct attr *attr, u_char flag)
853{
854 if (length != 6)
855 {
856 zlog (peer->log, LOG_ERR, "Aggregator length is not 6 [%d]", length);
857
858 bgp_notify_send (peer,
859 BGP_NOTIFY_UPDATE_ERR,
860 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
861 return -1;
862 }
863 attr->aggregator_as = stream_getw (peer->ibuf);
864 attr->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
865
866 /* Set atomic aggregate flag. */
867 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
868
869 return 0;
870}
871
872/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +0000873static int
paul718e3742002-12-13 20:15:29 +0000874bgp_attr_community (struct peer *peer, bgp_size_t length,
875 struct attr *attr, u_char flag)
876{
877 if (length == 0)
878 attr->community = NULL;
879 else
880 {
paul5228ad22004-06-04 17:58:18 +0000881 attr->community =
882 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +0000883 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000884 }
885
886 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
887
888 return 0;
889}
890
891/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +0000892static int
paul718e3742002-12-13 20:15:29 +0000893bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
894 struct attr *attr, u_char flag)
895{
896 if (length != 4)
897 {
898 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
899
900 bgp_notify_send (peer,
901 BGP_NOTIFY_UPDATE_ERR,
902 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
903 return -1;
904 }
905
906 attr->originator_id.s_addr = stream_get_ipv4 (peer->ibuf);
907
908 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
909
910 return 0;
911}
912
913/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +0000914static int
paul718e3742002-12-13 20:15:29 +0000915bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
916 struct attr *attr, u_char flag)
917{
918 /* Check length. */
919 if (length % 4)
920 {
921 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
922
923 bgp_notify_send (peer,
924 BGP_NOTIFY_UPDATE_ERR,
925 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
926 return -1;
927 }
928
paul5228ad22004-06-04 17:58:18 +0000929 attr->cluster = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf),
930 length);
paul718e3742002-12-13 20:15:29 +0000931
paul9985f832005-02-09 15:51:56 +0000932 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +0000933
934 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
935
936 return 0;
937}
938
939/* Multiprotocol reachability information parse. */
paul94f2b392005-06-28 12:44:16 +0000940static int
paul718e3742002-12-13 20:15:29 +0000941bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
942 struct bgp_nlri *mp_update)
943{
944 u_int16_t afi;
945 u_char safi;
paul718e3742002-12-13 20:15:29 +0000946 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +0000947 size_t start;
paul718e3742002-12-13 20:15:29 +0000948 int ret;
949 struct stream *s;
950
951 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +0000952 s = BGP_INPUT(peer);
953 start = stream_get_getp(s);
954
955 /* safe to read statically sized header? */
956#define BGP_MP_REACH_MIN_SIZE 5
957 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
958 return -1;
959
paul718e3742002-12-13 20:15:29 +0000960 /* Load AFI, SAFI. */
961 afi = stream_getw (s);
962 safi = stream_getc (s);
963
964 /* Get nexthop length. */
965 attr->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +0000966
967 if (STREAM_READABLE(s) < attr->mp_nexthop_len)
968 return -1;
969
paul718e3742002-12-13 20:15:29 +0000970 /* Nexthop length check. */
971 switch (attr->mp_nexthop_len)
972 {
973 case 4:
974 stream_get (&attr->mp_nexthop_global_in, s, 4);
975 break;
976 case 12:
977 {
978 u_int32_t rd_high;
979 u_int32_t rd_low;
980
981 rd_high = stream_getl (s);
982 rd_low = stream_getl (s);
983 stream_get (&attr->mp_nexthop_global_in, s, 4);
984 }
985 break;
986#ifdef HAVE_IPV6
987 case 16:
988 stream_get (&attr->mp_nexthop_global, s, 16);
989 break;
990 case 32:
991 stream_get (&attr->mp_nexthop_global, s, 16);
992 stream_get (&attr->mp_nexthop_local, s, 16);
993 if (! IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local))
994 {
995 char buf1[INET6_ADDRSTRLEN];
996 char buf2[INET6_ADDRSTRLEN];
997
998 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +0000999 zlog_debug ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host,
paul718e3742002-12-13 20:15:29 +00001000 inet_ntop (AF_INET6, &attr->mp_nexthop_global,
1001 buf1, INET6_ADDRSTRLEN),
1002 inet_ntop (AF_INET6, &attr->mp_nexthop_local,
1003 buf2, INET6_ADDRSTRLEN));
1004
1005 attr->mp_nexthop_len = 16;
1006 }
1007 break;
1008#endif /* HAVE_IPV6 */
1009 default:
1010 zlog_info ("Wrong multiprotocol next hop length: %d",
1011 attr->mp_nexthop_len);
1012 return -1;
paul718e3742002-12-13 20:15:29 +00001013 }
1014
Paul Jakma6e4ab122007-04-10 19:36:48 +00001015 if (!STREAM_READABLE(s))
1016 return -1;
paul718e3742002-12-13 20:15:29 +00001017
Paul Jakma6e4ab122007-04-10 19:36:48 +00001018 {
1019 u_char val;
1020 if ((val = stream_getc (s)))
1021 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1022 peer->host, val);
1023 }
1024
1025 /* must have nrli_len, what is left of the attribute */
1026 nlri_len = length - (stream_get_getp(s) - start);
1027 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
1028 return -1;
paul718e3742002-12-13 20:15:29 +00001029
1030 if (safi != BGP_SAFI_VPNV4)
1031 {
1032 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
1033 if (ret < 0)
1034 return -1;
1035 }
1036
1037 mp_update->afi = afi;
1038 mp_update->safi = safi;
1039 mp_update->nlri = stream_pnt (s);
1040 mp_update->length = nlri_len;
1041
paul9985f832005-02-09 15:51:56 +00001042 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001043
1044 return 0;
1045}
1046
1047/* Multiprotocol unreachable parse */
paul94f2b392005-06-28 12:44:16 +00001048static int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001049bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001050 struct bgp_nlri *mp_withdraw)
1051{
1052 struct stream *s;
1053 u_int16_t afi;
1054 u_char safi;
paul718e3742002-12-13 20:15:29 +00001055 u_int16_t withdraw_len;
1056 int ret;
1057
1058 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001059
1060#define BGP_MP_UNREACH_MIN_SIZE 3
1061 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1062 return -1;
1063
paul718e3742002-12-13 20:15:29 +00001064 afi = stream_getw (s);
1065 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001066
1067 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001068
1069 if (safi != BGP_SAFI_VPNV4)
1070 {
1071 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1072 if (ret < 0)
1073 return -1;
1074 }
1075
1076 mp_withdraw->afi = afi;
1077 mp_withdraw->safi = safi;
1078 mp_withdraw->nlri = stream_pnt (s);
1079 mp_withdraw->length = withdraw_len;
1080
paul9985f832005-02-09 15:51:56 +00001081 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001082
1083 return 0;
1084}
1085
1086/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001087static int
paul718e3742002-12-13 20:15:29 +00001088bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1089 struct attr *attr, u_char flag)
1090{
1091 if (length == 0)
1092 attr->ecommunity = NULL;
1093 else
1094 {
paul5228ad22004-06-04 17:58:18 +00001095 attr->ecommunity =
1096 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001097 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001098 }
1099 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1100
1101 return 0;
1102}
1103
1104/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001105static int
paul718e3742002-12-13 20:15:29 +00001106bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1107 u_char type, bgp_size_t length, u_char *startp)
1108{
1109 bgp_size_t total;
1110 struct transit *transit;
1111
hassof4184462005-02-01 20:13:16 +00001112 if (BGP_DEBUG (normal, NORMAL))
1113 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1114 peer->host, type, length);
1115
paul718e3742002-12-13 20:15:29 +00001116 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001117 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001118 "Unknown attribute type %d length %d is received", type, length);
1119
1120 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001121 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001122
1123 /* Adjest total length to include type and length. */
1124 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1125
1126 /* If any of the mandatory well-known attributes are not recognized,
1127 then the Error Subcode is set to Unrecognized Well-known
1128 Attribute. The Data field contains the unrecognized attribute
1129 (type, length and value). */
1130 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1131 {
1132 /* Adjust startp to do not include flag value. */
1133 bgp_notify_send_with_data (peer,
1134 BGP_NOTIFY_UPDATE_ERR,
1135 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1136 startp, total);
1137 return -1;
1138 }
1139
1140 /* Unrecognized non-transitive optional attributes must be quietly
1141 ignored and not passed along to other BGP peers. */
1142 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1143 return 0;
1144
1145 /* If a path with recognized transitive optional attribute is
1146 accepted and passed along to other BGP peers and the Partial bit
1147 in the Attribute Flags octet is set to 1 by some previous AS, it
1148 is not set back to 0 by the current AS. */
1149 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1150
1151 /* Store transitive attribute to the end of attr->transit. */
1152 if (! attr->transit)
1153 {
1154 attr->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit));
1155 memset (attr->transit, 0, sizeof (struct transit));
1156 }
1157
1158 transit = attr->transit;
1159
1160 if (transit->val)
1161 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1162 transit->length + total);
1163 else
1164 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1165
1166 memcpy (transit->val + transit->length, startp, total);
1167 transit->length += total;
1168
1169 return 0;
1170}
1171
1172/* Read attribute of update packet. This function is called from
1173 bgp_update() in bgpd.c. */
1174int
1175bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1176 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1177{
1178 int ret;
1179 u_char flag;
1180 u_char type;
1181 bgp_size_t length;
1182 u_char *startp, *endp;
1183 u_char *attr_endp;
1184 u_char seen[BGP_ATTR_BITMAP_SIZE];
1185
1186 /* Initialize bitmap. */
1187 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1188
1189 /* End pointer of BGP attribute. */
1190 endp = BGP_INPUT_PNT (peer) + size;
1191
1192 /* Get attributes to the end of attribute length. */
1193 while (BGP_INPUT_PNT (peer) < endp)
1194 {
1195 /* Check remaining length check.*/
1196 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1197 {
gdtc29fdba2004-12-09 14:46:46 +00001198 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001199 zlog (peer->log, LOG_WARNING,
paula2b1ecd2004-10-31 18:58:09 +00001200 "%s error BGP attribute length %ld is smaller than min len",
paul718e3742002-12-13 20:15:29 +00001201 peer->host, endp - STREAM_PNT (BGP_INPUT (peer)));
1202
1203 bgp_notify_send (peer,
1204 BGP_NOTIFY_UPDATE_ERR,
1205 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1206 return -1;
1207 }
1208
1209 /* Fetch attribute flag and type. */
1210 startp = BGP_INPUT_PNT (peer);
1211 flag = stream_getc (BGP_INPUT (peer));
1212 type = stream_getc (BGP_INPUT (peer));
1213
1214 /* Check extended attribue length bit. */
1215 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1216 length = stream_getw (BGP_INPUT (peer));
1217 else
1218 length = stream_getc (BGP_INPUT (peer));
1219
1220 /* If any attribute appears more than once in the UPDATE
1221 message, then the Error Subcode is set to Malformed Attribute
1222 List. */
1223
1224 if (CHECK_BITMAP (seen, type))
1225 {
1226 zlog (peer->log, LOG_WARNING,
1227 "%s error BGP attribute type %d appears twice in a message",
1228 peer->host, type);
1229
1230 bgp_notify_send (peer,
1231 BGP_NOTIFY_UPDATE_ERR,
1232 BGP_NOTIFY_UPDATE_MAL_ATTR);
1233 return -1;
1234 }
1235
1236 /* Set type to bitmap to check duplicate attribute. `type' is
1237 unsigned char so it never overflow bitmap range. */
1238
1239 SET_BITMAP (seen, type);
1240
1241 /* Overflow check. */
1242 attr_endp = BGP_INPUT_PNT (peer) + length;
1243
1244 if (attr_endp > endp)
1245 {
1246 zlog (peer->log, LOG_WARNING,
1247 "%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);
1248 bgp_notify_send (peer,
1249 BGP_NOTIFY_UPDATE_ERR,
1250 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1251 return -1;
1252 }
1253
1254 /* OK check attribute and store it's value. */
1255 switch (type)
1256 {
1257 case BGP_ATTR_ORIGIN:
1258 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1259 break;
1260 case BGP_ATTR_AS_PATH:
1261 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
1262 break;
1263 case BGP_ATTR_NEXT_HOP:
1264 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1265 break;
1266 case BGP_ATTR_MULTI_EXIT_DISC:
1267 ret = bgp_attr_med (peer, length, attr, flag, startp);
1268 break;
1269 case BGP_ATTR_LOCAL_PREF:
1270 ret = bgp_attr_local_pref (peer, length, attr, flag);
1271 break;
1272 case BGP_ATTR_ATOMIC_AGGREGATE:
1273 ret = bgp_attr_atomic (peer, length, attr, flag);
1274 break;
1275 case BGP_ATTR_AGGREGATOR:
1276 ret = bgp_attr_aggregator (peer, length, attr, flag);
1277 break;
1278 case BGP_ATTR_COMMUNITIES:
1279 ret = bgp_attr_community (peer, length, attr, flag);
1280 break;
1281 case BGP_ATTR_ORIGINATOR_ID:
1282 ret = bgp_attr_originator_id (peer, length, attr, flag);
1283 break;
1284 case BGP_ATTR_CLUSTER_LIST:
1285 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1286 break;
1287 case BGP_ATTR_MP_REACH_NLRI:
1288 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1289 break;
1290 case BGP_ATTR_MP_UNREACH_NLRI:
1291 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1292 break;
1293 case BGP_ATTR_EXT_COMMUNITIES:
1294 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1295 break;
1296 default:
1297 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1298 break;
1299 }
1300
1301 /* If error occured immediately return to the caller. */
1302 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001303 {
1304 zlog (peer->log, LOG_WARNING,
1305 "%s: Attribute %s, parse error",
1306 peer->host,
1307 LOOKUP (attr_str, type));
1308 bgp_notify_send (peer,
1309 BGP_NOTIFY_UPDATE_ERR,
1310 BGP_NOTIFY_UPDATE_MAL_ATTR);
1311 return ret;
1312 }
paul718e3742002-12-13 20:15:29 +00001313
1314 /* Check the fetched length. */
1315 if (BGP_INPUT_PNT (peer) != attr_endp)
1316 {
1317 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001318 "%s: BGP attribute %s, fetch error",
1319 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001320 bgp_notify_send (peer,
1321 BGP_NOTIFY_UPDATE_ERR,
1322 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1323 return -1;
1324 }
1325 }
1326
1327 /* Check final read pointer is same as end pointer. */
1328 if (BGP_INPUT_PNT (peer) != endp)
1329 {
1330 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001331 "%s BGP attribute %s, length mismatch",
1332 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001333 bgp_notify_send (peer,
1334 BGP_NOTIFY_UPDATE_ERR,
1335 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1336 return -1;
1337 }
1338
1339 /* Finally intern unknown attribute. */
1340 if (attr->transit)
1341 attr->transit = transit_intern (attr->transit);
1342
1343 return 0;
1344}
1345
1346/* Well-known attribute check. */
1347int
1348bgp_attr_check (struct peer *peer, struct attr *attr)
1349{
1350 u_char type = 0;
1351
1352 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1353 type = BGP_ATTR_ORIGIN;
1354
1355 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1356 type = BGP_ATTR_AS_PATH;
1357
1358 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1359 type = BGP_ATTR_NEXT_HOP;
1360
1361 if (peer_sort (peer) == BGP_PEER_IBGP
1362 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1363 type = BGP_ATTR_LOCAL_PREF;
1364
1365 if (type)
1366 {
1367 zlog (peer->log, LOG_WARNING,
1368 "%s Missing well-known attribute %d.",
1369 peer->host, type);
1370 bgp_notify_send_with_data (peer,
1371 BGP_NOTIFY_UPDATE_ERR,
1372 BGP_NOTIFY_UPDATE_MISS_ATTR,
1373 &type, 1);
1374 return -1;
1375 }
1376 return 0;
1377}
1378
1379int stream_put_prefix (struct stream *, struct prefix *);
1380
1381/* Make attribute packet. */
1382bgp_size_t
1383bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1384 struct stream *s, struct attr *attr, struct prefix *p,
1385 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001386 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001387{
paulfe69a502005-09-10 16:55:02 +00001388 size_t cp;
1389 unsigned int aspath_data_size;
paul718e3742002-12-13 20:15:29 +00001390 struct aspath *aspath;
1391
1392 if (! bgp)
1393 bgp = bgp_get_default ();
1394
1395 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001396 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001397
1398 /* Origin attribute. */
1399 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1400 stream_putc (s, BGP_ATTR_ORIGIN);
1401 stream_putc (s, 1);
1402 stream_putc (s, attr->origin);
1403
1404 /* AS path attribute. */
1405
1406 /* If remote-peer is EBGP */
1407 if (peer_sort (peer) == BGP_PEER_EBGP
1408 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001409 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001410 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001411 {
1412 aspath = aspath_dup (attr->aspath);
1413
1414 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1415 {
1416 /* Strip the confed info, and then stuff our path CONFED_ID
1417 on the front */
1418 aspath = aspath_delete_confed_seq (aspath);
1419 aspath = aspath_add_seq (aspath, bgp->confed_id);
1420 }
1421 else
1422 {
1423 aspath = aspath_add_seq (aspath, peer->local_as);
1424 if (peer->change_local_as)
1425 aspath = aspath_add_seq (aspath, peer->change_local_as);
1426 }
1427 }
1428 else if (peer_sort (peer) == BGP_PEER_CONFED)
1429 {
1430 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1431 aspath = aspath_dup (attr->aspath);
1432 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1433 }
1434 else
1435 aspath = attr->aspath;
1436
1437 /* AS path attribute extended length bit check. */
paulfe69a502005-09-10 16:55:02 +00001438 aspath_data_size = aspath_size (aspath);
1439 if (aspath_data_size > 255)
paul718e3742002-12-13 20:15:29 +00001440 {
1441 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1442 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001443 stream_putw (s, aspath_data_size);
paul718e3742002-12-13 20:15:29 +00001444 }
1445 else
1446 {
1447 stream_putc (s, BGP_ATTR_FLAG_TRANS);
paulfe69a502005-09-10 16:55:02 +00001448 stream_putc (s, BGP_ATTR_AS_PATH);
1449 stream_putc (s, aspath_data_size);
paul718e3742002-12-13 20:15:29 +00001450 }
paulfe69a502005-09-10 16:55:02 +00001451 aspath_put (s, aspath);
paul718e3742002-12-13 20:15:29 +00001452
1453 if (aspath != attr->aspath)
1454 aspath_free (aspath);
1455
1456 /* Nexthop attribute. */
1457 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1458 {
1459 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1460 stream_putc (s, BGP_ATTR_NEXT_HOP);
1461 stream_putc (s, 4);
1462 if (safi == SAFI_MPLS_VPN)
1463 {
1464 if (attr->nexthop.s_addr == 0)
1465 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1466 else
1467 stream_put_ipv4 (s, attr->nexthop.s_addr);
1468 }
1469 else
1470 stream_put_ipv4 (s, attr->nexthop.s_addr);
1471 }
1472
1473 /* MED attribute. */
1474 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1475 {
1476 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1477 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1478 stream_putc (s, 4);
1479 stream_putl (s, attr->med);
1480 }
1481
1482 /* Local preference. */
1483 if (peer_sort (peer) == BGP_PEER_IBGP ||
1484 peer_sort (peer) == BGP_PEER_CONFED)
1485 {
1486 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1487 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1488 stream_putc (s, 4);
1489 stream_putl (s, attr->local_pref);
1490 }
1491
1492 /* Atomic aggregate. */
1493 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1494 {
1495 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1496 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1497 stream_putc (s, 0);
1498 }
1499
1500 /* Aggregator. */
1501 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1502 {
1503 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1504 stream_putc (s, BGP_ATTR_AGGREGATOR);
1505 stream_putc (s, 6);
1506 stream_putw (s, attr->aggregator_as);
1507 stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
1508 }
1509
1510 /* Community attribute. */
1511 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1512 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1513 {
1514 if (attr->community->size * 4 > 255)
1515 {
1516 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1517 stream_putc (s, BGP_ATTR_COMMUNITIES);
1518 stream_putw (s, attr->community->size * 4);
1519 }
1520 else
1521 {
1522 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1523 stream_putc (s, BGP_ATTR_COMMUNITIES);
1524 stream_putc (s, attr->community->size * 4);
1525 }
1526 stream_put (s, attr->community->val, attr->community->size * 4);
1527 }
1528
1529 /* Route Reflector. */
1530 if (peer_sort (peer) == BGP_PEER_IBGP
1531 && from
1532 && peer_sort (from) == BGP_PEER_IBGP)
1533 {
1534 /* Originator ID. */
1535 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1536 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
1537 stream_putc (s, 4);
1538
1539 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
1540 stream_put_in_addr (s, &attr->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00001541 else
1542 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00001543
1544 /* Cluster list. */
1545 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1546 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
1547
1548 if (attr->cluster)
1549 {
1550 stream_putc (s, attr->cluster->length + 4);
1551 /* If this peer configuration's parent BGP has cluster_id. */
1552 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1553 stream_put_in_addr (s, &bgp->cluster_id);
1554 else
1555 stream_put_in_addr (s, &bgp->router_id);
1556 stream_put (s, attr->cluster->list, attr->cluster->length);
1557 }
1558 else
1559 {
1560 stream_putc (s, 4);
1561 /* If this peer configuration's parent BGP has cluster_id. */
1562 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1563 stream_put_in_addr (s, &bgp->cluster_id);
1564 else
1565 stream_put_in_addr (s, &bgp->router_id);
1566 }
1567 }
1568
1569#ifdef HAVE_IPV6
1570 /* If p is IPv6 address put it into attribute. */
1571 if (p->family == AF_INET6)
1572 {
1573 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00001574
1575 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1576 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001577 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001578 stream_putc (s, 0); /* Length of this attribute. */
1579 stream_putw (s, AFI_IP6); /* AFI */
1580 stream_putc (s, safi); /* SAFI */
1581
1582 stream_putc (s, attr->mp_nexthop_len);
1583
1584 if (attr->mp_nexthop_len == 16)
1585 stream_put (s, &attr->mp_nexthop_global, 16);
1586 else if (attr->mp_nexthop_len == 32)
1587 {
1588 stream_put (s, &attr->mp_nexthop_global, 16);
1589 stream_put (s, &attr->mp_nexthop_local, 16);
1590 }
1591
1592 /* SNPA */
1593 stream_putc (s, 0);
1594
paul718e3742002-12-13 20:15:29 +00001595 /* Prefix write. */
1596 stream_put_prefix (s, p);
1597
1598 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001599 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001600 }
1601#endif /* HAVE_IPV6 */
1602
1603 if (p->family == AF_INET && safi == SAFI_MULTICAST)
1604 {
1605 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00001606
1607 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1608 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001609 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001610 stream_putc (s, 0); /* Length of this attribute. */
1611 stream_putw (s, AFI_IP); /* AFI */
1612 stream_putc (s, SAFI_MULTICAST); /* SAFI */
1613
1614 stream_putc (s, 4);
1615 stream_put_ipv4 (s, attr->nexthop.s_addr);
1616
1617 /* SNPA */
1618 stream_putc (s, 0);
1619
paul718e3742002-12-13 20:15:29 +00001620 /* Prefix write. */
1621 stream_put_prefix (s, p);
1622
1623 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001624 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001625 }
1626
1627 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
1628 {
1629 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00001630
1631 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1632 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001633 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001634 stream_putc (s, 0); /* Length of this attribute. */
1635 stream_putw (s, AFI_IP); /* AFI */
1636 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
1637
1638 stream_putc (s, 12);
1639 stream_putl (s, 0);
1640 stream_putl (s, 0);
1641 stream_put (s, &attr->mp_nexthop_global_in, 4);
1642
1643 /* SNPA */
1644 stream_putc (s, 0);
1645
paul718e3742002-12-13 20:15:29 +00001646 /* Tag, RD, Prefix write. */
1647 stream_putc (s, p->prefixlen + 88);
1648 stream_put (s, tag, 3);
1649 stream_put (s, prd->val, 8);
1650 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
1651
1652 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001653 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001654 }
1655
1656 /* Extended Communities attribute. */
1657 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
1658 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
1659 {
hasso4372df72004-05-20 10:20:02 +00001660 if (peer_sort (peer) == BGP_PEER_IBGP || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00001661 {
hasso4372df72004-05-20 10:20:02 +00001662 if (attr->ecommunity->size * 8 > 255)
1663 {
1664 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1665 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1666 stream_putw (s, attr->ecommunity->size * 8);
1667 }
1668 else
1669 {
1670 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1671 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1672 stream_putc (s, attr->ecommunity->size * 8);
1673 }
1674 stream_put (s, attr->ecommunity->val, attr->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00001675 }
1676 else
1677 {
paul5228ad22004-06-04 17:58:18 +00001678 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00001679 int tbit;
1680 int ecom_tr_size = 0;
1681 int i;
1682
1683 for (i = 0; i < attr->ecommunity->size; i++)
1684 {
1685 pnt = attr->ecommunity->val + (i * 8);
1686 tbit = *pnt;
1687
1688 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
1689 continue;
1690
1691 ecom_tr_size++;
1692 }
1693
1694 if (ecom_tr_size)
1695 {
1696 if (ecom_tr_size * 8 > 255)
1697 {
1698 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1699 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1700 stream_putw (s, ecom_tr_size * 8);
1701 }
1702 else
1703 {
1704 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1705 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1706 stream_putc (s, ecom_tr_size * 8);
1707 }
1708
1709 for (i = 0; i < attr->ecommunity->size; i++)
1710 {
1711 pnt = attr->ecommunity->val + (i * 8);
1712 tbit = *pnt;
1713
1714 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
1715 continue;
1716
1717 stream_put (s, pnt, 8);
1718 }
1719 }
paul718e3742002-12-13 20:15:29 +00001720 }
paul718e3742002-12-13 20:15:29 +00001721 }
1722
1723 /* Unknown transit attribute. */
1724 if (attr->transit)
1725 stream_put (s, attr->transit->val, attr->transit->length);
1726
1727 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00001728 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00001729}
1730
1731bgp_size_t
1732bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
1733 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001734 u_char *tag)
paul718e3742002-12-13 20:15:29 +00001735{
1736 unsigned long cp;
1737 unsigned long attrlen_pnt;
1738 bgp_size_t size;
1739
paul9985f832005-02-09 15:51:56 +00001740 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001741
1742 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1743 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
1744
paul9985f832005-02-09 15:51:56 +00001745 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001746 stream_putc (s, 0); /* Length of this attribute. */
1747
1748 stream_putw (s, family2afi (p->family));
1749
1750 if (safi == SAFI_MPLS_VPN)
1751 {
1752 /* SAFI */
1753 stream_putc (s, BGP_SAFI_VPNV4);
1754
1755 /* prefix. */
1756 stream_putc (s, p->prefixlen + 88);
1757 stream_put (s, tag, 3);
1758 stream_put (s, prd->val, 8);
1759 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
1760 }
1761 else
1762 {
1763 /* SAFI */
1764 stream_putc (s, safi);
1765
1766 /* prefix */
1767 stream_put_prefix (s, p);
1768 }
1769
1770 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001771 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00001772 stream_putc_at (s, attrlen_pnt, size);
1773
paul9985f832005-02-09 15:51:56 +00001774 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00001775}
1776
1777/* Initialization of attribute. */
1778void
paulfe69a502005-09-10 16:55:02 +00001779bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00001780{
1781 void attrhash_init ();
1782
1783 aspath_init ();
1784 attrhash_init ();
1785 community_init ();
1786 ecommunity_init ();
1787 cluster_init ();
1788 transit_init ();
1789}
1790
1791/* Make attribute packet. */
1792void
paula3845922003-10-18 01:30:50 +00001793bgp_dump_routes_attr (struct stream *s, struct attr *attr,
1794 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00001795{
1796 unsigned long cp;
1797 unsigned long len;
paulfe69a502005-09-10 16:55:02 +00001798 unsigned int aspathlen;
paul718e3742002-12-13 20:15:29 +00001799 struct aspath *aspath;
1800
1801 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001802 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001803
1804 /* Place holder of length. */
1805 stream_putw (s, 0);
1806
1807 /* Origin attribute. */
1808 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1809 stream_putc (s, BGP_ATTR_ORIGIN);
1810 stream_putc (s, 1);
1811 stream_putc (s, attr->origin);
1812
1813 aspath = attr->aspath;
1814
paulfe69a502005-09-10 16:55:02 +00001815 if ( (aspathlen = aspath_size (aspath)) > 255 )
paul718e3742002-12-13 20:15:29 +00001816 {
1817 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1818 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001819 stream_putw (s, aspathlen);
paul718e3742002-12-13 20:15:29 +00001820 }
1821 else
1822 {
1823 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1824 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001825 stream_putc (s, aspathlen);
paul718e3742002-12-13 20:15:29 +00001826 }
paulfe69a502005-09-10 16:55:02 +00001827 aspath_put (s, aspath);
paul718e3742002-12-13 20:15:29 +00001828
1829 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00001830 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
1831 if(prefix != NULL
1832#ifdef HAVE_IPV6
1833 && prefix->family != AF_INET6
1834#endif /* HAVE_IPV6 */
1835 )
1836 {
1837 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1838 stream_putc (s, BGP_ATTR_NEXT_HOP);
1839 stream_putc (s, 4);
1840 stream_put_ipv4 (s, attr->nexthop.s_addr);
1841 }
paul718e3742002-12-13 20:15:29 +00001842
1843 /* MED attribute. */
1844 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1845 {
1846 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1847 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1848 stream_putc (s, 4);
1849 stream_putl (s, attr->med);
1850 }
1851
1852 /* Local preference. */
1853 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
1854 {
1855 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1856 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1857 stream_putc (s, 4);
1858 stream_putl (s, attr->local_pref);
1859 }
1860
1861 /* Atomic aggregate. */
1862 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1863 {
1864 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1865 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1866 stream_putc (s, 0);
1867 }
1868
1869 /* Aggregator. */
1870 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1871 {
1872 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1873 stream_putc (s, BGP_ATTR_AGGREGATOR);
1874 stream_putc (s, 6);
1875 stream_putw (s, attr->aggregator_as);
1876 stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
1877 }
1878
1879 /* Community attribute. */
1880 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
1881 {
1882 if (attr->community->size * 4 > 255)
1883 {
1884 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1885 stream_putc (s, BGP_ATTR_COMMUNITIES);
1886 stream_putw (s, attr->community->size * 4);
1887 }
1888 else
1889 {
1890 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1891 stream_putc (s, BGP_ATTR_COMMUNITIES);
1892 stream_putc (s, attr->community->size * 4);
1893 }
1894 stream_put (s, attr->community->val, attr->community->size * 4);
1895 }
1896
paula3845922003-10-18 01:30:50 +00001897#ifdef HAVE_IPV6
1898 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
1899 if(prefix != NULL && prefix->family == AF_INET6 &&
1900 (attr->mp_nexthop_len == 16 || attr->mp_nexthop_len == 32) )
1901 {
1902 int sizep;
1903
1904 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
1905 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001906 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00001907
1908 /* MP header */
1909 stream_putc (s, 0); /* Length of this attribute. */
1910 stream_putw(s, AFI_IP6); /* AFI */
1911 stream_putc(s, SAFI_UNICAST); /* SAFI */
1912
1913 /* Next hop */
1914 stream_putc(s, attr->mp_nexthop_len);
1915 stream_put(s, &attr->mp_nexthop_global, 16);
1916 if(attr->mp_nexthop_len == 32)
1917 stream_put(s, &attr->mp_nexthop_local, 16);
1918
1919 /* SNPA */
1920 stream_putc(s, 0);
1921
1922 /* Prefix */
1923 stream_put_prefix(s, prefix);
1924
1925 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001926 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00001927 }
1928#endif /* HAVE_IPV6 */
1929
paul718e3742002-12-13 20:15:29 +00001930 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00001931 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00001932 stream_putw_at (s, cp, len);
1933}