Annotation of embedaddon/quagga/bgpd/bgp_attr.c, revision 1.1
1.1 ! misho 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: #include "jhash.h"
! 32:
! 33: #include "bgpd/bgpd.h"
! 34: #include "bgpd/bgp_attr.h"
! 35: #include "bgpd/bgp_route.h"
! 36: #include "bgpd/bgp_aspath.h"
! 37: #include "bgpd/bgp_community.h"
! 38: #include "bgpd/bgp_debug.h"
! 39: #include "bgpd/bgp_packet.h"
! 40: #include "bgpd/bgp_ecommunity.h"
! 41:
! 42: /* Attribute strings for logging. */
! 43: static const struct message attr_str [] =
! 44: {
! 45: { BGP_ATTR_ORIGIN, "ORIGIN" },
! 46: { BGP_ATTR_AS_PATH, "AS_PATH" },
! 47: { BGP_ATTR_NEXT_HOP, "NEXT_HOP" },
! 48: { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
! 49: { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" },
! 50: { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
! 51: { BGP_ATTR_AGGREGATOR, "AGGREGATOR" },
! 52: { BGP_ATTR_COMMUNITIES, "COMMUNITY" },
! 53: { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" },
! 54: { BGP_ATTR_CLUSTER_LIST, "CLUSTERLIST" },
! 55: { BGP_ATTR_DPA, "DPA" },
! 56: { BGP_ATTR_ADVERTISER, "ADVERTISER"} ,
! 57: { BGP_ATTR_RCID_PATH, "RCID_PATH" },
! 58: { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
! 59: { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
! 60: { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" },
! 61: { BGP_ATTR_AS4_PATH, "AS4_PATH" },
! 62: { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" },
! 63: { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" },
! 64: };
! 65: static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
! 66:
! 67: static struct hash *cluster_hash;
! 68:
! 69: static void *
! 70: cluster_hash_alloc (void *p)
! 71: {
! 72: struct cluster_list * val = (struct cluster_list *) p;
! 73: struct cluster_list *cluster;
! 74:
! 75: cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
! 76: cluster->length = val->length;
! 77:
! 78: if (cluster->length)
! 79: {
! 80: cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
! 81: memcpy (cluster->list, val->list, val->length);
! 82: }
! 83: else
! 84: cluster->list = NULL;
! 85:
! 86: cluster->refcnt = 0;
! 87:
! 88: return cluster;
! 89: }
! 90:
! 91: /* Cluster list related functions. */
! 92: static struct cluster_list *
! 93: cluster_parse (struct in_addr * pnt, int length)
! 94: {
! 95: struct cluster_list tmp;
! 96: struct cluster_list *cluster;
! 97:
! 98: tmp.length = length;
! 99: tmp.list = pnt;
! 100:
! 101: cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
! 102: cluster->refcnt++;
! 103: return cluster;
! 104: }
! 105:
! 106: int
! 107: cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
! 108: {
! 109: int i;
! 110:
! 111: for (i = 0; i < cluster->length / 4; i++)
! 112: if (cluster->list[i].s_addr == originator.s_addr)
! 113: return 1;
! 114: return 0;
! 115: }
! 116:
! 117: static unsigned int
! 118: cluster_hash_key_make (void *p)
! 119: {
! 120: const struct cluster_list *cluster = p;
! 121:
! 122: return jhash(cluster->list, cluster->length, 0);
! 123: }
! 124:
! 125: static int
! 126: cluster_hash_cmp (const void *p1, const void *p2)
! 127: {
! 128: const struct cluster_list * cluster1 = p1;
! 129: const struct cluster_list * cluster2 = p2;
! 130:
! 131: return (cluster1->length == cluster2->length &&
! 132: memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
! 133: }
! 134:
! 135: static void
! 136: cluster_free (struct cluster_list *cluster)
! 137: {
! 138: if (cluster->list)
! 139: XFREE (MTYPE_CLUSTER_VAL, cluster->list);
! 140: XFREE (MTYPE_CLUSTER, cluster);
! 141: }
! 142:
! 143: #if 0
! 144: static struct cluster_list *
! 145: cluster_dup (struct cluster_list *cluster)
! 146: {
! 147: struct cluster_list *new;
! 148:
! 149: new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
! 150: new->length = cluster->length;
! 151:
! 152: if (cluster->length)
! 153: {
! 154: new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
! 155: memcpy (new->list, cluster->list, cluster->length);
! 156: }
! 157: else
! 158: new->list = NULL;
! 159:
! 160: return new;
! 161: }
! 162: #endif
! 163:
! 164: static 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: static void
! 191: cluster_init (void)
! 192: {
! 193: cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
! 194: }
! 195:
! 196: static void
! 197: cluster_finish (void)
! 198: {
! 199: hash_free (cluster_hash);
! 200: cluster_hash = NULL;
! 201: }
! 202:
! 203: /* Unknown transit attribute. */
! 204: static struct hash *transit_hash;
! 205:
! 206: static void
! 207: transit_free (struct transit *transit)
! 208: {
! 209: if (transit->val)
! 210: XFREE (MTYPE_TRANSIT_VAL, transit->val);
! 211: XFREE (MTYPE_TRANSIT, transit);
! 212: }
! 213:
! 214:
! 215: static void *
! 216: transit_hash_alloc (void *p)
! 217: {
! 218: /* Transit structure is already allocated. */
! 219: return p;
! 220: }
! 221:
! 222: static struct transit *
! 223: transit_intern (struct transit *transit)
! 224: {
! 225: struct transit *find;
! 226:
! 227: find = hash_get (transit_hash, transit, transit_hash_alloc);
! 228: if (find != transit)
! 229: transit_free (transit);
! 230: find->refcnt++;
! 231:
! 232: return find;
! 233: }
! 234:
! 235: void
! 236: transit_unintern (struct transit *transit)
! 237: {
! 238: struct transit *ret;
! 239:
! 240: if (transit->refcnt)
! 241: transit->refcnt--;
! 242:
! 243: if (transit->refcnt == 0)
! 244: {
! 245: ret = hash_release (transit_hash, transit);
! 246: transit_free (transit);
! 247: }
! 248: }
! 249:
! 250: static unsigned int
! 251: transit_hash_key_make (void *p)
! 252: {
! 253: const struct transit * transit = p;
! 254:
! 255: return jhash(transit->val, transit->length, 0);
! 256: }
! 257:
! 258: static int
! 259: transit_hash_cmp (const void *p1, const void *p2)
! 260: {
! 261: const struct transit * transit1 = p1;
! 262: const struct transit * transit2 = p2;
! 263:
! 264: return (transit1->length == transit2->length &&
! 265: memcmp (transit1->val, transit2->val, transit1->length) == 0);
! 266: }
! 267:
! 268: static void
! 269: transit_init (void)
! 270: {
! 271: transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
! 272: }
! 273:
! 274: static void
! 275: transit_finish (void)
! 276: {
! 277: hash_free (transit_hash);
! 278: transit_hash = NULL;
! 279: }
! 280:
! 281: /* Attribute hash routines. */
! 282: static struct hash *attrhash;
! 283:
! 284: static struct attr_extra *
! 285: bgp_attr_extra_new (void)
! 286: {
! 287: return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
! 288: }
! 289:
! 290: void
! 291: bgp_attr_extra_free (struct attr *attr)
! 292: {
! 293: if (attr->extra)
! 294: {
! 295: XFREE (MTYPE_ATTR_EXTRA, attr->extra);
! 296: attr->extra = NULL;
! 297: }
! 298: }
! 299:
! 300: struct attr_extra *
! 301: bgp_attr_extra_get (struct attr *attr)
! 302: {
! 303: if (!attr->extra)
! 304: attr->extra = bgp_attr_extra_new();
! 305: return attr->extra;
! 306: }
! 307:
! 308: /* Shallow copy of an attribute
! 309: * Though, not so shallow that it doesn't copy the contents
! 310: * of the attr_extra pointed to by 'extra'
! 311: */
! 312: void
! 313: bgp_attr_dup (struct attr *new, struct attr *orig)
! 314: {
! 315: *new = *orig;
! 316: if (orig->extra)
! 317: {
! 318: new->extra = bgp_attr_extra_new();
! 319: *new->extra = *orig->extra;
! 320: }
! 321: }
! 322:
! 323: unsigned long int
! 324: attr_count (void)
! 325: {
! 326: return attrhash->count;
! 327: }
! 328:
! 329: unsigned long int
! 330: attr_unknown_count (void)
! 331: {
! 332: return transit_hash->count;
! 333: }
! 334:
! 335: unsigned int
! 336: attrhash_key_make (void *p)
! 337: {
! 338: const struct attr * attr = (struct attr *) p;
! 339: uint32_t key = 0;
! 340: #define MIX(val) key = jhash_1word(val, key)
! 341:
! 342: MIX(attr->origin);
! 343: MIX(attr->nexthop.s_addr);
! 344: MIX(attr->med);
! 345: MIX(attr->local_pref);
! 346:
! 347: key += attr->origin;
! 348: key += attr->nexthop.s_addr;
! 349: key += attr->med;
! 350: key += attr->local_pref;
! 351:
! 352: if (attr->extra)
! 353: {
! 354: MIX(attr->extra->aggregator_as);
! 355: MIX(attr->extra->aggregator_addr.s_addr);
! 356: MIX(attr->extra->weight);
! 357: MIX(attr->extra->mp_nexthop_global_in.s_addr);
! 358: }
! 359:
! 360: if (attr->aspath)
! 361: MIX(aspath_key_make (attr->aspath));
! 362: if (attr->community)
! 363: MIX(community_hash_make (attr->community));
! 364:
! 365: if (attr->extra)
! 366: {
! 367: if (attr->extra->ecommunity)
! 368: MIX(ecommunity_hash_make (attr->extra->ecommunity));
! 369: if (attr->extra->cluster)
! 370: MIX(cluster_hash_key_make (attr->extra->cluster));
! 371: if (attr->extra->transit)
! 372: MIX(transit_hash_key_make (attr->extra->transit));
! 373:
! 374: #ifdef HAVE_IPV6
! 375: MIX(attr->extra->mp_nexthop_len);
! 376: key = jhash(attr->extra->mp_nexthop_global.s6_addr, 16, key);
! 377: key = jhash(attr->extra->mp_nexthop_local.s6_addr, 16, key);
! 378: #endif /* HAVE_IPV6 */
! 379: }
! 380:
! 381: return key;
! 382: }
! 383:
! 384: int
! 385: attrhash_cmp (const void *p1, const void *p2)
! 386: {
! 387: const struct attr * attr1 = p1;
! 388: const struct attr * attr2 = p2;
! 389:
! 390: if (attr1->flag == attr2->flag
! 391: && attr1->origin == attr2->origin
! 392: && attr1->nexthop.s_addr == attr2->nexthop.s_addr
! 393: && attr1->aspath == attr2->aspath
! 394: && attr1->community == attr2->community
! 395: && attr1->med == attr2->med
! 396: && attr1->local_pref == attr2->local_pref)
! 397: {
! 398: const struct attr_extra *ae1 = attr1->extra;
! 399: const struct attr_extra *ae2 = attr2->extra;
! 400:
! 401: if (ae1 && ae2
! 402: && ae1->aggregator_as == ae2->aggregator_as
! 403: && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
! 404: && ae1->weight == ae2->weight
! 405: #ifdef HAVE_IPV6
! 406: && ae1->mp_nexthop_len == ae2->mp_nexthop_len
! 407: && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
! 408: && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
! 409: #endif /* HAVE_IPV6 */
! 410: && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
! 411: && ae1->ecommunity == ae2->ecommunity
! 412: && ae1->cluster == ae2->cluster
! 413: && ae1->transit == ae2->transit)
! 414: return 1;
! 415: else if (ae1 || ae2)
! 416: return 0;
! 417: /* neither attribute has extra attributes, so they're same */
! 418: return 1;
! 419: }
! 420: else
! 421: return 0;
! 422: }
! 423:
! 424: static void
! 425: attrhash_init (void)
! 426: {
! 427: attrhash = hash_create (attrhash_key_make, attrhash_cmp);
! 428: }
! 429:
! 430: static void
! 431: attrhash_finish (void)
! 432: {
! 433: hash_free (attrhash);
! 434: attrhash = NULL;
! 435: }
! 436:
! 437: static void
! 438: attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
! 439: {
! 440: struct attr *attr = backet->data;
! 441:
! 442: vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
! 443: inet_ntoa (attr->nexthop), VTY_NEWLINE);
! 444: }
! 445:
! 446: void
! 447: attr_show_all (struct vty *vty)
! 448: {
! 449: hash_iterate (attrhash,
! 450: (void (*)(struct hash_backet *, void *))
! 451: attr_show_all_iterator,
! 452: vty);
! 453: }
! 454:
! 455: static void *
! 456: bgp_attr_hash_alloc (void *p)
! 457: {
! 458: struct attr * val = (struct attr *) p;
! 459: struct attr *attr;
! 460:
! 461: attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
! 462: *attr = *val;
! 463: if (val->extra)
! 464: {
! 465: attr->extra = bgp_attr_extra_new ();
! 466: *attr->extra = *val->extra;
! 467: }
! 468: attr->refcnt = 0;
! 469: return attr;
! 470: }
! 471:
! 472: /* Internet argument attribute. */
! 473: struct attr *
! 474: bgp_attr_intern (struct attr *attr)
! 475: {
! 476: struct attr *find;
! 477:
! 478: /* Intern referenced strucutre. */
! 479: if (attr->aspath)
! 480: {
! 481: if (! attr->aspath->refcnt)
! 482: attr->aspath = aspath_intern (attr->aspath);
! 483: else
! 484: attr->aspath->refcnt++;
! 485: }
! 486: if (attr->community)
! 487: {
! 488: if (! attr->community->refcnt)
! 489: attr->community = community_intern (attr->community);
! 490: else
! 491: attr->community->refcnt++;
! 492: }
! 493: if (attr->extra)
! 494: {
! 495: struct attr_extra *attre = attr->extra;
! 496:
! 497: if (attre->ecommunity)
! 498: {
! 499: if (! attre->ecommunity->refcnt)
! 500: attre->ecommunity = ecommunity_intern (attre->ecommunity);
! 501: else
! 502: attre->ecommunity->refcnt++;
! 503:
! 504: }
! 505: if (attre->cluster)
! 506: {
! 507: if (! attre->cluster->refcnt)
! 508: attre->cluster = cluster_intern (attre->cluster);
! 509: else
! 510: attre->cluster->refcnt++;
! 511: }
! 512: if (attre->transit)
! 513: {
! 514: if (! attre->transit->refcnt)
! 515: attre->transit = transit_intern (attre->transit);
! 516: else
! 517: attre->transit->refcnt++;
! 518: }
! 519: }
! 520:
! 521: find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
! 522: find->refcnt++;
! 523:
! 524: return find;
! 525: }
! 526:
! 527:
! 528: /* Make network statement's attribute. */
! 529: struct attr *
! 530: bgp_attr_default_set (struct attr *attr, u_char origin)
! 531: {
! 532: memset (attr, 0, sizeof (struct attr));
! 533: bgp_attr_extra_get (attr);
! 534:
! 535: attr->origin = origin;
! 536: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
! 537: attr->aspath = aspath_empty ();
! 538: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
! 539: attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
! 540: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
! 541: #ifdef HAVE_IPV6
! 542: attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
! 543: #endif
! 544:
! 545: return attr;
! 546: }
! 547:
! 548:
! 549: /* Make network statement's attribute. */
! 550: struct attr *
! 551: bgp_attr_default_intern (u_char origin)
! 552: {
! 553: struct attr attr;
! 554: struct attr *new;
! 555: struct attr_extra *attre;
! 556:
! 557: memset (&attr, 0, sizeof (struct attr));
! 558: attre = bgp_attr_extra_get (&attr);
! 559:
! 560: bgp_attr_default_set(&attr, origin);
! 561:
! 562: new = bgp_attr_intern (&attr);
! 563: bgp_attr_extra_free (&attr);
! 564:
! 565: aspath_unintern (&new->aspath);
! 566: return new;
! 567: }
! 568:
! 569: struct attr *
! 570: bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
! 571: struct aspath *aspath,
! 572: struct community *community, int as_set)
! 573: {
! 574: struct attr attr;
! 575: struct attr *new;
! 576: struct attr_extra *attre;
! 577:
! 578: memset (&attr, 0, sizeof (struct attr));
! 579: attre = bgp_attr_extra_get (&attr);
! 580:
! 581: /* Origin attribute. */
! 582: attr.origin = origin;
! 583: attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
! 584:
! 585: /* AS path attribute. */
! 586: if (aspath)
! 587: attr.aspath = aspath_intern (aspath);
! 588: else
! 589: attr.aspath = aspath_empty ();
! 590: attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
! 591:
! 592: /* Next hop attribute. */
! 593: attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
! 594:
! 595: if (community)
! 596: {
! 597: attr.community = community;
! 598: attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
! 599: }
! 600:
! 601: attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
! 602: #ifdef HAVE_IPV6
! 603: attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
! 604: #endif
! 605: if (! as_set)
! 606: attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
! 607: attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
! 608: if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
! 609: attre->aggregator_as = bgp->confed_id;
! 610: else
! 611: attre->aggregator_as = bgp->as;
! 612: attre->aggregator_addr = bgp->router_id;
! 613:
! 614: new = bgp_attr_intern (&attr);
! 615: bgp_attr_extra_free (&attr);
! 616:
! 617: aspath_unintern (&new->aspath);
! 618: return new;
! 619: }
! 620:
! 621: /* Unintern just the sub-components of the attr, but not the attr */
! 622: void
! 623: bgp_attr_unintern_sub (struct attr *attr)
! 624: {
! 625: /* aspath refcount shoud be decrement. */
! 626: if (attr->aspath)
! 627: aspath_unintern (&attr->aspath);
! 628: UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH);
! 629:
! 630: if (attr->community)
! 631: community_unintern (&attr->community);
! 632: UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES);
! 633:
! 634: if (attr->extra)
! 635: {
! 636: if (attr->extra->ecommunity)
! 637: ecommunity_unintern (&attr->extra->ecommunity);
! 638: UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES);
! 639:
! 640: if (attr->extra->cluster)
! 641: cluster_unintern (attr->extra->cluster);
! 642: UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST);
! 643:
! 644: if (attr->extra->transit)
! 645: transit_unintern (attr->extra->transit);
! 646: }
! 647: }
! 648:
! 649: /* Free bgp attribute and aspath. */
! 650: void
! 651: bgp_attr_unintern (struct attr **attr)
! 652: {
! 653: struct attr *ret;
! 654: struct attr tmp;
! 655:
! 656: /* Decrement attribute reference. */
! 657: (*attr)->refcnt--;
! 658:
! 659: tmp = *(*attr);
! 660:
! 661: if ((*attr)->extra)
! 662: {
! 663: tmp.extra = bgp_attr_extra_new ();
! 664: memcpy (tmp.extra, (*attr)->extra, sizeof (struct attr_extra));
! 665: }
! 666:
! 667: /* If reference becomes zero then free attribute object. */
! 668: if ((*attr)->refcnt == 0)
! 669: {
! 670: ret = hash_release (attrhash, *attr);
! 671: assert (ret != NULL);
! 672: bgp_attr_extra_free (*attr);
! 673: XFREE (MTYPE_ATTR, *attr);
! 674: *attr = NULL;
! 675: }
! 676:
! 677: bgp_attr_unintern_sub (&tmp);
! 678: }
! 679:
! 680: void
! 681: bgp_attr_flush (struct attr *attr)
! 682: {
! 683: if (attr->aspath && ! attr->aspath->refcnt)
! 684: aspath_free (attr->aspath);
! 685: if (attr->community && ! attr->community->refcnt)
! 686: community_free (attr->community);
! 687: if (attr->extra)
! 688: {
! 689: struct attr_extra *attre = attr->extra;
! 690:
! 691: if (attre->ecommunity && ! attre->ecommunity->refcnt)
! 692: ecommunity_free (&attre->ecommunity);
! 693: if (attre->cluster && ! attre->cluster->refcnt)
! 694: cluster_free (attre->cluster);
! 695: if (attre->transit && ! attre->transit->refcnt)
! 696: transit_free (attre->transit);
! 697: }
! 698: }
! 699:
! 700: /* Implement draft-scudder-idr-optional-transitive behaviour and
! 701: * avoid resetting sessions for malformed attributes which are
! 702: * are partial/optional and hence where the error likely was not
! 703: * introduced by the sending neighbour.
! 704: */
! 705: static bgp_attr_parse_ret_t
! 706: bgp_attr_malformed (struct peer *peer, u_char type, u_char flag,
! 707: u_char subcode, u_char *startp, bgp_size_t length)
! 708: {
! 709: /* Only relax error handling for eBGP peers */
! 710: if (peer_sort (peer) != BGP_PEER_EBGP)
! 711: {
! 712: bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
! 713: startp, length);
! 714: return BGP_ATTR_PARSE_ERROR;
! 715:
! 716: }
! 717:
! 718: switch (type) {
! 719: /* where an optional attribute is inconsequential, e.g. it does not affect
! 720: * route selection, and can be safely ignored then any such attributes
! 721: * which are malformed should just be ignored and the route processed as
! 722: * normal.
! 723: */
! 724: case BGP_ATTR_AS4_AGGREGATOR:
! 725: case BGP_ATTR_AGGREGATOR:
! 726: case BGP_ATTR_ATOMIC_AGGREGATE:
! 727: return BGP_ATTR_PARSE_PROCEED;
! 728:
! 729: /* Core attributes, particularly ones which may influence route
! 730: * selection should always cause session resets
! 731: */
! 732: case BGP_ATTR_ORIGIN:
! 733: case BGP_ATTR_AS_PATH:
! 734: case BGP_ATTR_NEXT_HOP:
! 735: case BGP_ATTR_MULTI_EXIT_DISC:
! 736: case BGP_ATTR_LOCAL_PREF:
! 737: case BGP_ATTR_COMMUNITIES:
! 738: case BGP_ATTR_ORIGINATOR_ID:
! 739: case BGP_ATTR_CLUSTER_LIST:
! 740: case BGP_ATTR_MP_REACH_NLRI:
! 741: case BGP_ATTR_MP_UNREACH_NLRI:
! 742: case BGP_ATTR_EXT_COMMUNITIES:
! 743: bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
! 744: startp, length);
! 745: return BGP_ATTR_PARSE_ERROR;
! 746: }
! 747:
! 748: /* Partial optional attributes that are malformed should not cause
! 749: * the whole session to be reset. Instead treat it as a withdrawal
! 750: * of the routes, if possible.
! 751: */
! 752: if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)
! 753: && CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
! 754: && CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
! 755: return BGP_ATTR_PARSE_WITHDRAW;
! 756:
! 757: /* default to reset */
! 758: return BGP_ATTR_PARSE_ERROR;
! 759: }
! 760:
! 761: /* Get origin attribute of the update message. */
! 762: static bgp_attr_parse_ret_t
! 763: bgp_attr_origin (struct peer *peer, bgp_size_t length,
! 764: struct attr *attr, u_char flag, u_char *startp)
! 765: {
! 766: bgp_size_t total;
! 767:
! 768: /* total is entire attribute length include Attribute Flags (1),
! 769: Attribute Type code (1) and Attribute length (1 or 2). */
! 770: total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
! 771:
! 772: /* If any recognized attribute has Attribute Flags that conflict
! 773: with the Attribute Type Code, then the Error Subcode is set to
! 774: Attribute Flags Error. The Data field contains the erroneous
! 775: attribute (type, length and value). */
! 776: if (flag != BGP_ATTR_FLAG_TRANS)
! 777: {
! 778: zlog (peer->log, LOG_ERR,
! 779: "Origin attribute flag isn't transitive %d", flag);
! 780: return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
! 781: BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
! 782: startp, total);
! 783: }
! 784:
! 785: /* If any recognized attribute has Attribute Length that conflicts
! 786: with the expected length (based on the attribute type code), then
! 787: the Error Subcode is set to Attribute Length Error. The Data
! 788: field contains the erroneous attribute (type, length and
! 789: value). */
! 790: if (length != 1)
! 791: {
! 792: zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
! 793: length);
! 794: return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
! 795: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
! 796: startp, total);
! 797: }
! 798:
! 799: /* Fetch origin attribute. */
! 800: attr->origin = stream_getc (BGP_INPUT (peer));
! 801:
! 802: /* If the ORIGIN attribute has an undefined value, then the Error
! 803: Subcode is set to Invalid Origin Attribute. The Data field
! 804: contains the unrecognized attribute (type, length and value). */
! 805: if ((attr->origin != BGP_ORIGIN_IGP)
! 806: && (attr->origin != BGP_ORIGIN_EGP)
! 807: && (attr->origin != BGP_ORIGIN_INCOMPLETE))
! 808: {
! 809: zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
! 810: attr->origin);
! 811: return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
! 812: BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
! 813: startp, total);
! 814: }
! 815:
! 816: /* Set oring attribute flag. */
! 817: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
! 818:
! 819: return 0;
! 820: }
! 821:
! 822: /* Parse AS path information. This function is wrapper of
! 823: aspath_parse. */
! 824: static int
! 825: bgp_attr_aspath (struct peer *peer, bgp_size_t length,
! 826: struct attr *attr, u_char flag, u_char *startp)
! 827: {
! 828: bgp_size_t total;
! 829:
! 830: total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
! 831:
! 832: /* Flag check. */
! 833: if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
! 834: || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
! 835: {
! 836: zlog (peer->log, LOG_ERR,
! 837: "As-Path attribute flag isn't transitive %d", flag);
! 838: return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
! 839: BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
! 840: startp, total);
! 841: }
! 842:
! 843: /*
! 844: * peer with AS4 => will get 4Byte ASnums
! 845: * otherwise, will get 16 Bit
! 846: */
! 847: attr->aspath = aspath_parse (peer->ibuf, length,
! 848: CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
! 849:
! 850: /* In case of IBGP, length will be zero. */
! 851: if (! attr->aspath)
! 852: {
! 853: zlog (peer->log, LOG_ERR,
! 854: "Malformed AS path from %s, length is %d",
! 855: peer->host, length);
! 856: return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
! 857: BGP_NOTIFY_UPDATE_MAL_AS_PATH,
! 858: NULL, 0);
! 859: }
! 860:
! 861: /* Set aspath attribute flag. */
! 862: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
! 863:
! 864: return BGP_ATTR_PARSE_PROCEED;
! 865: }
! 866:
! 867: static bgp_attr_parse_ret_t
! 868: bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag)
! 869: {
! 870: /* These checks were part of bgp_attr_aspath, but with
! 871: * as4 we should to check aspath things when
! 872: * aspath synthesizing with as4_path has already taken place.
! 873: * Otherwise we check ASPATH and use the synthesized thing, and that is
! 874: * not right.
! 875: * So do the checks later, i.e. here
! 876: */
! 877: struct bgp *bgp = peer->bgp;
! 878: struct aspath *aspath;
! 879:
! 880: bgp = peer->bgp;
! 881:
! 882: /* Confederation sanity check. */
! 883: if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
! 884: (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
! 885: {
! 886: zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
! 887: return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
! 888: BGP_NOTIFY_UPDATE_MAL_AS_PATH,
! 889: NULL, 0);
! 890: }
! 891:
! 892: /* First AS check for EBGP. */
! 893: if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
! 894: {
! 895: if (peer_sort (peer) == BGP_PEER_EBGP
! 896: && ! aspath_firstas_check (attr->aspath, peer->as))
! 897: {
! 898: zlog (peer->log, LOG_ERR,
! 899: "%s incorrect first AS (must be %u)", peer->host, peer->as);
! 900: return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
! 901: BGP_NOTIFY_UPDATE_MAL_AS_PATH,
! 902: NULL, 0);
! 903: }
! 904: }
! 905:
! 906: /* local-as prepend */
! 907: if (peer->change_local_as &&
! 908: ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
! 909: {
! 910: aspath = aspath_dup (attr->aspath);
! 911: aspath = aspath_add_seq (aspath, peer->change_local_as);
! 912: aspath_unintern (&attr->aspath);
! 913: attr->aspath = aspath_intern (aspath);
! 914: }
! 915:
! 916: return BGP_ATTR_PARSE_PROCEED;
! 917: }
! 918:
! 919: /* Parse AS4 path information. This function is another wrapper of
! 920: aspath_parse. */
! 921: static int
! 922: bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
! 923: struct attr *attr, u_char flag, u_char *startp,
! 924: struct aspath **as4_path)
! 925: {
! 926: bgp_size_t total;
! 927:
! 928: total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
! 929:
! 930: /* Flag check. */
! 931: if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
! 932: || !CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
! 933: {
! 934: zlog (peer->log, LOG_ERR,
! 935: "As4-Path attribute flag isn't optional/transitive %d", flag);
! 936: return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
! 937: BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
! 938: startp, total);
! 939: }
! 940:
! 941: *as4_path = aspath_parse (peer->ibuf, length, 1);
! 942:
! 943: /* In case of IBGP, length will be zero. */
! 944: if (!*as4_path)
! 945: {
! 946: zlog (peer->log, LOG_ERR,
! 947: "Malformed AS4 path from %s, length is %d",
! 948: peer->host, length);
! 949: return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag,
! 950: BGP_NOTIFY_UPDATE_MAL_AS_PATH,
! 951: NULL, 0);
! 952: }
! 953:
! 954: /* Set aspath attribute flag. */
! 955: if (as4_path)
! 956: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
! 957:
! 958: return BGP_ATTR_PARSE_PROCEED;
! 959: }
! 960:
! 961: /* Nexthop attribute. */
! 962: static bgp_attr_parse_ret_t
! 963: bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
! 964: struct attr *attr, u_char flag, u_char *startp)
! 965: {
! 966: bgp_size_t total;
! 967:
! 968: total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
! 969:
! 970: /* Flag check. */
! 971: if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
! 972: || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
! 973: {
! 974: zlog (peer->log, LOG_ERR,
! 975: "Origin attribute flag isn't transitive %d", flag);
! 976: return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
! 977: BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
! 978: startp, total);
! 979: }
! 980:
! 981: /* Check nexthop attribute length. */
! 982: if (length != 4)
! 983: {
! 984: zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
! 985: length);
! 986:
! 987: return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
! 988: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
! 989: startp, total);
! 990: }
! 991:
! 992: attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
! 993: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
! 994:
! 995: return BGP_ATTR_PARSE_PROCEED;
! 996: }
! 997:
! 998: /* MED atrribute. */
! 999: static bgp_attr_parse_ret_t
! 1000: bgp_attr_med (struct peer *peer, bgp_size_t length,
! 1001: struct attr *attr, u_char flag, u_char *startp)
! 1002: {
! 1003: bgp_size_t total;
! 1004:
! 1005: total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
! 1006:
! 1007: /* Flag checks. */
! 1008: if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
! 1009: {
! 1010: zlog (peer->log, LOG_ERR,
! 1011: "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag);
! 1012: bgp_notify_send_with_data (peer,
! 1013: BGP_NOTIFY_UPDATE_ERR,
! 1014: BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
! 1015: startp, total);
! 1016: return -1;
! 1017: }
! 1018: if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
! 1019: {
! 1020: zlog (peer->log, LOG_ERR,
! 1021: "MULTI_EXIT_DISC attribute must not be flagged as \"transitive\" (%u)", flag);
! 1022: bgp_notify_send_with_data (peer,
! 1023: BGP_NOTIFY_UPDATE_ERR,
! 1024: BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
! 1025: startp, total);
! 1026: return -1;
! 1027: }
! 1028: if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
! 1029: {
! 1030: zlog (peer->log, LOG_ERR,
! 1031: "MULTI_EXIT_DISC attribute must not be flagged as \"partial\" (%u)", flag);
! 1032: bgp_notify_send_with_data (peer,
! 1033: BGP_NOTIFY_UPDATE_ERR,
! 1034: BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
! 1035: startp, total);
! 1036: return -1;
! 1037: }
! 1038:
! 1039: /* Length check. */
! 1040: if (length != 4)
! 1041: {
! 1042: zlog (peer->log, LOG_ERR,
! 1043: "MED attribute length isn't four [%d]", length);
! 1044:
! 1045: return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
! 1046: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
! 1047: startp, total);
! 1048: }
! 1049:
! 1050: attr->med = stream_getl (peer->ibuf);
! 1051:
! 1052: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
! 1053:
! 1054: return BGP_ATTR_PARSE_PROCEED;
! 1055: }
! 1056:
! 1057: /* Local preference attribute. */
! 1058: static bgp_attr_parse_ret_t
! 1059: bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
! 1060: struct attr *attr, u_char flag, u_char *startp)
! 1061: {
! 1062: bgp_size_t total;
! 1063:
! 1064: total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
! 1065: /* Flag checks. */
! 1066: if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
! 1067: {
! 1068: zlog (peer->log, LOG_ERR,
! 1069: "LOCAL_PREF attribute must be flagged as \"well-known\" (%u)", flag);
! 1070: bgp_notify_send_with_data (peer,
! 1071: BGP_NOTIFY_UPDATE_ERR,
! 1072: BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
! 1073: startp, total);
! 1074: return -1;
! 1075: }
! 1076: if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
! 1077: {
! 1078: zlog (peer->log, LOG_ERR,
! 1079: "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);
! 1080: bgp_notify_send_with_data (peer,
! 1081: BGP_NOTIFY_UPDATE_ERR,
! 1082: BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
! 1083: startp, total);
! 1084: return -1;
! 1085: }
! 1086:
! 1087: /* If it is contained in an UPDATE message that is received from an
! 1088: external peer, then this attribute MUST be ignored by the
! 1089: receiving speaker. */
! 1090: if (peer_sort (peer) == BGP_PEER_EBGP)
! 1091: {
! 1092: stream_forward_getp (peer->ibuf, length);
! 1093: return BGP_ATTR_PARSE_PROCEED;
! 1094: }
! 1095:
! 1096: if (length == 4)
! 1097: attr->local_pref = stream_getl (peer->ibuf);
! 1098: else
! 1099: attr->local_pref = 0;
! 1100:
! 1101: /* Set atomic aggregate flag. */
! 1102: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
! 1103:
! 1104: return BGP_ATTR_PARSE_PROCEED;
! 1105: }
! 1106:
! 1107: /* Atomic aggregate. */
! 1108: static int
! 1109: bgp_attr_atomic (struct peer *peer, bgp_size_t length,
! 1110: struct attr *attr, u_char flag, u_char *startp)
! 1111: {
! 1112: bgp_size_t total;
! 1113:
! 1114: total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
! 1115: /* Flag checks. */
! 1116: if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
! 1117: {
! 1118: zlog (peer->log, LOG_ERR,
! 1119: "ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag);
! 1120: bgp_notify_send_with_data (peer,
! 1121: BGP_NOTIFY_UPDATE_ERR,
! 1122: BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
! 1123: startp, total);
! 1124: return -1;
! 1125: }
! 1126: if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
! 1127: {
! 1128: zlog (peer->log, LOG_ERR,
! 1129: "ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag);
! 1130: bgp_notify_send_with_data (peer,
! 1131: BGP_NOTIFY_UPDATE_ERR,
! 1132: BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
! 1133: startp, total);
! 1134: return -1;
! 1135: }
! 1136: if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
! 1137: {
! 1138: zlog (peer->log, LOG_ERR,
! 1139: "ATOMIC_AGGREGATE attribute must not be flagged as \"partial\" (%u)", flag);
! 1140: bgp_notify_send_with_data (peer,
! 1141: BGP_NOTIFY_UPDATE_ERR,
! 1142: BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
! 1143: startp, total);
! 1144: return -1;
! 1145: }
! 1146:
! 1147: /* Length check. */
! 1148: if (length != 0)
! 1149: {
! 1150: zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
! 1151:
! 1152: return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
! 1153: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
! 1154: NULL, 0);
! 1155: }
! 1156:
! 1157: /* Set atomic aggregate flag. */
! 1158: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
! 1159:
! 1160: return BGP_ATTR_PARSE_PROCEED;
! 1161: }
! 1162:
! 1163: /* Aggregator attribute */
! 1164: static int
! 1165: bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
! 1166: struct attr *attr, u_char flag)
! 1167: {
! 1168: int wantedlen = 6;
! 1169: struct attr_extra *attre = bgp_attr_extra_get (attr);
! 1170:
! 1171: /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
! 1172: if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
! 1173: wantedlen = 8;
! 1174:
! 1175: if (length != wantedlen)
! 1176: {
! 1177: zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
! 1178:
! 1179: return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
! 1180: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
! 1181: NULL, 0);
! 1182: }
! 1183:
! 1184: if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
! 1185: attre->aggregator_as = stream_getl (peer->ibuf);
! 1186: else
! 1187: attre->aggregator_as = stream_getw (peer->ibuf);
! 1188: attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
! 1189:
! 1190: /* Set atomic aggregate flag. */
! 1191: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
! 1192:
! 1193: return BGP_ATTR_PARSE_PROCEED;
! 1194: }
! 1195:
! 1196: /* New Aggregator attribute */
! 1197: static bgp_attr_parse_ret_t
! 1198: bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
! 1199: struct attr *attr, u_char flag,
! 1200: as_t *as4_aggregator_as,
! 1201: struct in_addr *as4_aggregator_addr)
! 1202: {
! 1203: if (length != 8)
! 1204: {
! 1205: zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
! 1206: return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag,
! 1207: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
! 1208: NULL, 0);
! 1209: }
! 1210: *as4_aggregator_as = stream_getl (peer->ibuf);
! 1211: as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
! 1212:
! 1213: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
! 1214:
! 1215: return BGP_ATTR_PARSE_PROCEED;
! 1216: }
! 1217:
! 1218: /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
! 1219: */
! 1220: static bgp_attr_parse_ret_t
! 1221: bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag,
! 1222: struct aspath *as4_path, as_t as4_aggregator,
! 1223: struct in_addr *as4_aggregator_addr)
! 1224: {
! 1225: int ignore_as4_path = 0;
! 1226: struct aspath *newpath;
! 1227: struct attr_extra *attre = attr->extra;
! 1228:
! 1229: if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
! 1230: {
! 1231: /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
! 1232: * if given.
! 1233: * It is worth a warning though, because the peer really
! 1234: * should not send them
! 1235: */
! 1236: if (BGP_DEBUG(as4, AS4))
! 1237: {
! 1238: if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
! 1239: zlog_debug ("[AS4] %s %s AS4_PATH",
! 1240: peer->host, "AS4 capable peer, yet it sent");
! 1241:
! 1242: if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
! 1243: zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
! 1244: peer->host, "AS4 capable peer, yet it sent");
! 1245: }
! 1246:
! 1247: return BGP_ATTR_PARSE_PROCEED;
! 1248: }
! 1249:
! 1250: if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH))
! 1251: && !(attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))))
! 1252: {
! 1253: /* Hu? This is not supposed to happen at all!
! 1254: * got as4_path and no aspath,
! 1255: * This should already
! 1256: * have been handled by 'well known attributes missing'
! 1257: * But... yeah, paranoia
! 1258: * Take this as a "malformed attribute"
! 1259: */
! 1260: zlog (peer->log, LOG_ERR,
! 1261: "%s BGP not AS4 capable peer sent AS4_PATH but"
! 1262: " no AS_PATH, cant do anything here", peer->host);
! 1263: return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
! 1264: BGP_NOTIFY_UPDATE_MAL_ATTR,
! 1265: NULL, 0);
! 1266: }
! 1267:
! 1268: /* We have a asn16 peer. First, look for AS4_AGGREGATOR
! 1269: * because that may override AS4_PATH
! 1270: */
! 1271: if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
! 1272: {
! 1273: if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
! 1274: {
! 1275: assert (attre);
! 1276:
! 1277: /* received both.
! 1278: * if the as_number in aggregator is not AS_TRANS,
! 1279: * then AS4_AGGREGATOR and AS4_PATH shall be ignored
! 1280: * and the Aggregator shall be taken as
! 1281: * info on the aggregating node, and the AS_PATH
! 1282: * shall be taken as the AS_PATH
! 1283: * otherwise
! 1284: * the Aggregator shall be ignored and the
! 1285: * AS4_AGGREGATOR shall be taken as the
! 1286: * Aggregating node and the AS_PATH is to be
! 1287: * constructed "as in all other cases"
! 1288: */
! 1289: if (attre->aggregator_as != BGP_AS_TRANS)
! 1290: {
! 1291: /* ignore */
! 1292: if ( BGP_DEBUG(as4, AS4))
! 1293: zlog_debug ("[AS4] %s BGP not AS4 capable peer"
! 1294: " send AGGREGATOR != AS_TRANS and"
! 1295: " AS4_AGGREGATOR, so ignore"
! 1296: " AS4_AGGREGATOR and AS4_PATH", peer->host);
! 1297: ignore_as4_path = 1;
! 1298: }
! 1299: else
! 1300: {
! 1301: /* "New_aggregator shall be taken as aggregator" */
! 1302: attre->aggregator_as = as4_aggregator;
! 1303: attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
! 1304: }
! 1305: }
! 1306: else
! 1307: {
! 1308: /* We received a AS4_AGGREGATOR but no AGGREGATOR.
! 1309: * That is bogus - but reading the conditions
! 1310: * we have to handle AS4_AGGREGATOR as if it were
! 1311: * AGGREGATOR in that case
! 1312: */
! 1313: if ( BGP_DEBUG(as4, AS4))
! 1314: zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
! 1315: " AS4_AGGREGATOR but no AGGREGATOR, will take"
! 1316: " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
! 1317: (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
! 1318: /* sweep it under the carpet and simulate a "good" AGGREGATOR */
! 1319: attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
! 1320: }
! 1321: }
! 1322:
! 1323: /* need to reconcile NEW_AS_PATH and AS_PATH */
! 1324: if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
! 1325: {
! 1326: newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
! 1327: aspath_unintern (&attr->aspath);
! 1328: attr->aspath = aspath_intern (newpath);
! 1329: }
! 1330: return BGP_ATTR_PARSE_PROCEED;
! 1331: }
! 1332:
! 1333: /* Community attribute. */
! 1334: static bgp_attr_parse_ret_t
! 1335: bgp_attr_community (struct peer *peer, bgp_size_t length,
! 1336: struct attr *attr, u_char flag, u_char *startp)
! 1337: {
! 1338: bgp_size_t total
! 1339: = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
! 1340:
! 1341: if (length == 0)
! 1342: {
! 1343: attr->community = NULL;
! 1344: return BGP_ATTR_PARSE_PROCEED;
! 1345: }
! 1346:
! 1347: attr->community =
! 1348: community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
! 1349:
! 1350: /* XXX: fix community_parse to use stream API and remove this */
! 1351: stream_forward_getp (peer->ibuf, length);
! 1352:
! 1353: if (!attr->community)
! 1354: return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag,
! 1355: BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
! 1356: startp, total);
! 1357:
! 1358: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
! 1359:
! 1360: return BGP_ATTR_PARSE_PROCEED;
! 1361: }
! 1362:
! 1363: /* Originator ID attribute. */
! 1364: static bgp_attr_parse_ret_t
! 1365: bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
! 1366: struct attr *attr, u_char flag)
! 1367: {
! 1368: if (length != 4)
! 1369: {
! 1370: zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
! 1371:
! 1372: return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
! 1373: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
! 1374: NULL, 0);
! 1375: }
! 1376:
! 1377: (bgp_attr_extra_get (attr))->originator_id.s_addr
! 1378: = stream_get_ipv4 (peer->ibuf);
! 1379:
! 1380: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
! 1381:
! 1382: return BGP_ATTR_PARSE_PROCEED;
! 1383: }
! 1384:
! 1385: /* Cluster list attribute. */
! 1386: static bgp_attr_parse_ret_t
! 1387: bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
! 1388: struct attr *attr, u_char flag)
! 1389: {
! 1390: /* Check length. */
! 1391: if (length % 4)
! 1392: {
! 1393: zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
! 1394:
! 1395: return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
! 1396: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
! 1397: NULL, 0);
! 1398: }
! 1399:
! 1400: (bgp_attr_extra_get (attr))->cluster
! 1401: = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
! 1402:
! 1403: /* XXX: Fix cluster_parse to use stream API and then remove this */
! 1404: stream_forward_getp (peer->ibuf, length);
! 1405:
! 1406: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
! 1407:
! 1408: return BGP_ATTR_PARSE_PROCEED;
! 1409: }
! 1410:
! 1411: /* Multiprotocol reachability information parse. */
! 1412: int
! 1413: bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
! 1414: struct bgp_nlri *mp_update)
! 1415: {
! 1416: afi_t afi;
! 1417: safi_t safi;
! 1418: bgp_size_t nlri_len;
! 1419: size_t start;
! 1420: int ret;
! 1421: struct stream *s;
! 1422: struct attr_extra *attre = bgp_attr_extra_get(attr);
! 1423:
! 1424: /* Set end of packet. */
! 1425: s = BGP_INPUT(peer);
! 1426: start = stream_get_getp(s);
! 1427:
! 1428: /* safe to read statically sized header? */
! 1429: #define BGP_MP_REACH_MIN_SIZE 5
! 1430: #define LEN_LEFT (length - (stream_get_getp(s) - start))
! 1431: if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
! 1432: {
! 1433: zlog_info ("%s: %s sent invalid length, %lu",
! 1434: __func__, peer->host, (unsigned long)length);
! 1435: return BGP_ATTR_PARSE_ERROR;
! 1436: }
! 1437:
! 1438: /* Load AFI, SAFI. */
! 1439: afi = stream_getw (s);
! 1440: safi = stream_getc (s);
! 1441:
! 1442: /* Get nexthop length. */
! 1443: attre->mp_nexthop_len = stream_getc (s);
! 1444:
! 1445: if (LEN_LEFT < attre->mp_nexthop_len)
! 1446: {
! 1447: zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
! 1448: __func__, peer->host, attre->mp_nexthop_len);
! 1449: return BGP_ATTR_PARSE_ERROR;
! 1450: }
! 1451:
! 1452: /* Nexthop length check. */
! 1453: switch (attre->mp_nexthop_len)
! 1454: {
! 1455: case 4:
! 1456: stream_get (&attre->mp_nexthop_global_in, s, 4);
! 1457: /* Probably needed for RFC 2283 */
! 1458: if (attr->nexthop.s_addr == 0)
! 1459: memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
! 1460: break;
! 1461: case 12:
! 1462: {
! 1463: u_int32_t rd_high;
! 1464: u_int32_t rd_low;
! 1465:
! 1466: rd_high = stream_getl (s);
! 1467: rd_low = stream_getl (s);
! 1468: stream_get (&attre->mp_nexthop_global_in, s, 4);
! 1469: }
! 1470: break;
! 1471: #ifdef HAVE_IPV6
! 1472: case 16:
! 1473: stream_get (&attre->mp_nexthop_global, s, 16);
! 1474: break;
! 1475: case 32:
! 1476: stream_get (&attre->mp_nexthop_global, s, 16);
! 1477: stream_get (&attre->mp_nexthop_local, s, 16);
! 1478: if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
! 1479: {
! 1480: char buf1[INET6_ADDRSTRLEN];
! 1481: char buf2[INET6_ADDRSTRLEN];
! 1482:
! 1483: if (BGP_DEBUG (update, UPDATE_IN))
! 1484: zlog_debug ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host,
! 1485: inet_ntop (AF_INET6, &attre->mp_nexthop_global,
! 1486: buf1, INET6_ADDRSTRLEN),
! 1487: inet_ntop (AF_INET6, &attre->mp_nexthop_local,
! 1488: buf2, INET6_ADDRSTRLEN));
! 1489:
! 1490: attre->mp_nexthop_len = 16;
! 1491: }
! 1492: break;
! 1493: #endif /* HAVE_IPV6 */
! 1494: default:
! 1495: zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
! 1496: __func__, peer->host, attre->mp_nexthop_len);
! 1497: return BGP_ATTR_PARSE_ERROR;
! 1498: }
! 1499:
! 1500: if (!LEN_LEFT)
! 1501: {
! 1502: zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
! 1503: __func__, peer->host);
! 1504: return BGP_ATTR_PARSE_ERROR;
! 1505: }
! 1506:
! 1507: {
! 1508: u_char val;
! 1509: if ((val = stream_getc (s)))
! 1510: zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
! 1511: peer->host, val);
! 1512: }
! 1513:
! 1514: /* must have nrli_len, what is left of the attribute */
! 1515: nlri_len = LEN_LEFT;
! 1516: if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
! 1517: {
! 1518: zlog_info ("%s: (%s) Failed to read NLRI",
! 1519: __func__, peer->host);
! 1520: return BGP_ATTR_PARSE_ERROR;
! 1521: }
! 1522:
! 1523: if (safi != BGP_SAFI_VPNV4)
! 1524: {
! 1525: ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
! 1526: if (ret < 0)
! 1527: {
! 1528: zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
! 1529: __func__, peer->host);
! 1530: return BGP_ATTR_PARSE_ERROR;
! 1531: }
! 1532: }
! 1533:
! 1534: mp_update->afi = afi;
! 1535: mp_update->safi = safi;
! 1536: mp_update->nlri = stream_pnt (s);
! 1537: mp_update->length = nlri_len;
! 1538:
! 1539: stream_forward_getp (s, nlri_len);
! 1540:
! 1541: return BGP_ATTR_PARSE_PROCEED;
! 1542: #undef LEN_LEFT
! 1543: }
! 1544:
! 1545: /* Multiprotocol unreachable parse */
! 1546: int
! 1547: bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
! 1548: struct bgp_nlri *mp_withdraw)
! 1549: {
! 1550: struct stream *s;
! 1551: afi_t afi;
! 1552: safi_t safi;
! 1553: u_int16_t withdraw_len;
! 1554: int ret;
! 1555:
! 1556: s = peer->ibuf;
! 1557:
! 1558: #define BGP_MP_UNREACH_MIN_SIZE 3
! 1559: if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
! 1560: return BGP_ATTR_PARSE_ERROR;
! 1561:
! 1562: afi = stream_getw (s);
! 1563: safi = stream_getc (s);
! 1564:
! 1565: withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
! 1566:
! 1567: if (safi != BGP_SAFI_VPNV4)
! 1568: {
! 1569: ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
! 1570: if (ret < 0)
! 1571: return BGP_ATTR_PARSE_ERROR;
! 1572: }
! 1573:
! 1574: mp_withdraw->afi = afi;
! 1575: mp_withdraw->safi = safi;
! 1576: mp_withdraw->nlri = stream_pnt (s);
! 1577: mp_withdraw->length = withdraw_len;
! 1578:
! 1579: stream_forward_getp (s, withdraw_len);
! 1580:
! 1581: return BGP_ATTR_PARSE_PROCEED;
! 1582: }
! 1583:
! 1584: /* Extended Community attribute. */
! 1585: static bgp_attr_parse_ret_t
! 1586: bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
! 1587: struct attr *attr, u_char flag, u_char *startp)
! 1588: {
! 1589: bgp_size_t total
! 1590: = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
! 1591:
! 1592: if (length == 0)
! 1593: {
! 1594: if (attr->extra)
! 1595: attr->extra->ecommunity = NULL;
! 1596: /* Empty extcomm doesn't seem to be invalid per se */
! 1597: return BGP_ATTR_PARSE_PROCEED;
! 1598: }
! 1599:
! 1600: (bgp_attr_extra_get (attr))->ecommunity =
! 1601: ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
! 1602: /* XXX: fix ecommunity_parse to use stream API */
! 1603: stream_forward_getp (peer->ibuf, length);
! 1604:
! 1605: if (!attr->extra->ecommunity)
! 1606: return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES,
! 1607: flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
! 1608: startp, total);
! 1609:
! 1610: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
! 1611:
! 1612: return BGP_ATTR_PARSE_PROCEED;
! 1613: }
! 1614:
! 1615: /* BGP unknown attribute treatment. */
! 1616: static bgp_attr_parse_ret_t
! 1617: bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
! 1618: u_char type, bgp_size_t length, u_char *startp)
! 1619: {
! 1620: bgp_size_t total;
! 1621: struct transit *transit;
! 1622: struct attr_extra *attre;
! 1623:
! 1624: if (BGP_DEBUG (normal, NORMAL))
! 1625: zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
! 1626: peer->host, type, length);
! 1627:
! 1628: if (BGP_DEBUG (events, EVENTS))
! 1629: zlog (peer->log, LOG_DEBUG,
! 1630: "Unknown attribute type %d length %d is received", type, length);
! 1631:
! 1632: /* Forward read pointer of input stream. */
! 1633: stream_forward_getp (peer->ibuf, length);
! 1634:
! 1635: /* Adjest total length to include type and length. */
! 1636: total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
! 1637:
! 1638: /* If any of the mandatory well-known attributes are not recognized,
! 1639: then the Error Subcode is set to Unrecognized Well-known
! 1640: Attribute. The Data field contains the unrecognized attribute
! 1641: (type, length and value). */
! 1642: if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
! 1643: {
! 1644: return bgp_attr_malformed (peer, type, flag,
! 1645: BGP_NOTIFY_UPDATE_UNREC_ATTR,
! 1646: startp, total);
! 1647: }
! 1648:
! 1649: /* Unrecognized non-transitive optional attributes must be quietly
! 1650: ignored and not passed along to other BGP peers. */
! 1651: if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
! 1652: return BGP_ATTR_PARSE_PROCEED;
! 1653:
! 1654: /* If a path with recognized transitive optional attribute is
! 1655: accepted and passed along to other BGP peers and the Partial bit
! 1656: in the Attribute Flags octet is set to 1 by some previous AS, it
! 1657: is not set back to 0 by the current AS. */
! 1658: SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
! 1659:
! 1660: /* Store transitive attribute to the end of attr->transit. */
! 1661: if (! ((attre = bgp_attr_extra_get(attr))->transit) )
! 1662: attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
! 1663:
! 1664: transit = attre->transit;
! 1665:
! 1666: if (transit->val)
! 1667: transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
! 1668: transit->length + total);
! 1669: else
! 1670: transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
! 1671:
! 1672: memcpy (transit->val + transit->length, startp, total);
! 1673: transit->length += total;
! 1674:
! 1675: return BGP_ATTR_PARSE_PROCEED;
! 1676: }
! 1677:
! 1678: /* Read attribute of update packet. This function is called from
! 1679: bgp_update() in bgpd.c. */
! 1680: bgp_attr_parse_ret_t
! 1681: bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
! 1682: struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
! 1683: {
! 1684: int ret;
! 1685: u_char flag = 0;
! 1686: u_char type = 0;
! 1687: bgp_size_t length;
! 1688: u_char *startp, *endp;
! 1689: u_char *attr_endp;
! 1690: u_char seen[BGP_ATTR_BITMAP_SIZE];
! 1691: /* we need the as4_path only until we have synthesized the as_path with it */
! 1692: /* same goes for as4_aggregator */
! 1693: struct aspath *as4_path = NULL;
! 1694: as_t as4_aggregator = 0;
! 1695: struct in_addr as4_aggregator_addr = { 0 };
! 1696:
! 1697: /* Initialize bitmap. */
! 1698: memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
! 1699:
! 1700: /* End pointer of BGP attribute. */
! 1701: endp = BGP_INPUT_PNT (peer) + size;
! 1702:
! 1703: /* Get attributes to the end of attribute length. */
! 1704: while (BGP_INPUT_PNT (peer) < endp)
! 1705: {
! 1706: /* Check remaining length check.*/
! 1707: if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
! 1708: {
! 1709: /* XXX warning: long int format, int arg (arg 5) */
! 1710: zlog (peer->log, LOG_WARNING,
! 1711: "%s: error BGP attribute length %lu is smaller than min len",
! 1712: peer->host,
! 1713: (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
! 1714:
! 1715: bgp_notify_send (peer,
! 1716: BGP_NOTIFY_UPDATE_ERR,
! 1717: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
! 1718: return BGP_ATTR_PARSE_ERROR;
! 1719: }
! 1720:
! 1721: /* Fetch attribute flag and type. */
! 1722: startp = BGP_INPUT_PNT (peer);
! 1723: flag = stream_getc (BGP_INPUT (peer));
! 1724: type = stream_getc (BGP_INPUT (peer));
! 1725:
! 1726: /* Check whether Extended-Length applies and is in bounds */
! 1727: if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
! 1728: && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
! 1729: {
! 1730: zlog (peer->log, LOG_WARNING,
! 1731: "%s: Extended length set, but just %lu bytes of attr header",
! 1732: peer->host,
! 1733: (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
! 1734:
! 1735: bgp_notify_send (peer,
! 1736: BGP_NOTIFY_UPDATE_ERR,
! 1737: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
! 1738: return BGP_ATTR_PARSE_ERROR;
! 1739: }
! 1740:
! 1741: /* Check extended attribue length bit. */
! 1742: if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
! 1743: length = stream_getw (BGP_INPUT (peer));
! 1744: else
! 1745: length = stream_getc (BGP_INPUT (peer));
! 1746:
! 1747: /* If any attribute appears more than once in the UPDATE
! 1748: message, then the Error Subcode is set to Malformed Attribute
! 1749: List. */
! 1750:
! 1751: if (CHECK_BITMAP (seen, type))
! 1752: {
! 1753: zlog (peer->log, LOG_WARNING,
! 1754: "%s: error BGP attribute type %d appears twice in a message",
! 1755: peer->host, type);
! 1756:
! 1757: bgp_notify_send (peer,
! 1758: BGP_NOTIFY_UPDATE_ERR,
! 1759: BGP_NOTIFY_UPDATE_MAL_ATTR);
! 1760: return BGP_ATTR_PARSE_ERROR;
! 1761: }
! 1762:
! 1763: /* Set type to bitmap to check duplicate attribute. `type' is
! 1764: unsigned char so it never overflow bitmap range. */
! 1765:
! 1766: SET_BITMAP (seen, type);
! 1767:
! 1768: /* Overflow check. */
! 1769: attr_endp = BGP_INPUT_PNT (peer) + length;
! 1770:
! 1771: if (attr_endp > endp)
! 1772: {
! 1773: zlog (peer->log, LOG_WARNING,
! 1774: "%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);
! 1775: bgp_notify_send (peer,
! 1776: BGP_NOTIFY_UPDATE_ERR,
! 1777: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
! 1778: return BGP_ATTR_PARSE_ERROR;
! 1779: }
! 1780:
! 1781: /* OK check attribute and store it's value. */
! 1782: switch (type)
! 1783: {
! 1784: case BGP_ATTR_ORIGIN:
! 1785: ret = bgp_attr_origin (peer, length, attr, flag, startp);
! 1786: break;
! 1787: case BGP_ATTR_AS_PATH:
! 1788: ret = bgp_attr_aspath (peer, length, attr, flag, startp);
! 1789: break;
! 1790: case BGP_ATTR_AS4_PATH:
! 1791: ret = bgp_attr_as4_path (peer, length, attr, flag, startp, &as4_path);
! 1792: break;
! 1793: case BGP_ATTR_NEXT_HOP:
! 1794: ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
! 1795: break;
! 1796: case BGP_ATTR_MULTI_EXIT_DISC:
! 1797: ret = bgp_attr_med (peer, length, attr, flag, startp);
! 1798: break;
! 1799: case BGP_ATTR_LOCAL_PREF:
! 1800: ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
! 1801: break;
! 1802: case BGP_ATTR_ATOMIC_AGGREGATE:
! 1803: ret = bgp_attr_atomic (peer, length, attr, flag, startp);
! 1804: break;
! 1805: case BGP_ATTR_AGGREGATOR:
! 1806: ret = bgp_attr_aggregator (peer, length, attr, flag);
! 1807: break;
! 1808: case BGP_ATTR_AS4_AGGREGATOR:
! 1809: ret = bgp_attr_as4_aggregator (peer, length, attr, flag,
! 1810: &as4_aggregator,
! 1811: &as4_aggregator_addr);
! 1812: break;
! 1813: case BGP_ATTR_COMMUNITIES:
! 1814: ret = bgp_attr_community (peer, length, attr, flag, startp);
! 1815: break;
! 1816: case BGP_ATTR_ORIGINATOR_ID:
! 1817: ret = bgp_attr_originator_id (peer, length, attr, flag);
! 1818: break;
! 1819: case BGP_ATTR_CLUSTER_LIST:
! 1820: ret = bgp_attr_cluster_list (peer, length, attr, flag);
! 1821: break;
! 1822: case BGP_ATTR_MP_REACH_NLRI:
! 1823: ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
! 1824: break;
! 1825: case BGP_ATTR_MP_UNREACH_NLRI:
! 1826: ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
! 1827: break;
! 1828: case BGP_ATTR_EXT_COMMUNITIES:
! 1829: ret = bgp_attr_ext_communities (peer, length, attr, flag, startp);
! 1830: break;
! 1831: default:
! 1832: ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
! 1833: break;
! 1834: }
! 1835:
! 1836: /* If hard error occured immediately return to the caller. */
! 1837: if (ret == BGP_ATTR_PARSE_ERROR)
! 1838: {
! 1839: zlog (peer->log, LOG_WARNING,
! 1840: "%s: Attribute %s, parse error",
! 1841: peer->host,
! 1842: LOOKUP (attr_str, type));
! 1843: bgp_notify_send (peer,
! 1844: BGP_NOTIFY_UPDATE_ERR,
! 1845: BGP_NOTIFY_UPDATE_MAL_ATTR);
! 1846: if (as4_path)
! 1847: aspath_unintern (&as4_path);
! 1848: return ret;
! 1849: }
! 1850: if (ret == BGP_ATTR_PARSE_WITHDRAW)
! 1851: {
! 1852:
! 1853: zlog (peer->log, LOG_WARNING,
! 1854: "%s: Attribute %s, parse error - treating as withdrawal",
! 1855: peer->host,
! 1856: LOOKUP (attr_str, type));
! 1857: if (as4_path)
! 1858: aspath_unintern (&as4_path);
! 1859: return ret;
! 1860: }
! 1861:
! 1862: /* Check the fetched length. */
! 1863: if (BGP_INPUT_PNT (peer) != attr_endp)
! 1864: {
! 1865: zlog (peer->log, LOG_WARNING,
! 1866: "%s: BGP attribute %s, fetch error",
! 1867: peer->host, LOOKUP (attr_str, type));
! 1868: bgp_notify_send (peer,
! 1869: BGP_NOTIFY_UPDATE_ERR,
! 1870: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
! 1871: if (as4_path)
! 1872: aspath_unintern (&as4_path);
! 1873: return BGP_ATTR_PARSE_ERROR;
! 1874: }
! 1875: }
! 1876:
! 1877: /* Check final read pointer is same as end pointer. */
! 1878: if (BGP_INPUT_PNT (peer) != endp)
! 1879: {
! 1880: zlog (peer->log, LOG_WARNING,
! 1881: "%s: BGP attribute %s, length mismatch",
! 1882: peer->host, LOOKUP (attr_str, type));
! 1883: bgp_notify_send (peer,
! 1884: BGP_NOTIFY_UPDATE_ERR,
! 1885: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
! 1886: if (as4_path)
! 1887: aspath_unintern (&as4_path);
! 1888: return BGP_ATTR_PARSE_ERROR;
! 1889: }
! 1890:
! 1891: /*
! 1892: * At this place we can see whether we got AS4_PATH and/or
! 1893: * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
! 1894: * We can not do this before we've read all attributes because
! 1895: * the as4 handling does not say whether AS4_PATH has to be sent
! 1896: * after AS_PATH or not - and when AS4_AGGREGATOR will be send
! 1897: * in relationship to AGGREGATOR.
! 1898: * So, to be defensive, we are not relying on any order and read
! 1899: * all attributes first, including these 32bit ones, and now,
! 1900: * afterwards, we look what and if something is to be done for as4.
! 1901: */
! 1902: if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path,
! 1903: as4_aggregator, &as4_aggregator_addr))
! 1904: {
! 1905: if (as4_path)
! 1906: aspath_unintern (&as4_path);
! 1907: return BGP_ATTR_PARSE_ERROR;
! 1908: }
! 1909:
! 1910: /* At this stage, we have done all fiddling with as4, and the
! 1911: * resulting info is in attr->aggregator resp. attr->aspath
! 1912: * so we can chuck as4_aggregator and as4_path alltogether in
! 1913: * order to save memory
! 1914: */
! 1915: if (as4_path)
! 1916: {
! 1917: aspath_unintern (&as4_path); /* unintern - it is in the hash */
! 1918: /* The flag that we got this is still there, but that does not
! 1919: * do any trouble
! 1920: */
! 1921: }
! 1922: /*
! 1923: * The "rest" of the code does nothing with as4_aggregator.
! 1924: * there is no memory attached specifically which is not part
! 1925: * of the attr.
! 1926: * so ignoring just means do nothing.
! 1927: */
! 1928: /*
! 1929: * Finally do the checks on the aspath we did not do yet
! 1930: * because we waited for a potentially synthesized aspath.
! 1931: */
! 1932: if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
! 1933: {
! 1934: ret = bgp_attr_aspath_check (peer, attr, flag);
! 1935: if (ret != BGP_ATTR_PARSE_PROCEED)
! 1936: return ret;
! 1937: }
! 1938:
! 1939: /* Finally intern unknown attribute. */
! 1940: if (attr->extra && attr->extra->transit)
! 1941: attr->extra->transit = transit_intern (attr->extra->transit);
! 1942:
! 1943: return BGP_ATTR_PARSE_PROCEED;
! 1944: }
! 1945:
! 1946: /* Well-known attribute check. */
! 1947: int
! 1948: bgp_attr_check (struct peer *peer, struct attr *attr)
! 1949: {
! 1950: u_char type = 0;
! 1951:
! 1952: if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
! 1953: type = BGP_ATTR_ORIGIN;
! 1954:
! 1955: if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
! 1956: type = BGP_ATTR_AS_PATH;
! 1957:
! 1958: if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
! 1959: type = BGP_ATTR_NEXT_HOP;
! 1960:
! 1961: if (peer_sort (peer) == BGP_PEER_IBGP
! 1962: && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
! 1963: type = BGP_ATTR_LOCAL_PREF;
! 1964:
! 1965: if (type)
! 1966: {
! 1967: zlog (peer->log, LOG_WARNING,
! 1968: "%s Missing well-known attribute %d.",
! 1969: peer->host, type);
! 1970: bgp_notify_send_with_data (peer,
! 1971: BGP_NOTIFY_UPDATE_ERR,
! 1972: BGP_NOTIFY_UPDATE_MISS_ATTR,
! 1973: &type, 1);
! 1974: return BGP_ATTR_PARSE_ERROR;
! 1975: }
! 1976: return BGP_ATTR_PARSE_PROCEED;
! 1977: }
! 1978:
! 1979: int stream_put_prefix (struct stream *, struct prefix *);
! 1980:
! 1981: /* Make attribute packet. */
! 1982: bgp_size_t
! 1983: bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
! 1984: struct stream *s, struct attr *attr, struct prefix *p,
! 1985: afi_t afi, safi_t safi, struct peer *from,
! 1986: struct prefix_rd *prd, u_char *tag)
! 1987: {
! 1988: size_t cp;
! 1989: size_t aspath_sizep;
! 1990: struct aspath *aspath;
! 1991: int send_as4_path = 0;
! 1992: int send_as4_aggregator = 0;
! 1993: int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
! 1994:
! 1995: if (! bgp)
! 1996: bgp = bgp_get_default ();
! 1997:
! 1998: /* Remember current pointer. */
! 1999: cp = stream_get_endp (s);
! 2000:
! 2001: /* Origin attribute. */
! 2002: stream_putc (s, BGP_ATTR_FLAG_TRANS);
! 2003: stream_putc (s, BGP_ATTR_ORIGIN);
! 2004: stream_putc (s, 1);
! 2005: stream_putc (s, attr->origin);
! 2006:
! 2007: /* AS path attribute. */
! 2008:
! 2009: /* If remote-peer is EBGP */
! 2010: if (peer_sort (peer) == BGP_PEER_EBGP
! 2011: && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
! 2012: || attr->aspath->segments == NULL)
! 2013: && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
! 2014: {
! 2015: aspath = aspath_dup (attr->aspath);
! 2016:
! 2017: if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
! 2018: {
! 2019: /* Strip the confed info, and then stuff our path CONFED_ID
! 2020: on the front */
! 2021: aspath = aspath_delete_confed_seq (aspath);
! 2022: aspath = aspath_add_seq (aspath, bgp->confed_id);
! 2023: }
! 2024: else
! 2025: {
! 2026: aspath = aspath_add_seq (aspath, peer->local_as);
! 2027: if (peer->change_local_as)
! 2028: aspath = aspath_add_seq (aspath, peer->change_local_as);
! 2029: }
! 2030: }
! 2031: else if (peer_sort (peer) == BGP_PEER_CONFED)
! 2032: {
! 2033: /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
! 2034: aspath = aspath_dup (attr->aspath);
! 2035: aspath = aspath_add_confed_seq (aspath, peer->local_as);
! 2036: }
! 2037: else
! 2038: aspath = attr->aspath;
! 2039:
! 2040: /* If peer is not AS4 capable, then:
! 2041: * - send the created AS_PATH out as AS4_PATH (optional, transitive),
! 2042: * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
! 2043: * types are in it (i.e. exclude them if they are there)
! 2044: * AND do this only if there is at least one asnum > 65535 in the path!
! 2045: * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
! 2046: * all ASnums > 65535 to BGP_AS_TRANS
! 2047: */
! 2048:
! 2049: stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
! 2050: stream_putc (s, BGP_ATTR_AS_PATH);
! 2051: aspath_sizep = stream_get_endp (s);
! 2052: stream_putw (s, 0);
! 2053: stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
! 2054:
! 2055: /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
! 2056: * in the path
! 2057: */
! 2058: if (!use32bit && aspath_has_as4 (aspath))
! 2059: send_as4_path = 1; /* we'll do this later, at the correct place */
! 2060:
! 2061: /* Nexthop attribute. */
! 2062: if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
! 2063: {
! 2064: stream_putc (s, BGP_ATTR_FLAG_TRANS);
! 2065: stream_putc (s, BGP_ATTR_NEXT_HOP);
! 2066: stream_putc (s, 4);
! 2067: if (safi == SAFI_MPLS_VPN)
! 2068: {
! 2069: if (attr->nexthop.s_addr == 0)
! 2070: stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
! 2071: else
! 2072: stream_put_ipv4 (s, attr->nexthop.s_addr);
! 2073: }
! 2074: else
! 2075: stream_put_ipv4 (s, attr->nexthop.s_addr);
! 2076: }
! 2077:
! 2078: /* MED attribute. */
! 2079: if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
! 2080: {
! 2081: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
! 2082: stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
! 2083: stream_putc (s, 4);
! 2084: stream_putl (s, attr->med);
! 2085: }
! 2086:
! 2087: /* Local preference. */
! 2088: if (peer_sort (peer) == BGP_PEER_IBGP ||
! 2089: peer_sort (peer) == BGP_PEER_CONFED)
! 2090: {
! 2091: stream_putc (s, BGP_ATTR_FLAG_TRANS);
! 2092: stream_putc (s, BGP_ATTR_LOCAL_PREF);
! 2093: stream_putc (s, 4);
! 2094: stream_putl (s, attr->local_pref);
! 2095: }
! 2096:
! 2097: /* Atomic aggregate. */
! 2098: if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
! 2099: {
! 2100: stream_putc (s, BGP_ATTR_FLAG_TRANS);
! 2101: stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
! 2102: stream_putc (s, 0);
! 2103: }
! 2104:
! 2105: /* Aggregator. */
! 2106: if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
! 2107: {
! 2108: assert (attr->extra);
! 2109:
! 2110: /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
! 2111: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
! 2112: stream_putc (s, BGP_ATTR_AGGREGATOR);
! 2113:
! 2114: if (use32bit)
! 2115: {
! 2116: /* AS4 capable peer */
! 2117: stream_putc (s, 8);
! 2118: stream_putl (s, attr->extra->aggregator_as);
! 2119: }
! 2120: else
! 2121: {
! 2122: /* 2-byte AS peer */
! 2123: stream_putc (s, 6);
! 2124:
! 2125: /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
! 2126: if ( attr->extra->aggregator_as > 65535 )
! 2127: {
! 2128: stream_putw (s, BGP_AS_TRANS);
! 2129:
! 2130: /* we have to send AS4_AGGREGATOR, too.
! 2131: * we'll do that later in order to send attributes in ascending
! 2132: * order.
! 2133: */
! 2134: send_as4_aggregator = 1;
! 2135: }
! 2136: else
! 2137: stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
! 2138: }
! 2139: stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
! 2140: }
! 2141:
! 2142: /* Community attribute. */
! 2143: if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
! 2144: && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
! 2145: {
! 2146: if (attr->community->size * 4 > 255)
! 2147: {
! 2148: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
! 2149: stream_putc (s, BGP_ATTR_COMMUNITIES);
! 2150: stream_putw (s, attr->community->size * 4);
! 2151: }
! 2152: else
! 2153: {
! 2154: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
! 2155: stream_putc (s, BGP_ATTR_COMMUNITIES);
! 2156: stream_putc (s, attr->community->size * 4);
! 2157: }
! 2158: stream_put (s, attr->community->val, attr->community->size * 4);
! 2159: }
! 2160:
! 2161: /* Route Reflector. */
! 2162: if (peer_sort (peer) == BGP_PEER_IBGP
! 2163: && from
! 2164: && peer_sort (from) == BGP_PEER_IBGP)
! 2165: {
! 2166: /* Originator ID. */
! 2167: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
! 2168: stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
! 2169: stream_putc (s, 4);
! 2170:
! 2171: if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
! 2172: stream_put_in_addr (s, &attr->extra->originator_id);
! 2173: else
! 2174: stream_put_in_addr (s, &from->remote_id);
! 2175:
! 2176: /* Cluster list. */
! 2177: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
! 2178: stream_putc (s, BGP_ATTR_CLUSTER_LIST);
! 2179:
! 2180: if (attr->extra && attr->extra->cluster)
! 2181: {
! 2182: stream_putc (s, attr->extra->cluster->length + 4);
! 2183: /* If this peer configuration's parent BGP has cluster_id. */
! 2184: if (bgp->config & BGP_CONFIG_CLUSTER_ID)
! 2185: stream_put_in_addr (s, &bgp->cluster_id);
! 2186: else
! 2187: stream_put_in_addr (s, &bgp->router_id);
! 2188: stream_put (s, attr->extra->cluster->list,
! 2189: attr->extra->cluster->length);
! 2190: }
! 2191: else
! 2192: {
! 2193: stream_putc (s, 4);
! 2194: /* If this peer configuration's parent BGP has cluster_id. */
! 2195: if (bgp->config & BGP_CONFIG_CLUSTER_ID)
! 2196: stream_put_in_addr (s, &bgp->cluster_id);
! 2197: else
! 2198: stream_put_in_addr (s, &bgp->router_id);
! 2199: }
! 2200: }
! 2201:
! 2202: #ifdef HAVE_IPV6
! 2203: /* If p is IPv6 address put it into attribute. */
! 2204: if (p->family == AF_INET6)
! 2205: {
! 2206: unsigned long sizep;
! 2207: struct attr_extra *attre = attr->extra;
! 2208:
! 2209: assert (attr->extra);
! 2210:
! 2211: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
! 2212: stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
! 2213: sizep = stream_get_endp (s);
! 2214: stream_putc (s, 0); /* Marker: Attribute length. */
! 2215: stream_putw (s, AFI_IP6); /* AFI */
! 2216: stream_putc (s, safi); /* SAFI */
! 2217:
! 2218: stream_putc (s, attre->mp_nexthop_len);
! 2219:
! 2220: if (attre->mp_nexthop_len == 16)
! 2221: stream_put (s, &attre->mp_nexthop_global, 16);
! 2222: else if (attre->mp_nexthop_len == 32)
! 2223: {
! 2224: stream_put (s, &attre->mp_nexthop_global, 16);
! 2225: stream_put (s, &attre->mp_nexthop_local, 16);
! 2226: }
! 2227:
! 2228: /* SNPA */
! 2229: stream_putc (s, 0);
! 2230:
! 2231: /* Prefix write. */
! 2232: stream_put_prefix (s, p);
! 2233:
! 2234: /* Set MP attribute length. */
! 2235: stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
! 2236: }
! 2237: #endif /* HAVE_IPV6 */
! 2238:
! 2239: if (p->family == AF_INET && safi == SAFI_MULTICAST)
! 2240: {
! 2241: unsigned long sizep;
! 2242:
! 2243: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
! 2244: stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
! 2245: sizep = stream_get_endp (s);
! 2246: stream_putc (s, 0); /* Marker: Attribute Length. */
! 2247: stream_putw (s, AFI_IP); /* AFI */
! 2248: stream_putc (s, SAFI_MULTICAST); /* SAFI */
! 2249:
! 2250: stream_putc (s, 4);
! 2251: stream_put_ipv4 (s, attr->nexthop.s_addr);
! 2252:
! 2253: /* SNPA */
! 2254: stream_putc (s, 0);
! 2255:
! 2256: /* Prefix write. */
! 2257: stream_put_prefix (s, p);
! 2258:
! 2259: /* Set MP attribute length. */
! 2260: stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
! 2261: }
! 2262:
! 2263: if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
! 2264: {
! 2265: unsigned long sizep;
! 2266:
! 2267: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
! 2268: stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
! 2269: sizep = stream_get_endp (s);
! 2270: stream_putc (s, 0); /* Length of this attribute. */
! 2271: stream_putw (s, AFI_IP); /* AFI */
! 2272: stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
! 2273:
! 2274: stream_putc (s, 12);
! 2275: stream_putl (s, 0);
! 2276: stream_putl (s, 0);
! 2277: stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
! 2278:
! 2279: /* SNPA */
! 2280: stream_putc (s, 0);
! 2281:
! 2282: /* Tag, RD, Prefix write. */
! 2283: stream_putc (s, p->prefixlen + 88);
! 2284: stream_put (s, tag, 3);
! 2285: stream_put (s, prd->val, 8);
! 2286: stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
! 2287:
! 2288: /* Set MP attribute length. */
! 2289: stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
! 2290: }
! 2291:
! 2292: /* Extended Communities attribute. */
! 2293: if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
! 2294: && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
! 2295: {
! 2296: struct attr_extra *attre = attr->extra;
! 2297:
! 2298: assert (attre);
! 2299:
! 2300: if (peer_sort (peer) == BGP_PEER_IBGP
! 2301: || peer_sort (peer) == BGP_PEER_CONFED)
! 2302: {
! 2303: if (attre->ecommunity->size * 8 > 255)
! 2304: {
! 2305: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
! 2306: stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
! 2307: stream_putw (s, attre->ecommunity->size * 8);
! 2308: }
! 2309: else
! 2310: {
! 2311: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
! 2312: stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
! 2313: stream_putc (s, attre->ecommunity->size * 8);
! 2314: }
! 2315: stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
! 2316: }
! 2317: else
! 2318: {
! 2319: u_int8_t *pnt;
! 2320: int tbit;
! 2321: int ecom_tr_size = 0;
! 2322: int i;
! 2323:
! 2324: for (i = 0; i < attre->ecommunity->size; i++)
! 2325: {
! 2326: pnt = attre->ecommunity->val + (i * 8);
! 2327: tbit = *pnt;
! 2328:
! 2329: if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
! 2330: continue;
! 2331:
! 2332: ecom_tr_size++;
! 2333: }
! 2334:
! 2335: if (ecom_tr_size)
! 2336: {
! 2337: if (ecom_tr_size * 8 > 255)
! 2338: {
! 2339: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
! 2340: stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
! 2341: stream_putw (s, ecom_tr_size * 8);
! 2342: }
! 2343: else
! 2344: {
! 2345: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
! 2346: stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
! 2347: stream_putc (s, ecom_tr_size * 8);
! 2348: }
! 2349:
! 2350: for (i = 0; i < attre->ecommunity->size; i++)
! 2351: {
! 2352: pnt = attre->ecommunity->val + (i * 8);
! 2353: tbit = *pnt;
! 2354:
! 2355: if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
! 2356: continue;
! 2357:
! 2358: stream_put (s, pnt, 8);
! 2359: }
! 2360: }
! 2361: }
! 2362: }
! 2363:
! 2364: if ( send_as4_path )
! 2365: {
! 2366: /* If the peer is NOT As4 capable, AND */
! 2367: /* there are ASnums > 65535 in path THEN
! 2368: * give out AS4_PATH */
! 2369:
! 2370: /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
! 2371: * path segments!
! 2372: * Hm, I wonder... confederation things *should* only be at
! 2373: * the beginning of an aspath, right? Then we should use
! 2374: * aspath_delete_confed_seq for this, because it is already
! 2375: * there! (JK)
! 2376: * Folks, talk to me: what is reasonable here!?
! 2377: */
! 2378: aspath = aspath_delete_confed_seq (aspath);
! 2379:
! 2380: stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
! 2381: stream_putc (s, BGP_ATTR_AS4_PATH);
! 2382: aspath_sizep = stream_get_endp (s);
! 2383: stream_putw (s, 0);
! 2384: stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
! 2385: }
! 2386:
! 2387: if (aspath != attr->aspath)
! 2388: aspath_free (aspath);
! 2389:
! 2390: if ( send_as4_aggregator )
! 2391: {
! 2392: assert (attr->extra);
! 2393:
! 2394: /* send AS4_AGGREGATOR, at this place */
! 2395: /* this section of code moved here in order to ensure the correct
! 2396: * *ascending* order of attributes
! 2397: */
! 2398: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
! 2399: stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
! 2400: stream_putc (s, 8);
! 2401: stream_putl (s, attr->extra->aggregator_as);
! 2402: stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
! 2403: }
! 2404:
! 2405: /* Unknown transit attribute. */
! 2406: if (attr->extra && attr->extra->transit)
! 2407: stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
! 2408:
! 2409: /* Return total size of attribute. */
! 2410: return stream_get_endp (s) - cp;
! 2411: }
! 2412:
! 2413: bgp_size_t
! 2414: bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
! 2415: afi_t afi, safi_t safi, struct prefix_rd *prd,
! 2416: u_char *tag)
! 2417: {
! 2418: unsigned long cp;
! 2419: unsigned long attrlen_pnt;
! 2420: bgp_size_t size;
! 2421:
! 2422: cp = stream_get_endp (s);
! 2423:
! 2424: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
! 2425: stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
! 2426:
! 2427: attrlen_pnt = stream_get_endp (s);
! 2428: stream_putc (s, 0); /* Length of this attribute. */
! 2429:
! 2430: stream_putw (s, family2afi (p->family));
! 2431:
! 2432: if (safi == SAFI_MPLS_VPN)
! 2433: {
! 2434: /* SAFI */
! 2435: stream_putc (s, BGP_SAFI_VPNV4);
! 2436:
! 2437: /* prefix. */
! 2438: stream_putc (s, p->prefixlen + 88);
! 2439: stream_put (s, tag, 3);
! 2440: stream_put (s, prd->val, 8);
! 2441: stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
! 2442: }
! 2443: else
! 2444: {
! 2445: /* SAFI */
! 2446: stream_putc (s, safi);
! 2447:
! 2448: /* prefix */
! 2449: stream_put_prefix (s, p);
! 2450: }
! 2451:
! 2452: /* Set MP attribute length. */
! 2453: size = stream_get_endp (s) - attrlen_pnt - 1;
! 2454: stream_putc_at (s, attrlen_pnt, size);
! 2455:
! 2456: return stream_get_endp (s) - cp;
! 2457: }
! 2458:
! 2459: /* Initialization of attribute. */
! 2460: void
! 2461: bgp_attr_init (void)
! 2462: {
! 2463: aspath_init ();
! 2464: attrhash_init ();
! 2465: community_init ();
! 2466: ecommunity_init ();
! 2467: cluster_init ();
! 2468: transit_init ();
! 2469: }
! 2470:
! 2471: void
! 2472: bgp_attr_finish (void)
! 2473: {
! 2474: aspath_finish ();
! 2475: attrhash_finish ();
! 2476: community_finish ();
! 2477: ecommunity_finish ();
! 2478: cluster_finish ();
! 2479: transit_finish ();
! 2480: }
! 2481:
! 2482: /* Make attribute packet. */
! 2483: void
! 2484: bgp_dump_routes_attr (struct stream *s, struct attr *attr,
! 2485: struct prefix *prefix)
! 2486: {
! 2487: unsigned long cp;
! 2488: unsigned long len;
! 2489: size_t aspath_lenp;
! 2490: struct aspath *aspath;
! 2491:
! 2492: /* Remember current pointer. */
! 2493: cp = stream_get_endp (s);
! 2494:
! 2495: /* Place holder of length. */
! 2496: stream_putw (s, 0);
! 2497:
! 2498: /* Origin attribute. */
! 2499: stream_putc (s, BGP_ATTR_FLAG_TRANS);
! 2500: stream_putc (s, BGP_ATTR_ORIGIN);
! 2501: stream_putc (s, 1);
! 2502: stream_putc (s, attr->origin);
! 2503:
! 2504: aspath = attr->aspath;
! 2505:
! 2506: stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
! 2507: stream_putc (s, BGP_ATTR_AS_PATH);
! 2508: aspath_lenp = stream_get_endp (s);
! 2509: stream_putw (s, 0);
! 2510:
! 2511: stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
! 2512:
! 2513: /* Nexthop attribute. */
! 2514: /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
! 2515: if(prefix != NULL
! 2516: #ifdef HAVE_IPV6
! 2517: && prefix->family != AF_INET6
! 2518: #endif /* HAVE_IPV6 */
! 2519: )
! 2520: {
! 2521: stream_putc (s, BGP_ATTR_FLAG_TRANS);
! 2522: stream_putc (s, BGP_ATTR_NEXT_HOP);
! 2523: stream_putc (s, 4);
! 2524: stream_put_ipv4 (s, attr->nexthop.s_addr);
! 2525: }
! 2526:
! 2527: /* MED attribute. */
! 2528: if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
! 2529: {
! 2530: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
! 2531: stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
! 2532: stream_putc (s, 4);
! 2533: stream_putl (s, attr->med);
! 2534: }
! 2535:
! 2536: /* Local preference. */
! 2537: if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
! 2538: {
! 2539: stream_putc (s, BGP_ATTR_FLAG_TRANS);
! 2540: stream_putc (s, BGP_ATTR_LOCAL_PREF);
! 2541: stream_putc (s, 4);
! 2542: stream_putl (s, attr->local_pref);
! 2543: }
! 2544:
! 2545: /* Atomic aggregate. */
! 2546: if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
! 2547: {
! 2548: stream_putc (s, BGP_ATTR_FLAG_TRANS);
! 2549: stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
! 2550: stream_putc (s, 0);
! 2551: }
! 2552:
! 2553: /* Aggregator. */
! 2554: if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
! 2555: {
! 2556: assert (attr->extra);
! 2557: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
! 2558: stream_putc (s, BGP_ATTR_AGGREGATOR);
! 2559: stream_putc (s, 8);
! 2560: stream_putl (s, attr->extra->aggregator_as);
! 2561: stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
! 2562: }
! 2563:
! 2564: /* Community attribute. */
! 2565: if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
! 2566: {
! 2567: if (attr->community->size * 4 > 255)
! 2568: {
! 2569: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
! 2570: stream_putc (s, BGP_ATTR_COMMUNITIES);
! 2571: stream_putw (s, attr->community->size * 4);
! 2572: }
! 2573: else
! 2574: {
! 2575: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
! 2576: stream_putc (s, BGP_ATTR_COMMUNITIES);
! 2577: stream_putc (s, attr->community->size * 4);
! 2578: }
! 2579: stream_put (s, attr->community->val, attr->community->size * 4);
! 2580: }
! 2581:
! 2582: #ifdef HAVE_IPV6
! 2583: /* Add a MP_NLRI attribute to dump the IPv6 next hop */
! 2584: if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
! 2585: (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
! 2586: {
! 2587: int sizep;
! 2588: struct attr_extra *attre = attr->extra;
! 2589:
! 2590: stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
! 2591: stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
! 2592: sizep = stream_get_endp (s);
! 2593:
! 2594: /* MP header */
! 2595: stream_putc (s, 0); /* Marker: Attribute length. */
! 2596: stream_putw(s, AFI_IP6); /* AFI */
! 2597: stream_putc(s, SAFI_UNICAST); /* SAFI */
! 2598:
! 2599: /* Next hop */
! 2600: stream_putc(s, attre->mp_nexthop_len);
! 2601: stream_put(s, &attre->mp_nexthop_global, 16);
! 2602: if (attre->mp_nexthop_len == 32)
! 2603: stream_put(s, &attre->mp_nexthop_local, 16);
! 2604:
! 2605: /* SNPA */
! 2606: stream_putc(s, 0);
! 2607:
! 2608: /* Prefix */
! 2609: stream_put_prefix(s, prefix);
! 2610:
! 2611: /* Set MP attribute length. */
! 2612: stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
! 2613: }
! 2614: #endif /* HAVE_IPV6 */
! 2615:
! 2616: /* Return total size of attribute. */
! 2617: len = stream_get_endp (s) - cp - 2;
! 2618: stream_putw_at (s, cp, len);
! 2619: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>