~ubuntu-branches/ubuntu/warty/quagga/warty

« back to all changes in this revision

Viewing changes to bgpd/bgp_attr.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabio M. Di Nitto
  • Date: 2004-06-29 09:50:59 UTC
  • Revision ID: james.westby@ubuntu.com-20040629095059-px1m2m108z4qw1mr
Tags: upstream-0.96.5
ImportĀ upstreamĀ versionĀ 0.96.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* BGP attributes management routines.
 
2
   Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
 
3
 
 
4
This file is part of GNU Zebra.
 
5
 
 
6
GNU Zebra is free software; you can redistribute it and/or modify it
 
7
under the terms of the GNU General Public License as published by the
 
8
Free Software Foundation; either version 2, or (at your option) any
 
9
later version.
 
10
 
 
11
GNU Zebra is distributed in the hope that it will be useful, but
 
12
WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
General Public License for more details.
 
15
 
 
16
You should have received a copy of the GNU General Public License
 
17
along with GNU Zebra; see the file COPYING.  If not, write to the Free
 
18
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
19
02111-1307, USA.  */
 
20
 
 
21
#include <zebra.h>
 
22
 
 
23
#include "linklist.h"
 
24
#include "prefix.h"
 
25
#include "memory.h"
 
26
#include "vector.h"
 
27
#include "vty.h"
 
28
#include "stream.h"
 
29
#include "log.h"
 
30
#include "hash.h"
 
31
 
 
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. */
 
42
struct message attr_str [] = 
 
43
{
 
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
};
 
61
 
 
62
struct hash *cluster_hash;
 
63
 
 
64
void *
 
65
cluster_hash_alloc (struct cluster_list *val)
 
66
{
 
67
  struct cluster_list *cluster;
 
68
 
 
69
  cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
 
70
  cluster->length = val->length;
 
71
 
 
72
  if (cluster->length)
 
73
    {
 
74
      cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
 
75
      memcpy (cluster->list, val->list, val->length);
 
76
    }
 
77
  else
 
78
    cluster->list = NULL;
 
79
 
 
80
  cluster->refcnt = 0;
 
81
 
 
82
  return cluster;
 
83
}
 
84
 
 
85
/* Cluster list related functions. */
 
86
struct cluster_list *
 
87
cluster_parse (caddr_t pnt, int length)
 
88
{
 
89
  struct cluster_list tmp;
 
90
  struct cluster_list *cluster;
 
91
 
 
92
  tmp.length = length;
 
93
  tmp.list = (struct in_addr *) pnt;
 
94
 
 
95
  cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
 
96
  cluster->refcnt++;
 
97
  return cluster;
 
98
}
 
99
 
 
100
int
 
101
cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
 
102
{
 
103
  int i;
 
104
    
 
105
  for (i = 0; i < cluster->length / 4; i++)
 
106
    if (cluster->list[i].s_addr == originator.s_addr)
 
107
      return 1;
 
108
  return 0;
 
109
}
 
110
 
 
111
unsigned int
 
112
cluster_hash_key_make (struct cluster_list *cluster)
 
113
{
 
114
  unsigned int key = 0;
 
115
  int length;
 
116
  caddr_t pnt;
 
117
 
 
118
  length = cluster->length;
 
119
  pnt = (caddr_t) cluster->list;
 
120
  
 
121
  while (length)
 
122
    key += pnt[--length];
 
123
 
 
124
  return key;
 
125
}
 
126
 
 
127
int
 
128
cluster_hash_cmp (struct cluster_list *cluster1, struct cluster_list *cluster2)
 
129
{
 
130
  if (cluster1->length == cluster2->length &&
 
131
      memcmp (cluster1->list, cluster2->list, cluster1->length) == 0)
 
132
    return 1;
 
133
  return 0;
 
134
}
 
135
 
 
136
void
 
137
cluster_free (struct cluster_list *cluster)
 
138
{
 
139
  if (cluster->list)
 
140
    XFREE (MTYPE_CLUSTER_VAL, cluster->list);
 
141
  XFREE (MTYPE_CLUSTER, cluster);
 
142
}
 
143
 
 
144
struct cluster_list *
 
145
cluster_dup (struct cluster_list *cluster)
 
146
{
 
147
  struct cluster_list *new;
 
148
 
 
149
  new = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
 
150
  memset (new, 0, sizeof (struct cluster_list));
 
151
  new->length = cluster->length;
 
152
 
 
153
  if (cluster->length)
 
154
    {
 
155
      new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
 
156
      memcpy (new->list, cluster->list, cluster->length);
 
157
    }
 
158
  else
 
159
    new->list = NULL;
 
160
  
 
161
  return new;
 
162
}
 
163
 
 
164
struct cluster_list *
 
165
cluster_intern (struct cluster_list *cluster)
 
166
{
 
167
  struct cluster_list *find;
 
168
 
 
169
  find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
 
170
  find->refcnt++;
 
171
 
 
172
  return find;
 
173
}
 
174
 
 
175
void
 
176
cluster_unintern (struct cluster_list *cluster)
 
177
{
 
178
  struct cluster_list *ret;
 
179
 
 
180
  if (cluster->refcnt)
 
181
    cluster->refcnt--;
 
182
 
 
183
  if (cluster->refcnt == 0)
 
184
    {
 
185
      ret = hash_release (cluster_hash, cluster);
 
186
      cluster_free (cluster);
 
187
    }
 
188
}
 
189
 
 
190
void
 
191
cluster_init ()
 
192
{
 
193
  cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
 
194
}
 
195
 
 
196
/* Unknown transit attribute. */
 
197
struct hash *transit_hash;
 
198
 
 
199
void
 
200
transit_free (struct transit *transit)
 
201
{
 
202
  if (transit->val)
 
203
    XFREE (MTYPE_TRANSIT_VAL, transit->val);
 
204
  XFREE (MTYPE_TRANSIT, transit);
 
205
}
 
206
 
 
207
void *
 
208
transit_hash_alloc (struct transit *transit)
 
209
{
 
210
  /* Transit structure is already allocated.  */
 
211
  return transit;
 
212
}
 
213
 
 
214
struct transit *
 
215
transit_intern (struct transit *transit)
 
216
{
 
217
  struct transit *find;
 
218
 
 
219
  find = hash_get (transit_hash, transit, transit_hash_alloc);
 
220
  if (find != transit)
 
221
    transit_free (transit);
 
222
  find->refcnt++;
 
223
 
 
224
  return find;
 
225
}
 
226
 
 
227
void
 
228
transit_unintern (struct transit *transit)
 
229
{
 
230
  struct transit *ret;
 
231
 
 
232
  if (transit->refcnt)
 
233
    transit->refcnt--;
 
234
 
 
235
  if (transit->refcnt == 0)
 
236
    {
 
237
      ret = hash_release (transit_hash, transit);
 
238
      transit_free (transit);
 
239
    }
 
240
}
 
241
 
 
242
unsigned int
 
243
transit_hash_key_make (struct transit *transit)
 
244
{
 
245
  unsigned int key = 0;
 
246
  int length;
 
247
  caddr_t pnt;
 
248
 
 
249
  length = transit->length;
 
250
  pnt = (caddr_t) transit->val;
 
251
  
 
252
  while (length)
 
253
    key += pnt[--length];
 
254
 
 
255
  return key;
 
256
}
 
257
 
 
258
int
 
259
transit_hash_cmp (struct transit *transit1, struct transit *transit2)
 
260
{
 
261
  if (transit1->length == transit2->length &&
 
262
      memcmp (transit1->val, transit2->val, transit1->length) == 0)
 
263
    return 1;
 
264
  return 0;
 
265
}
 
266
 
 
267
void
 
268
transit_init ()
 
269
{
 
270
  transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
 
271
}
 
272
 
 
273
/* Attribute hash routines. */
 
274
 
 
275
struct hash *attrhash;
 
276
 
 
277
unsigned int
 
278
attrhash_key_make (struct attr *attr)
 
279
{
 
280
  unsigned int key = 0;
 
281
 
 
282
  key += attr->origin;
 
283
  key += attr->nexthop.s_addr;
 
284
  key += attr->med;
 
285
  key += attr->local_pref;
 
286
  key += attr->aggregator_as;
 
287
  key += attr->aggregator_addr.s_addr;
 
288
  key += attr->weight;
 
289
 
 
290
  key += attr->mp_nexthop_global_in.s_addr;
 
291
  if (attr->aspath)
 
292
    key += aspath_key_make (attr->aspath);
 
293
  if (attr->community)
 
294
    key += community_hash_make (attr->community);
 
295
  if (attr->ecommunity)
 
296
    key += ecommunity_hash_make (attr->ecommunity);
 
297
  if (attr->cluster)
 
298
    key += cluster_hash_key_make (attr->cluster);
 
299
  if (attr->transit)
 
300
    key += transit_hash_key_make (attr->transit);
 
301
 
 
302
#ifdef HAVE_IPV6
 
303
 {
 
304
   int i;
 
305
   
 
306
   key += attr->mp_nexthop_len;
 
307
   for (i = 0; i < 16; i++)
 
308
     key += attr->mp_nexthop_global.s6_addr[i];
 
309
   for (i = 0; i < 16; i++)
 
310
     key += attr->mp_nexthop_local.s6_addr[i];
 
311
 }
 
312
#endif /* HAVE_IPV6 */
 
313
 
 
314
  return key;
 
315
}
 
316
 
 
317
int
 
318
attrhash_cmp (struct attr *attr1, struct attr *attr2)
 
319
{
 
320
  if (attr1->flag == attr2->flag
 
321
      && attr1->origin == attr2->origin
 
322
      && attr1->nexthop.s_addr == attr2->nexthop.s_addr
 
323
      && attr1->med == attr2->med
 
324
      && attr1->local_pref == attr2->local_pref
 
325
      && attr1->aggregator_as == attr2->aggregator_as
 
326
      && attr1->aggregator_addr.s_addr == attr2->aggregator_addr.s_addr
 
327
      && attr1->weight == attr2->weight
 
328
#ifdef HAVE_IPV6
 
329
      && attr1->mp_nexthop_len == attr2->mp_nexthop_len
 
330
      && IPV6_ADDR_SAME (&attr1->mp_nexthop_global, &attr2->mp_nexthop_global)
 
331
      && IPV6_ADDR_SAME (&attr1->mp_nexthop_local, &attr2->mp_nexthop_local)
 
332
#endif /* HAVE_IPV6 */
 
333
      && IPV4_ADDR_SAME (&attr1->mp_nexthop_global_in, &attr2->mp_nexthop_global_in)
 
334
      && attr1->aspath == attr2->aspath
 
335
      && attr1->community == attr2->community
 
336
      && attr1->ecommunity == attr2->ecommunity
 
337
      && attr1->cluster == attr2->cluster
 
338
      && attr1->transit == attr2->transit)
 
339
    return 1;
 
340
  else
 
341
    return 0;
 
342
}
 
343
 
 
344
void
 
345
attrhash_init ()
 
346
{
 
347
  attrhash = hash_create (attrhash_key_make, attrhash_cmp);
 
348
}
 
349
 
 
350
void
 
351
attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
 
352
{
 
353
  struct attr *attr = backet->data;
 
354
 
 
355
  vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt, 
 
356
           inet_ntoa (attr->nexthop), VTY_NEWLINE);
 
357
}
 
358
 
 
359
void
 
360
attr_show_all (struct vty *vty)
 
361
{
 
362
  hash_iterate (attrhash, 
 
363
                (void (*)(struct hash_backet *, void *))
 
364
                attr_show_all_iterator,
 
365
                vty);
 
366
}
 
367
 
 
368
void *
 
369
bgp_attr_hash_alloc (struct attr *val)
 
370
{
 
371
  struct attr *attr;
 
372
 
 
373
  attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
 
374
  *attr = *val;
 
375
  attr->refcnt = 0;
 
376
  return attr;
 
377
}
 
378
 
 
379
/* Internet argument attribute. */
 
380
struct attr *
 
381
bgp_attr_intern (struct attr *attr)
 
382
{
 
383
  struct attr *find;
 
384
 
 
385
  /* Intern referenced strucutre. */
 
386
  if (attr->aspath)
 
387
    {
 
388
      if (! attr->aspath->refcnt)
 
389
        attr->aspath = aspath_intern (attr->aspath);
 
390
      else
 
391
        attr->aspath->refcnt++;
 
392
    }
 
393
  if (attr->community)
 
394
    {
 
395
      if (! attr->community->refcnt)
 
396
        attr->community = community_intern (attr->community);
 
397
      else
 
398
        attr->community->refcnt++;
 
399
    }
 
400
  if (attr->ecommunity)
 
401
    {
 
402
      if (! attr->ecommunity->refcnt)
 
403
        attr->ecommunity = ecommunity_intern (attr->ecommunity);
 
404
      else
 
405
        attr->ecommunity->refcnt++;
 
406
    }
 
407
  if (attr->cluster)
 
408
    {
 
409
      if (! attr->cluster->refcnt)
 
410
        attr->cluster = cluster_intern (attr->cluster);
 
411
      else
 
412
        attr->cluster->refcnt++;
 
413
    }
 
414
  if (attr->transit)
 
415
    {
 
416
      if (! attr->transit->refcnt)
 
417
        attr->transit = transit_intern (attr->transit);
 
418
      else
 
419
        attr->transit->refcnt++;
 
420
    }
 
421
 
 
422
  find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
 
423
  find->refcnt++;
 
424
 
 
425
  return find;
 
426
}
 
427
 
 
428
/* Make network statement's attribute. */
 
429
struct attr *
 
430
bgp_attr_default_set (struct attr *attr, u_char origin)
 
431
{
 
432
  memset (attr, 0, sizeof (struct attr));
 
433
 
 
434
  attr->origin = origin;
 
435
  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
 
436
  attr->aspath = aspath_empty ();
 
437
  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
 
438
  attr->weight = 32768;
 
439
  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
 
440
#ifdef HAVE_IPV6
 
441
  attr->mp_nexthop_len = 16;
 
442
#endif
 
443
  return attr;
 
444
}
 
445
 
 
446
/* Make network statement's attribute. */
 
447
struct attr *
 
448
bgp_attr_default_intern (u_char origin)
 
449
{
 
450
  struct attr attr;
 
451
  struct attr *new;
 
452
 
 
453
  memset (&attr, 0, sizeof (struct attr));
 
454
 
 
455
  attr.origin = origin;
 
456
  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
 
457
  attr.aspath = aspath_empty ();
 
458
  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
 
459
  attr.weight = 32768;
 
460
  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
 
461
#ifdef HAVE_IPV6
 
462
  attr.mp_nexthop_len = 16;
 
463
#endif
 
464
 
 
465
  new = bgp_attr_intern (&attr);
 
466
  aspath_unintern (new->aspath);
 
467
  return new;
 
468
}
 
469
 
 
470
struct attr *
 
471
bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
 
472
                           struct aspath *aspath,
 
473
                           struct community *community, int as_set)
 
474
{
 
475
  struct attr attr;
 
476
  struct attr *new;
 
477
 
 
478
  memset (&attr, 0, sizeof (struct attr));
 
479
 
 
480
  /* Origin attribute. */
 
481
  attr.origin = origin;
 
482
  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
 
483
 
 
484
  /* AS path attribute. */
 
485
  if (aspath)
 
486
    attr.aspath = aspath_intern (aspath);
 
487
  else
 
488
    attr.aspath = aspath_empty ();
 
489
  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
 
490
 
 
491
  /* Next hop attribute.  */
 
492
  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
 
493
 
 
494
  if (community)
 
495
    {
 
496
      attr.community = community;
 
497
      attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
 
498
    }
 
499
 
 
500
  attr.weight = 32768;
 
501
#ifdef HAVE_IPV6
 
502
  attr.mp_nexthop_len = 16;
 
503
#endif
 
504
  if (! as_set)
 
505
    attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
 
506
  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
 
507
  if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
 
508
    attr.aggregator_as = bgp->confed_id;
 
509
  else
 
510
    attr.aggregator_as = bgp->as;
 
511
  attr.aggregator_addr = bgp->router_id;
 
512
 
 
513
  new = bgp_attr_intern (&attr);
 
514
  aspath_unintern (new->aspath);
 
515
  return new;
 
516
}
 
517
 
 
518
/* Free bgp attribute and aspath. */
 
519
void
 
520
bgp_attr_unintern (struct attr *attr)
 
521
{
 
522
  struct attr *ret;
 
523
  struct aspath *aspath;
 
524
  struct community *community;
 
525
  struct ecommunity *ecommunity;
 
526
  struct cluster_list *cluster;
 
527
  struct transit *transit;
 
528
 
 
529
  /* Decrement attribute reference. */
 
530
  attr->refcnt--;
 
531
  aspath = attr->aspath;
 
532
  community = attr->community;
 
533
  ecommunity = attr->ecommunity;
 
534
  cluster = attr->cluster;
 
535
  transit = attr->transit;
 
536
 
 
537
  /* If reference becomes zero then free attribute object. */
 
538
  if (attr->refcnt == 0)
 
539
    {    
 
540
      ret = hash_release (attrhash, attr);
 
541
      assert (ret != NULL);
 
542
      XFREE (MTYPE_ATTR, attr);
 
543
    }
 
544
 
 
545
  /* aspath refcount shoud be decrement. */
 
546
  if (aspath)
 
547
    aspath_unintern (aspath);
 
548
  if (community)
 
549
    community_unintern (community);
 
550
  if (ecommunity)
 
551
    ecommunity_unintern (ecommunity);
 
552
  if (cluster)
 
553
    cluster_unintern (cluster);
 
554
  if (transit)
 
555
    transit_unintern (transit);
 
556
}
 
557
 
 
558
void
 
559
bgp_attr_flush (struct attr *attr)
 
560
{
 
561
  if (attr->aspath && ! attr->aspath->refcnt)
 
562
    aspath_free (attr->aspath);
 
563
  if (attr->community && ! attr->community->refcnt)
 
564
    community_free (attr->community);
 
565
  if (attr->ecommunity && ! attr->ecommunity->refcnt)
 
566
    ecommunity_free (attr->ecommunity);
 
567
  if (attr->cluster && ! attr->cluster->refcnt)
 
568
    cluster_free (attr->cluster);
 
569
  if (attr->transit && ! attr->transit->refcnt)
 
570
    transit_free (attr->transit);
 
571
}
 
572
 
 
573
/* Get origin attribute of the update message. */
 
574
int
 
575
bgp_attr_origin (struct peer *peer, bgp_size_t length, 
 
576
                 struct attr *attr, u_char flag, u_char *startp)
 
577
{
 
578
  bgp_size_t total;
 
579
 
 
580
  /* total is entire attribute length include Attribute Flags (1),
 
581
     Attribute Type code (1) and Attribute length (1 or 2).  */
 
582
  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
 
583
 
 
584
  /* If any recognized attribute has Attribute Flags that conflict
 
585
     with the Attribute Type Code, then the Error Subcode is set to
 
586
     Attribute Flags Error.  The Data field contains the erroneous
 
587
     attribute (type, length and value). */
 
588
  if (flag != BGP_ATTR_FLAG_TRANS)
 
589
    {
 
590
      zlog (peer->log, LOG_ERR, 
 
591
            "Origin attribute flag isn't transitive %d", flag);
 
592
      bgp_notify_send_with_data (peer, 
 
593
                                 BGP_NOTIFY_UPDATE_ERR, 
 
594
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
 
595
                                 startp, total);
 
596
      return -1;
 
597
    }
 
598
 
 
599
  /* If any recognized attribute has Attribute Length that conflicts
 
600
     with the expected length (based on the attribute type code), then
 
601
     the Error Subcode is set to Attribute Length Error.  The Data
 
602
     field contains the erroneous attribute (type, length and
 
603
     value). */
 
604
  if (length != 1)
 
605
    {
 
606
      zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
 
607
            length);
 
608
      bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, 
 
609
                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
 
610
                                 startp, total);
 
611
      return -1;
 
612
    }
 
613
 
 
614
  /* Fetch origin attribute. */
 
615
  attr->origin = stream_getc (BGP_INPUT (peer));
 
616
 
 
617
  /* If the ORIGIN attribute has an undefined value, then the Error
 
618
     Subcode is set to Invalid Origin Attribute.  The Data field
 
619
     contains the unrecognized attribute (type, length and value). */
 
620
  if ((attr->origin != BGP_ORIGIN_IGP)
 
621
      && (attr->origin != BGP_ORIGIN_EGP)
 
622
      && (attr->origin != BGP_ORIGIN_INCOMPLETE))
 
623
    {
 
624
      zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
 
625
              attr->origin);
 
626
 
 
627
      bgp_notify_send_with_data (peer, 
 
628
                                 BGP_NOTIFY_UPDATE_ERR, 
 
629
                                 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
 
630
                                 startp, total);
 
631
      return -1;
 
632
    }
 
633
 
 
634
  /* Set oring attribute flag. */
 
635
  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
 
636
 
 
637
  return 0;
 
638
}
 
639
 
 
640
/* Parse AS path information.  This function is wrapper of
 
641
   aspath_parse. */
 
642
int
 
643
bgp_attr_aspath (struct peer *peer, bgp_size_t length, 
 
644
                 struct attr *attr, u_char flag, u_char *startp)
 
645
{
 
646
  struct bgp *bgp;
 
647
  struct aspath *aspath;
 
648
  bgp_size_t total;
 
649
 
 
650
  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
 
651
 
 
652
  /* Flag check. */
 
653
  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
 
654
      || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
 
655
    {
 
656
      zlog (peer->log, LOG_ERR, 
 
657
            "Origin attribute flag isn't transitive %d", flag);
 
658
      bgp_notify_send_with_data (peer, 
 
659
                                 BGP_NOTIFY_UPDATE_ERR, 
 
660
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
 
661
                                 startp, total);
 
662
      return -1;
 
663
    }
 
664
 
 
665
  /* In case of IBGP, length will be zero. */
 
666
  attr->aspath = aspath_parse (stream_pnt (peer->ibuf), length);
 
667
  if (! attr->aspath)
 
668
    {
 
669
      zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
 
670
      bgp_notify_send (peer, 
 
671
                       BGP_NOTIFY_UPDATE_ERR, 
 
672
                       BGP_NOTIFY_UPDATE_MAL_AS_PATH);
 
673
      return -1;
 
674
    }
 
675
 
 
676
  bgp = peer->bgp;
 
677
    
 
678
  /* First AS check for EBGP. */
 
679
  if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
 
680
    {
 
681
      if (peer_sort (peer) == BGP_PEER_EBGP 
 
682
          && ! aspath_firstas_check (attr->aspath, peer->as))
 
683
        {
 
684
          zlog (peer->log, LOG_ERR,
 
685
                "%s incorrect first AS (must be %d)", peer->host, peer->as);
 
686
          bgp_notify_send (peer,
 
687
                           BGP_NOTIFY_UPDATE_ERR,
 
688
                           BGP_NOTIFY_UPDATE_MAL_AS_PATH);
 
689
          return -1;
 
690
        }
 
691
    }
 
692
 
 
693
  /* local-as prepend */
 
694
  if (peer->change_local_as &&
 
695
      ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
 
696
    {
 
697
      aspath = aspath_dup (attr->aspath);
 
698
      aspath = aspath_add_seq (aspath, peer->change_local_as);
 
699
      aspath_unintern (attr->aspath);
 
700
      attr->aspath = aspath_intern (aspath);
 
701
    }
 
702
 
 
703
  /* Forward pointer. */
 
704
  stream_forward (peer->ibuf, length);
 
705
 
 
706
  /* Set aspath attribute flag. */
 
707
  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
 
708
 
 
709
  return 0;
 
710
}
 
711
 
 
712
/* Nexthop attribute. */
 
713
int
 
714
bgp_attr_nexthop (struct peer *peer, bgp_size_t length, 
 
715
                  struct attr *attr, u_char flag, u_char *startp)
 
716
{
 
717
  bgp_size_t total;
 
718
 
 
719
  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
 
720
 
 
721
  /* Flag check. */
 
722
  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
 
723
      || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
 
724
    {
 
725
      zlog (peer->log, LOG_ERR, 
 
726
            "Origin attribute flag isn't transitive %d", flag);
 
727
      bgp_notify_send_with_data (peer, 
 
728
                                 BGP_NOTIFY_UPDATE_ERR, 
 
729
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
 
730
                                 startp, total);
 
731
      return -1;
 
732
    }
 
733
 
 
734
  /* Check nexthop attribute length. */
 
735
  if (length != 4)
 
736
    {
 
737
      zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
 
738
              length);
 
739
 
 
740
      bgp_notify_send_with_data (peer, 
 
741
                                 BGP_NOTIFY_UPDATE_ERR, 
 
742
                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
 
743
                                 startp, total);
 
744
      return -1;
 
745
    }
 
746
 
 
747
  attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
 
748
  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
 
749
 
 
750
  return 0;
 
751
}
 
752
 
 
753
/* MED atrribute. */
 
754
int
 
755
bgp_attr_med (struct peer *peer, bgp_size_t length, 
 
756
              struct attr *attr, u_char flag, u_char *startp)
 
757
{
 
758
  bgp_size_t total;
 
759
 
 
760
  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
 
761
 
 
762
  /* Length check. */
 
763
  if (length != 4)
 
764
    {
 
765
      zlog (peer->log, LOG_ERR, 
 
766
            "MED attribute length isn't four [%d]", length);
 
767
      
 
768
      bgp_notify_send_with_data (peer, 
 
769
                                 BGP_NOTIFY_UPDATE_ERR, 
 
770
                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
 
771
                                 startp, total);
 
772
      return -1;
 
773
    }
 
774
 
 
775
  attr->med = stream_getl (peer->ibuf);
 
776
 
 
777
  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
 
778
 
 
779
  return 0;
 
780
}
 
781
 
 
782
/* Local preference attribute. */
 
783
int
 
784
bgp_attr_local_pref (struct peer *peer, bgp_size_t length, 
 
785
                     struct attr *attr, u_char flag)
 
786
{
 
787
  /* If it is contained in an UPDATE message that is received from an
 
788
     external peer, then this attribute MUST be ignored by the
 
789
     receiving speaker. */
 
790
  if (peer_sort (peer) == BGP_PEER_EBGP)
 
791
    {
 
792
      stream_forward (peer->ibuf, length);
 
793
      return 0;
 
794
    }
 
795
 
 
796
  if (length == 4) 
 
797
    attr->local_pref = stream_getl (peer->ibuf);
 
798
  else 
 
799
    attr->local_pref = 0;
 
800
 
 
801
  /* Set atomic aggregate flag. */
 
802
  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
 
803
 
 
804
  return 0;
 
805
}
 
806
 
 
807
/* Atomic aggregate. */
 
808
int
 
809
bgp_attr_atomic (struct peer *peer, bgp_size_t length, 
 
810
                 struct attr *attr, u_char flag)
 
811
{
 
812
  if (length != 0)
 
813
    {
 
814
      zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
 
815
 
 
816
      bgp_notify_send (peer, 
 
817
                       BGP_NOTIFY_UPDATE_ERR, 
 
818
                       BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
 
819
      return -1;
 
820
    }
 
821
 
 
822
  /* Set atomic aggregate flag. */
 
823
  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
 
824
 
 
825
  return 0;
 
826
}
 
827
 
 
828
/* Aggregator attribute */
 
829
int
 
830
bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
 
831
                     struct attr *attr, u_char flag)
 
832
{
 
833
  if (length != 6)
 
834
    {
 
835
      zlog (peer->log, LOG_ERR, "Aggregator length is not 6 [%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
  attr->aggregator_as = stream_getw (peer->ibuf);
 
843
  attr->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
 
844
 
 
845
  /* Set atomic aggregate flag. */
 
846
  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
 
847
 
 
848
  return 0;
 
849
}
 
850
 
 
851
/* Community attribute. */
 
852
int
 
853
bgp_attr_community (struct peer *peer, bgp_size_t length, 
 
854
                    struct attr *attr, u_char flag)
 
855
{
 
856
  if (length == 0)
 
857
    attr->community = NULL;
 
858
  else
 
859
    {
 
860
      attr->community = community_parse (stream_pnt (peer->ibuf), length);
 
861
      stream_forward (peer->ibuf, length);
 
862
    }
 
863
 
 
864
  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
 
865
 
 
866
  return 0;
 
867
}
 
868
 
 
869
/* Originator ID attribute. */
 
870
int
 
871
bgp_attr_originator_id (struct peer *peer, bgp_size_t length, 
 
872
                        struct attr *attr, u_char flag)
 
873
{
 
874
  if (length != 4)
 
875
    {
 
876
      zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
 
877
 
 
878
      bgp_notify_send (peer, 
 
879
                       BGP_NOTIFY_UPDATE_ERR, 
 
880
                       BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
 
881
      return -1;
 
882
    }
 
883
 
 
884
  attr->originator_id.s_addr = stream_get_ipv4 (peer->ibuf);
 
885
 
 
886
  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
 
887
 
 
888
  return 0;
 
889
}
 
890
 
 
891
/* Cluster list attribute. */
 
892
int
 
893
bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, 
 
894
                       struct attr *attr, u_char flag)
 
895
{
 
896
  /* Check length. */
 
897
  if (length % 4)
 
898
    {
 
899
      zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
 
900
 
 
901
      bgp_notify_send (peer, 
 
902
                       BGP_NOTIFY_UPDATE_ERR, 
 
903
                       BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
 
904
      return -1;
 
905
    }
 
906
 
 
907
  attr->cluster = cluster_parse (stream_pnt (peer->ibuf), length);
 
908
 
 
909
  stream_forward (peer->ibuf, length);;
 
910
 
 
911
  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
 
912
 
 
913
  return 0;
 
914
}
 
915
 
 
916
/* Multiprotocol reachability information parse. */
 
917
int
 
918
bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
 
919
                    struct bgp_nlri *mp_update)
 
920
{
 
921
  u_int16_t afi;
 
922
  u_char safi;
 
923
  u_char snpa_num;
 
924
  u_char snpa_len;
 
925
  u_char *lim;
 
926
  bgp_size_t nlri_len;
 
927
  int ret;
 
928
  struct stream *s;
 
929
  
 
930
  /* Set end of packet. */
 
931
  s = peer->ibuf;
 
932
  lim = stream_pnt (s) + length;
 
933
 
 
934
  /* Load AFI, SAFI. */
 
935
  afi = stream_getw (s);
 
936
  safi = stream_getc (s);
 
937
 
 
938
  /* Get nexthop length. */
 
939
  attr->mp_nexthop_len = stream_getc (s);
 
940
 
 
941
  /* Nexthop length check. */
 
942
  switch (attr->mp_nexthop_len)
 
943
    {
 
944
    case 4:
 
945
      stream_get (&attr->mp_nexthop_global_in, s, 4);
 
946
      break;
 
947
    case 12:
 
948
      {
 
949
        u_int32_t rd_high;
 
950
        u_int32_t rd_low;
 
951
 
 
952
        rd_high = stream_getl (s);
 
953
        rd_low = stream_getl (s);
 
954
        stream_get (&attr->mp_nexthop_global_in, s, 4);
 
955
      }
 
956
      break;
 
957
#ifdef HAVE_IPV6
 
958
    case 16:
 
959
      stream_get (&attr->mp_nexthop_global, s, 16);
 
960
      break;
 
961
    case 32:
 
962
      stream_get (&attr->mp_nexthop_global, s, 16);
 
963
      stream_get (&attr->mp_nexthop_local, s, 16);
 
964
      if (! IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local))
 
965
        {
 
966
          char buf1[INET6_ADDRSTRLEN];
 
967
          char buf2[INET6_ADDRSTRLEN];
 
968
 
 
969
          if (BGP_DEBUG (update, UPDATE_IN))
 
970
            zlog_warn ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host,
 
971
                       inet_ntop (AF_INET6, &attr->mp_nexthop_global,
 
972
                                  buf1, INET6_ADDRSTRLEN),
 
973
                       inet_ntop (AF_INET6, &attr->mp_nexthop_local,
 
974
                                  buf2, INET6_ADDRSTRLEN));
 
975
 
 
976
          attr->mp_nexthop_len = 16;
 
977
        }
 
978
      break;
 
979
#endif /* HAVE_IPV6 */
 
980
    default:
 
981
      zlog_info ("Wrong multiprotocol next hop length: %d", 
 
982
                 attr->mp_nexthop_len);
 
983
      return -1;
 
984
      break;
 
985
    }
 
986
 
 
987
  snpa_num = stream_getc (s);
 
988
 
 
989
  while (snpa_num--)
 
990
    {
 
991
      snpa_len = stream_getc (s);
 
992
      stream_forward (s, (snpa_len + 1) >> 1);
 
993
    }
 
994
  
 
995
  /* If peer is based on old draft-00. I read NLRI length from the
 
996
     packet. */
 
997
  if (peer->version == BGP_VERSION_MP_4_DRAFT_00)
 
998
    {
 
999
      bgp_size_t nlri_total_len;
 
1000
      nlri_total_len = stream_getw (s);
 
1001
    }
 
1002
 
 
1003
  nlri_len = lim - stream_pnt (s);
 
1004
 
 
1005
  if (safi != BGP_SAFI_VPNV4)
 
1006
    {
 
1007
      ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
 
1008
      if (ret < 0)
 
1009
        return -1;
 
1010
    }
 
1011
 
 
1012
  mp_update->afi = afi;
 
1013
  mp_update->safi = safi;
 
1014
  mp_update->nlri = stream_pnt (s);
 
1015
  mp_update->length = nlri_len;
 
1016
 
 
1017
  stream_forward (s, nlri_len);
 
1018
 
 
1019
  return 0;
 
1020
}
 
1021
 
 
1022
/* Multiprotocol unreachable parse */
 
1023
int
 
1024
bgp_mp_unreach_parse (struct peer *peer, int length, 
 
1025
                      struct bgp_nlri *mp_withdraw)
 
1026
{
 
1027
  struct stream *s;
 
1028
  u_int16_t afi;
 
1029
  u_char safi;
 
1030
  u_char *lim;
 
1031
  u_int16_t withdraw_len;
 
1032
  int ret;
 
1033
 
 
1034
  s = peer->ibuf;
 
1035
  lim = stream_pnt (s) + length;
 
1036
 
 
1037
  afi = stream_getw (s);
 
1038
  safi = stream_getc (s);
 
1039
 
 
1040
  withdraw_len = lim - stream_pnt (s);
 
1041
 
 
1042
  if (safi != BGP_SAFI_VPNV4)
 
1043
    {
 
1044
      ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
 
1045
      if (ret < 0)
 
1046
        return -1;
 
1047
    }
 
1048
 
 
1049
  mp_withdraw->afi = afi;
 
1050
  mp_withdraw->safi = safi;
 
1051
  mp_withdraw->nlri = stream_pnt (s);
 
1052
  mp_withdraw->length = withdraw_len;
 
1053
 
 
1054
  stream_forward (s, withdraw_len);
 
1055
 
 
1056
  return 0;
 
1057
}
 
1058
 
 
1059
/* Extended Community attribute. */
 
1060
int
 
1061
bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, 
 
1062
                          struct attr *attr, u_char flag)
 
1063
{
 
1064
  if (length == 0)
 
1065
    attr->ecommunity = NULL;
 
1066
  else
 
1067
    {
 
1068
      attr->ecommunity = ecommunity_parse (stream_pnt (peer->ibuf), length);
 
1069
      stream_forward (peer->ibuf, length);
 
1070
    }
 
1071
  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
 
1072
 
 
1073
  return 0;
 
1074
}
 
1075
 
 
1076
/* BGP unknown attribute treatment. */
 
1077
int
 
1078
bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
 
1079
                  u_char type, bgp_size_t length, u_char *startp)
 
1080
{
 
1081
  bgp_size_t total;
 
1082
  struct transit *transit;
 
1083
 
 
1084
  if (BGP_DEBUG (events, EVENTS))
 
1085
    zlog (peer->log, LOG_INFO, 
 
1086
          "Unknown attribute type %d length %d is received", type, length);
 
1087
 
 
1088
  /* Forward read pointer of input stream. */
 
1089
  stream_forward (peer->ibuf, length);
 
1090
 
 
1091
  /* Adjest total length to include type and length. */
 
1092
  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
 
1093
 
 
1094
  /* If any of the mandatory well-known attributes are not recognized,
 
1095
     then the Error Subcode is set to Unrecognized Well-known
 
1096
     Attribute.  The Data field contains the unrecognized attribute
 
1097
     (type, length and value). */
 
1098
  if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
 
1099
    {
 
1100
      /* Adjust startp to do not include flag value. */
 
1101
      bgp_notify_send_with_data (peer, 
 
1102
                                 BGP_NOTIFY_UPDATE_ERR, 
 
1103
                                 BGP_NOTIFY_UPDATE_UNREC_ATTR,
 
1104
                                 startp, total);
 
1105
      return -1;
 
1106
    }
 
1107
 
 
1108
  /* Unrecognized non-transitive optional attributes must be quietly
 
1109
     ignored and not passed along to other BGP peers. */
 
1110
  if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
 
1111
    return 0;
 
1112
 
 
1113
  /* If a path with recognized transitive optional attribute is
 
1114
     accepted and passed along to other BGP peers and the Partial bit
 
1115
     in the Attribute Flags octet is set to 1 by some previous AS, it
 
1116
     is not set back to 0 by the current AS. */
 
1117
  SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
 
1118
 
 
1119
  /* Store transitive attribute to the end of attr->transit. */
 
1120
  if (! attr->transit)
 
1121
    {
 
1122
      attr->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit));
 
1123
      memset (attr->transit, 0, sizeof (struct transit));
 
1124
    }
 
1125
 
 
1126
  transit = attr->transit;
 
1127
 
 
1128
  if (transit->val)
 
1129
    transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val, 
 
1130
                             transit->length + total);
 
1131
  else
 
1132
    transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
 
1133
 
 
1134
  memcpy (transit->val + transit->length, startp, total);
 
1135
  transit->length += total;
 
1136
 
 
1137
  return 0;
 
1138
}
 
1139
 
 
1140
/* Read attribute of update packet.  This function is called from
 
1141
   bgp_update() in bgpd.c.  */
 
1142
int
 
1143
bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
 
1144
                struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
 
1145
{
 
1146
  int ret;
 
1147
  u_char flag;
 
1148
  u_char type;
 
1149
  bgp_size_t length;
 
1150
  u_char *startp, *endp;
 
1151
  u_char *attr_endp;
 
1152
  u_char seen[BGP_ATTR_BITMAP_SIZE];
 
1153
 
 
1154
  /* Initialize bitmap. */
 
1155
  memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
 
1156
 
 
1157
  /* End pointer of BGP attribute. */
 
1158
  endp = BGP_INPUT_PNT (peer) + size;
 
1159
 
 
1160
  /* Get attributes to the end of attribute length. */
 
1161
  while (BGP_INPUT_PNT (peer) < endp)
 
1162
    {
 
1163
      /* Check remaining length check.*/
 
1164
      if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
 
1165
        {
 
1166
          zlog (peer->log, LOG_WARNING, 
 
1167
                "%s error BGP attribute length %d is smaller than min len",
 
1168
                peer->host, endp - STREAM_PNT (BGP_INPUT (peer)));
 
1169
 
 
1170
          bgp_notify_send (peer, 
 
1171
                           BGP_NOTIFY_UPDATE_ERR, 
 
1172
                           BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
 
1173
          return -1;
 
1174
        }
 
1175
 
 
1176
      /* Fetch attribute flag and type. */
 
1177
      startp = BGP_INPUT_PNT (peer);
 
1178
      flag = stream_getc (BGP_INPUT (peer));
 
1179
      type = stream_getc (BGP_INPUT (peer));
 
1180
 
 
1181
      /* Check extended attribue length bit. */
 
1182
      if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
 
1183
        length = stream_getw (BGP_INPUT (peer));
 
1184
      else
 
1185
        length = stream_getc (BGP_INPUT (peer));
 
1186
      
 
1187
      /* If any attribute appears more than once in the UPDATE
 
1188
         message, then the Error Subcode is set to Malformed Attribute
 
1189
         List. */
 
1190
 
 
1191
      if (CHECK_BITMAP (seen, type))
 
1192
        {
 
1193
          zlog (peer->log, LOG_WARNING,
 
1194
                "%s error BGP attribute type %d appears twice in a message",
 
1195
                peer->host, type);
 
1196
 
 
1197
          bgp_notify_send (peer, 
 
1198
                           BGP_NOTIFY_UPDATE_ERR, 
 
1199
                           BGP_NOTIFY_UPDATE_MAL_ATTR);
 
1200
          return -1;
 
1201
        }
 
1202
 
 
1203
      /* Set type to bitmap to check duplicate attribute.  `type' is
 
1204
         unsigned char so it never overflow bitmap range. */
 
1205
 
 
1206
      SET_BITMAP (seen, type);
 
1207
 
 
1208
      /* Overflow check. */
 
1209
      attr_endp =  BGP_INPUT_PNT (peer) + length;
 
1210
 
 
1211
      if (attr_endp > endp)
 
1212
        {
 
1213
          zlog (peer->log, LOG_WARNING, 
 
1214
                "%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);
 
1215
          bgp_notify_send (peer, 
 
1216
                           BGP_NOTIFY_UPDATE_ERR, 
 
1217
                           BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
 
1218
          return -1;
 
1219
        }
 
1220
 
 
1221
      /* OK check attribute and store it's value. */
 
1222
      switch (type)
 
1223
        {
 
1224
        case BGP_ATTR_ORIGIN:
 
1225
          ret = bgp_attr_origin (peer, length, attr, flag, startp);
 
1226
          break;
 
1227
        case BGP_ATTR_AS_PATH:
 
1228
          ret = bgp_attr_aspath (peer, length, attr, flag, startp);
 
1229
          break;
 
1230
        case BGP_ATTR_NEXT_HOP: 
 
1231
          ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
 
1232
          break;
 
1233
        case BGP_ATTR_MULTI_EXIT_DISC:
 
1234
          ret = bgp_attr_med (peer, length, attr, flag, startp);
 
1235
          break;
 
1236
        case BGP_ATTR_LOCAL_PREF:
 
1237
          ret = bgp_attr_local_pref (peer, length, attr, flag);
 
1238
          break;
 
1239
        case BGP_ATTR_ATOMIC_AGGREGATE:
 
1240
          ret = bgp_attr_atomic (peer, length, attr, flag);
 
1241
          break;
 
1242
        case BGP_ATTR_AGGREGATOR:
 
1243
          ret = bgp_attr_aggregator (peer, length, attr, flag);
 
1244
          break;
 
1245
        case BGP_ATTR_COMMUNITIES:
 
1246
          ret = bgp_attr_community (peer, length, attr, flag);
 
1247
          break;
 
1248
        case BGP_ATTR_ORIGINATOR_ID:
 
1249
          ret = bgp_attr_originator_id (peer, length, attr, flag);
 
1250
          break;
 
1251
        case BGP_ATTR_CLUSTER_LIST:
 
1252
          ret = bgp_attr_cluster_list (peer, length, attr, flag);
 
1253
          break;
 
1254
        case BGP_ATTR_MP_REACH_NLRI:
 
1255
          ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
 
1256
          break;
 
1257
        case BGP_ATTR_MP_UNREACH_NLRI:
 
1258
          ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
 
1259
          break;
 
1260
        case BGP_ATTR_EXT_COMMUNITIES:
 
1261
          ret = bgp_attr_ext_communities (peer, length, attr, flag);
 
1262
          break;
 
1263
        default:
 
1264
          ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
 
1265
          break;
 
1266
        }
 
1267
 
 
1268
      /* If error occured immediately return to the caller. */
 
1269
      if (ret < 0)
 
1270
        return ret;
 
1271
 
 
1272
      /* Check the fetched length. */
 
1273
      if (BGP_INPUT_PNT (peer) != attr_endp)
 
1274
        {
 
1275
          zlog (peer->log, LOG_WARNING, 
 
1276
                "%s BGP attribute fetch error", peer->host);
 
1277
          bgp_notify_send (peer, 
 
1278
                           BGP_NOTIFY_UPDATE_ERR, 
 
1279
                           BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
 
1280
          return -1;
 
1281
        }
 
1282
    }
 
1283
 
 
1284
  /* Check final read pointer is same as end pointer. */
 
1285
  if (BGP_INPUT_PNT (peer) != endp)
 
1286
    {
 
1287
      zlog (peer->log, LOG_WARNING, 
 
1288
            "%s BGP attribute length mismatch", peer->host);
 
1289
      bgp_notify_send (peer, 
 
1290
                       BGP_NOTIFY_UPDATE_ERR, 
 
1291
                       BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
 
1292
      return -1;
 
1293
    }
 
1294
 
 
1295
  /* Finally intern unknown attribute. */
 
1296
  if (attr->transit)
 
1297
    attr->transit = transit_intern (attr->transit);
 
1298
 
 
1299
  return 0;
 
1300
}
 
1301
 
 
1302
/* Well-known attribute check. */
 
1303
int
 
1304
bgp_attr_check (struct peer *peer, struct attr *attr)
 
1305
{
 
1306
  u_char type = 0;
 
1307
  
 
1308
  if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
 
1309
    type = BGP_ATTR_ORIGIN;
 
1310
 
 
1311
  if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
 
1312
    type = BGP_ATTR_AS_PATH;
 
1313
 
 
1314
  if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
 
1315
    type = BGP_ATTR_NEXT_HOP;
 
1316
 
 
1317
  if (peer_sort (peer) == BGP_PEER_IBGP
 
1318
      && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
 
1319
    type = BGP_ATTR_LOCAL_PREF;
 
1320
 
 
1321
  if (type)
 
1322
    {
 
1323
      zlog (peer->log, LOG_WARNING, 
 
1324
            "%s Missing well-known attribute %d.",
 
1325
            peer->host, type);
 
1326
      bgp_notify_send_with_data (peer, 
 
1327
                                 BGP_NOTIFY_UPDATE_ERR, 
 
1328
                                 BGP_NOTIFY_UPDATE_MISS_ATTR,
 
1329
                                 &type, 1);
 
1330
      return -1;
 
1331
    }
 
1332
  return 0;
 
1333
}
 
1334
 
 
1335
int stream_put_prefix (struct stream *, struct prefix *);
 
1336
 
 
1337
/* Make attribute packet. */
 
1338
bgp_size_t
 
1339
bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
 
1340
                      struct stream *s, struct attr *attr, struct prefix *p,
 
1341
                      afi_t afi, safi_t safi, struct peer *from,
 
1342
                      struct prefix_rd *prd, u_char *tag)
 
1343
{
 
1344
  unsigned long cp;
 
1345
  struct aspath *aspath;
 
1346
 
 
1347
  if (! bgp)
 
1348
    bgp = bgp_get_default ();
 
1349
 
 
1350
  /* Remember current pointer. */
 
1351
  cp = stream_get_putp (s);
 
1352
 
 
1353
  /* Origin attribute. */
 
1354
  stream_putc (s, BGP_ATTR_FLAG_TRANS);
 
1355
  stream_putc (s, BGP_ATTR_ORIGIN);
 
1356
  stream_putc (s, 1);
 
1357
  stream_putc (s, attr->origin);
 
1358
 
 
1359
  /* AS path attribute. */
 
1360
 
 
1361
  /* If remote-peer is EBGP */
 
1362
  if (peer_sort (peer) == BGP_PEER_EBGP
 
1363
      && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
 
1364
          || attr->aspath->length == 0)
 
1365
      && ! (CHECK_FLAG (from->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)
 
1366
            && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
 
1367
    {    
 
1368
      aspath = aspath_dup (attr->aspath);
 
1369
 
 
1370
      if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
 
1371
        {
 
1372
          /* Strip the confed info, and then stuff our path CONFED_ID
 
1373
             on the front */
 
1374
          aspath = aspath_delete_confed_seq (aspath);
 
1375
          aspath = aspath_add_seq (aspath, bgp->confed_id);
 
1376
        }
 
1377
      else
 
1378
        {
 
1379
          aspath = aspath_add_seq (aspath, peer->local_as);
 
1380
          if (peer->change_local_as)
 
1381
            aspath = aspath_add_seq (aspath, peer->change_local_as);
 
1382
        }
 
1383
    }
 
1384
  else if (peer_sort (peer) == BGP_PEER_CONFED)
 
1385
    {
 
1386
      /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
 
1387
      aspath = aspath_dup (attr->aspath);
 
1388
      aspath = aspath_add_confed_seq (aspath, peer->local_as);
 
1389
    }
 
1390
  else
 
1391
    aspath = attr->aspath;
 
1392
 
 
1393
  /* AS path attribute extended length bit check. */
 
1394
  if (aspath->length > 255)
 
1395
    {
 
1396
      stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
 
1397
      stream_putc (s, BGP_ATTR_AS_PATH);
 
1398
      stream_putw (s, aspath->length);
 
1399
    }
 
1400
  else
 
1401
    {
 
1402
      stream_putc (s, BGP_ATTR_FLAG_TRANS);
 
1403
      stream_putc(s, BGP_ATTR_AS_PATH);
 
1404
      stream_putc (s, aspath->length);
 
1405
    }
 
1406
  stream_put (s, aspath->data, aspath->length);
 
1407
 
 
1408
  if (aspath != attr->aspath)
 
1409
    aspath_free (aspath);
 
1410
 
 
1411
  /* Nexthop attribute. */
 
1412
  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
 
1413
    {
 
1414
      stream_putc (s, BGP_ATTR_FLAG_TRANS);
 
1415
      stream_putc (s, BGP_ATTR_NEXT_HOP);
 
1416
      stream_putc (s, 4);
 
1417
      if (safi == SAFI_MPLS_VPN)
 
1418
        {
 
1419
          if (attr->nexthop.s_addr == 0)
 
1420
            stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
 
1421
          else
 
1422
            stream_put_ipv4 (s, attr->nexthop.s_addr);
 
1423
        }
 
1424
      else
 
1425
        stream_put_ipv4 (s, attr->nexthop.s_addr);
 
1426
    }
 
1427
 
 
1428
  /* MED attribute. */
 
1429
  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
 
1430
    {
 
1431
      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
 
1432
      stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
 
1433
      stream_putc (s, 4);
 
1434
      stream_putl (s, attr->med);
 
1435
    }
 
1436
 
 
1437
  /* Local preference. */
 
1438
  if (peer_sort (peer) == BGP_PEER_IBGP ||
 
1439
      peer_sort (peer) == BGP_PEER_CONFED)
 
1440
    {
 
1441
      stream_putc (s, BGP_ATTR_FLAG_TRANS);
 
1442
      stream_putc (s, BGP_ATTR_LOCAL_PREF);
 
1443
      stream_putc (s, 4);
 
1444
      stream_putl (s, attr->local_pref);
 
1445
    }
 
1446
 
 
1447
  /* Atomic aggregate. */
 
1448
  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
 
1449
    {
 
1450
      stream_putc (s, BGP_ATTR_FLAG_TRANS);
 
1451
      stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
 
1452
      stream_putc (s, 0);
 
1453
    }
 
1454
 
 
1455
  /* Aggregator. */
 
1456
  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
 
1457
    {
 
1458
      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
 
1459
      stream_putc (s, BGP_ATTR_AGGREGATOR);
 
1460
      stream_putc (s, 6);
 
1461
      stream_putw (s, attr->aggregator_as);
 
1462
      stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
 
1463
    }
 
1464
 
 
1465
  /* Community attribute. */
 
1466
  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) 
 
1467
      && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
 
1468
    {
 
1469
      if (attr->community->size * 4 > 255)
 
1470
        {
 
1471
          stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
 
1472
          stream_putc (s, BGP_ATTR_COMMUNITIES);
 
1473
          stream_putw (s, attr->community->size * 4);
 
1474
        }
 
1475
      else
 
1476
        {
 
1477
          stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
 
1478
          stream_putc (s, BGP_ATTR_COMMUNITIES);
 
1479
          stream_putc (s, attr->community->size * 4);
 
1480
        }
 
1481
      stream_put (s, attr->community->val, attr->community->size * 4);
 
1482
    }
 
1483
 
 
1484
  /* Route Reflector. */
 
1485
  if (peer_sort (peer) == BGP_PEER_IBGP
 
1486
      && from
 
1487
      && peer_sort (from) == BGP_PEER_IBGP)
 
1488
    {
 
1489
      /* Originator ID. */
 
1490
      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
 
1491
      stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
 
1492
      stream_putc (s, 4);
 
1493
 
 
1494
      if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
 
1495
        stream_put_in_addr (s, &attr->originator_id);
 
1496
      else
 
1497
        {
 
1498
          if (from)
 
1499
            stream_put_in_addr (s, &from->remote_id);
 
1500
          else
 
1501
            stream_put_in_addr (s, &attr->originator_id);
 
1502
        }
 
1503
 
 
1504
      /* Cluster list. */
 
1505
      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
 
1506
      stream_putc (s, BGP_ATTR_CLUSTER_LIST);
 
1507
      
 
1508
      if (attr->cluster)
 
1509
        {
 
1510
          stream_putc (s, attr->cluster->length + 4);
 
1511
          /* If this peer configuration's parent BGP has cluster_id. */
 
1512
          if (bgp->config & BGP_CONFIG_CLUSTER_ID)
 
1513
            stream_put_in_addr (s, &bgp->cluster_id);
 
1514
          else
 
1515
            stream_put_in_addr (s, &bgp->router_id);
 
1516
          stream_put (s, attr->cluster->list, attr->cluster->length);
 
1517
        }
 
1518
      else
 
1519
        {
 
1520
          stream_putc (s, 4);
 
1521
          /* If this peer configuration's parent BGP has cluster_id. */
 
1522
          if (bgp->config & BGP_CONFIG_CLUSTER_ID)
 
1523
            stream_put_in_addr (s, &bgp->cluster_id);
 
1524
          else
 
1525
            stream_put_in_addr (s, &bgp->router_id);
 
1526
        }
 
1527
    }
 
1528
 
 
1529
#ifdef HAVE_IPV6
 
1530
  /* If p is IPv6 address put it into attribute. */
 
1531
  if (p->family == AF_INET6)
 
1532
    {
 
1533
      unsigned long sizep;
 
1534
      unsigned long draftp = 0;
 
1535
 
 
1536
      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
 
1537
      stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
 
1538
      sizep = stream_get_putp (s);
 
1539
      stream_putc (s, 0);       /* Length of this attribute. */
 
1540
      stream_putw (s, AFI_IP6); /* AFI */
 
1541
      stream_putc (s, safi);    /* SAFI */
 
1542
 
 
1543
      stream_putc (s, attr->mp_nexthop_len);
 
1544
 
 
1545
      if (attr->mp_nexthop_len == 16)
 
1546
        stream_put (s, &attr->mp_nexthop_global, 16);
 
1547
      else if (attr->mp_nexthop_len == 32)
 
1548
        {
 
1549
          stream_put (s, &attr->mp_nexthop_global, 16);
 
1550
          stream_put (s, &attr->mp_nexthop_local, 16);
 
1551
        }
 
1552
      
 
1553
      /* SNPA */
 
1554
      stream_putc (s, 0);
 
1555
 
 
1556
      /* In case of old draft BGP-4+. */
 
1557
      if (peer->version == BGP_VERSION_MP_4_DRAFT_00)
 
1558
        {
 
1559
          draftp = stream_get_putp (s);
 
1560
          stream_putw (s, 0);
 
1561
        }
 
1562
      
 
1563
      /* Prefix write. */
 
1564
      stream_put_prefix (s, p);
 
1565
 
 
1566
      /* Set MP attribute length. */
 
1567
      stream_putc_at (s, sizep, (stream_get_putp (s) - sizep) - 1);
 
1568
 
 
1569
      /* In case of old draft BGP-4+. */
 
1570
      if (peer->version == BGP_VERSION_MP_4_DRAFT_00)
 
1571
        stream_putw_at (s, draftp, (stream_get_putp (s) - draftp) - 2);
 
1572
    }
 
1573
#endif /* HAVE_IPV6 */
 
1574
 
 
1575
  if (p->family == AF_INET && safi == SAFI_MULTICAST)
 
1576
    {
 
1577
      unsigned long sizep;
 
1578
      unsigned long draftp = 0;
 
1579
 
 
1580
      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
 
1581
      stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
 
1582
      sizep = stream_get_putp (s);
 
1583
      stream_putc (s, 0);       /* Length of this attribute. */
 
1584
      stream_putw (s, AFI_IP);  /* AFI */
 
1585
      stream_putc (s, SAFI_MULTICAST);  /* SAFI */
 
1586
 
 
1587
      stream_putc (s, 4);
 
1588
      stream_put_ipv4 (s, attr->nexthop.s_addr);
 
1589
 
 
1590
      /* SNPA */
 
1591
      stream_putc (s, 0);
 
1592
 
 
1593
      /* In case of old draft BGP-4+. */
 
1594
      if (peer->version == BGP_VERSION_MP_4_DRAFT_00)
 
1595
        {
 
1596
          draftp = stream_get_putp (s);
 
1597
          stream_putw (s, 0);
 
1598
        }
 
1599
      
 
1600
      /* Prefix write. */
 
1601
      stream_put_prefix (s, p);
 
1602
 
 
1603
      /* Set MP attribute length. */
 
1604
      stream_putc_at (s, sizep, (stream_get_putp (s) - sizep) - 1);
 
1605
 
 
1606
      /* In case of old draft BGP-4+. */
 
1607
      if (peer->version == BGP_VERSION_MP_4_DRAFT_00)
 
1608
        stream_putw_at (s, draftp, (stream_get_putp (s) - draftp) - 2);
 
1609
    }
 
1610
 
 
1611
  if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
 
1612
    {
 
1613
      unsigned long sizep;
 
1614
      unsigned long draftp = 0;
 
1615
 
 
1616
      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
 
1617
      stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
 
1618
      sizep = stream_get_putp (s);
 
1619
      stream_putc (s, 0);       /* Length of this attribute. */
 
1620
      stream_putw (s, AFI_IP);  /* AFI */
 
1621
      stream_putc (s, BGP_SAFI_VPNV4);  /* SAFI */
 
1622
 
 
1623
      stream_putc (s, 12);
 
1624
      stream_putl (s, 0);
 
1625
      stream_putl (s, 0);
 
1626
      stream_put (s, &attr->mp_nexthop_global_in, 4);
 
1627
 
 
1628
      /* SNPA */
 
1629
      stream_putc (s, 0);
 
1630
 
 
1631
      /* In case of old draft BGP-4+. */
 
1632
      if (peer->version == BGP_VERSION_MP_4_DRAFT_00)
 
1633
        {
 
1634
          draftp = stream_get_putp (s);
 
1635
          stream_putw (s, 0);
 
1636
        }
 
1637
      
 
1638
      /* Tag, RD, Prefix write. */
 
1639
      stream_putc (s, p->prefixlen + 88);
 
1640
      stream_put (s, tag, 3);
 
1641
      stream_put (s, prd->val, 8);
 
1642
      stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
 
1643
 
 
1644
      /* Set MP attribute length. */
 
1645
      stream_putc_at (s, sizep, (stream_get_putp (s) - sizep) - 1);
 
1646
 
 
1647
      /* In case of old draft BGP-4+. */
 
1648
      if (peer->version == BGP_VERSION_MP_4_DRAFT_00)
 
1649
        stream_putw_at (s, draftp, (stream_get_putp (s) - draftp) - 2);
 
1650
    }
 
1651
 
 
1652
  /* Extended Communities attribute. */
 
1653
  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) 
 
1654
      && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
 
1655
    {
 
1656
      if (attr->ecommunity->size * 8 > 255)
 
1657
        {
 
1658
          stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
 
1659
          stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
 
1660
          stream_putw (s, attr->ecommunity->size * 8);
 
1661
        }
 
1662
      else
 
1663
        {
 
1664
          stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
 
1665
          stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
 
1666
          stream_putc (s, attr->ecommunity->size * 8);
 
1667
        }
 
1668
      stream_put (s, attr->ecommunity->val, attr->ecommunity->size * 8);
 
1669
    }
 
1670
 
 
1671
  /* Unknown transit attribute. */
 
1672
  if (attr->transit)
 
1673
    stream_put (s, attr->transit->val, attr->transit->length);
 
1674
 
 
1675
  /* Return total size of attribute. */
 
1676
  return stream_get_putp (s) - cp;
 
1677
}
 
1678
 
 
1679
bgp_size_t
 
1680
bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
 
1681
                     afi_t afi, safi_t safi, struct prefix_rd *prd,
 
1682
                     u_char *tag)
 
1683
{
 
1684
  unsigned long cp;
 
1685
  unsigned long attrlen_pnt;
 
1686
  bgp_size_t size;
 
1687
 
 
1688
  cp = stream_get_putp (s);
 
1689
 
 
1690
  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
 
1691
  stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
 
1692
 
 
1693
  attrlen_pnt = stream_get_putp (s);
 
1694
  stream_putc (s, 0);           /* Length of this attribute. */
 
1695
 
 
1696
  stream_putw (s, family2afi (p->family));
 
1697
 
 
1698
  if (safi == SAFI_MPLS_VPN)
 
1699
    {
 
1700
      /* SAFI */
 
1701
      stream_putc (s, BGP_SAFI_VPNV4);
 
1702
 
 
1703
      /* prefix. */
 
1704
      stream_putc (s, p->prefixlen + 88);
 
1705
      stream_put (s, tag, 3);
 
1706
      stream_put (s, prd->val, 8);
 
1707
      stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
 
1708
    }
 
1709
  else
 
1710
    {
 
1711
      /* SAFI */
 
1712
      stream_putc (s, safi);
 
1713
 
 
1714
      /* prefix */
 
1715
      stream_put_prefix (s, p);
 
1716
    }
 
1717
 
 
1718
  /* Set MP attribute length. */
 
1719
  size = stream_get_putp (s) - attrlen_pnt - 1;
 
1720
  stream_putc_at (s, attrlen_pnt, size);
 
1721
 
 
1722
  return stream_get_putp (s) - cp;
 
1723
}
 
1724
 
 
1725
/* Initialization of attribute. */
 
1726
void
 
1727
bgp_attr_init ()
 
1728
{
 
1729
  void attrhash_init ();
 
1730
 
 
1731
  aspath_init ();
 
1732
  attrhash_init ();
 
1733
  community_init ();
 
1734
  ecommunity_init ();
 
1735
  cluster_init ();
 
1736
  transit_init ();
 
1737
}
 
1738
 
 
1739
/* Make attribute packet. */
 
1740
void
 
1741
bgp_dump_routes_attr (struct stream *s, struct attr *attr, 
 
1742
                      struct prefix *prefix)
 
1743
{
 
1744
  unsigned long cp;
 
1745
  unsigned long len;
 
1746
  struct aspath *aspath;
 
1747
 
 
1748
  /* Remember current pointer. */
 
1749
  cp = stream_get_putp (s);
 
1750
 
 
1751
  /* Place holder of length. */
 
1752
  stream_putw (s, 0);
 
1753
 
 
1754
  /* Origin attribute. */
 
1755
  stream_putc (s, BGP_ATTR_FLAG_TRANS);
 
1756
  stream_putc (s, BGP_ATTR_ORIGIN);
 
1757
  stream_putc (s, 1);
 
1758
  stream_putc (s, attr->origin);
 
1759
 
 
1760
  aspath = attr->aspath;
 
1761
 
 
1762
  if (aspath->length > 255)
 
1763
    {
 
1764
      stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
 
1765
      stream_putc (s, BGP_ATTR_AS_PATH);
 
1766
      stream_putw (s, aspath->length);
 
1767
    }
 
1768
  else
 
1769
    {
 
1770
      stream_putc (s, BGP_ATTR_FLAG_TRANS);
 
1771
      stream_putc (s, BGP_ATTR_AS_PATH);
 
1772
      stream_putc (s, aspath->length);
 
1773
    }
 
1774
  stream_put (s, aspath->data, aspath->length);
 
1775
 
 
1776
  /* Nexthop attribute. */
 
1777
  /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
 
1778
  if(prefix != NULL
 
1779
#ifdef HAVE_IPV6
 
1780
     && prefix->family != AF_INET6
 
1781
#endif /* HAVE_IPV6 */
 
1782
     )
 
1783
    {
 
1784
      stream_putc (s, BGP_ATTR_FLAG_TRANS);
 
1785
      stream_putc (s, BGP_ATTR_NEXT_HOP);
 
1786
      stream_putc (s, 4);
 
1787
      stream_put_ipv4 (s, attr->nexthop.s_addr);
 
1788
    }
 
1789
 
 
1790
  /* MED attribute. */
 
1791
  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
 
1792
    {
 
1793
      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
 
1794
      stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
 
1795
      stream_putc (s, 4);
 
1796
      stream_putl (s, attr->med);
 
1797
    }
 
1798
 
 
1799
  /* Local preference. */
 
1800
  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
 
1801
    {
 
1802
      stream_putc (s, BGP_ATTR_FLAG_TRANS);
 
1803
      stream_putc (s, BGP_ATTR_LOCAL_PREF);
 
1804
      stream_putc (s, 4);
 
1805
      stream_putl (s, attr->local_pref);
 
1806
    }
 
1807
 
 
1808
  /* Atomic aggregate. */
 
1809
  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
 
1810
    {
 
1811
      stream_putc (s, BGP_ATTR_FLAG_TRANS);
 
1812
      stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
 
1813
      stream_putc (s, 0);
 
1814
    }
 
1815
 
 
1816
  /* Aggregator. */
 
1817
  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
 
1818
    {
 
1819
      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
 
1820
      stream_putc (s, BGP_ATTR_AGGREGATOR);
 
1821
      stream_putc (s, 6);
 
1822
      stream_putw (s, attr->aggregator_as);
 
1823
      stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
 
1824
    }
 
1825
 
 
1826
  /* Community attribute. */
 
1827
  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
 
1828
    {
 
1829
      if (attr->community->size * 4 > 255)
 
1830
        {
 
1831
          stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
 
1832
          stream_putc (s, BGP_ATTR_COMMUNITIES);
 
1833
          stream_putw (s, attr->community->size * 4);
 
1834
        }
 
1835
      else
 
1836
        {
 
1837
          stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
 
1838
          stream_putc (s, BGP_ATTR_COMMUNITIES);
 
1839
          stream_putc (s, attr->community->size * 4);
 
1840
        }
 
1841
      stream_put (s, attr->community->val, attr->community->size * 4);
 
1842
    }
 
1843
 
 
1844
#ifdef HAVE_IPV6
 
1845
  /* Add a MP_NLRI attribute to dump the IPv6 next hop */
 
1846
  if(prefix != NULL && prefix->family == AF_INET6 && 
 
1847
     (attr->mp_nexthop_len == 16 || attr->mp_nexthop_len == 32) )
 
1848
    {
 
1849
      int sizep;
 
1850
 
 
1851
      stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
 
1852
      stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
 
1853
      sizep = stream_get_putp (s);
 
1854
 
 
1855
      /* MP header */
 
1856
      stream_putc (s, 0);               /* Length of this attribute. */
 
1857
      stream_putw(s, AFI_IP6);          /* AFI */
 
1858
      stream_putc(s, SAFI_UNICAST);     /* SAFI */
 
1859
 
 
1860
      /* Next hop */
 
1861
      stream_putc(s, attr->mp_nexthop_len);
 
1862
      stream_put(s, &attr->mp_nexthop_global, 16);
 
1863
      if(attr->mp_nexthop_len == 32)
 
1864
        stream_put(s, &attr->mp_nexthop_local, 16);
 
1865
 
 
1866
      /* SNPA */
 
1867
      stream_putc(s, 0);
 
1868
 
 
1869
      /* Prefix */
 
1870
      stream_put_prefix(s, prefix);
 
1871
 
 
1872
      /* Set MP attribute length. */
 
1873
      stream_putc_at (s, sizep, (stream_get_putp (s) - sizep) - 1);
 
1874
    }
 
1875
#endif /* HAVE_IPV6 */
 
1876
 
 
1877
  /* Return total size of attribute. */
 
1878
  len = stream_get_putp (s) - cp - 2;
 
1879
  stream_putw_at (s, cp, len);
 
1880
}