Annotation of embedaddon/quagga/bgpd/bgp_open.c, revision 1.1
1.1 ! misho 1: /* BGP open message handling
! 2: Copyright (C) 1998, 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 "stream.h"
! 26: #include "thread.h"
! 27: #include "log.h"
! 28: #include "command.h"
! 29: #include "memory.h"
! 30:
! 31: #include "bgpd/bgpd.h"
! 32: #include "bgpd/bgp_attr.h"
! 33: #include "bgpd/bgp_debug.h"
! 34: #include "bgpd/bgp_fsm.h"
! 35: #include "bgpd/bgp_packet.h"
! 36: #include "bgpd/bgp_open.h"
! 37: #include "bgpd/bgp_aspath.h"
! 38: #include "bgpd/bgp_vty.h"
! 39:
! 40: /* BGP-4 Multiprotocol Extentions lead us to the complex world. We can
! 41: negotiate remote peer supports extentions or not. But if
! 42: remote-peer doesn't supports negotiation process itself. We would
! 43: like to do manual configuration.
! 44:
! 45: So there is many configurable point. First of all we want set each
! 46: peer whether we send capability negotiation to the peer or not.
! 47: Next, if we send capability to the peer we want to set my capabilty
! 48: inforation at each peer. */
! 49:
! 50: void
! 51: bgp_capability_vty_out (struct vty *vty, struct peer *peer)
! 52: {
! 53: char *pnt;
! 54: char *end;
! 55: struct capability_mp_data mpc;
! 56: struct capability_header *hdr;
! 57:
! 58: pnt = peer->notify.data;
! 59: end = pnt + peer->notify.length;
! 60:
! 61: while (pnt < end)
! 62: {
! 63: if (pnt + sizeof (struct capability_mp_data) + 2 > end)
! 64: return;
! 65:
! 66: hdr = (struct capability_header *)pnt;
! 67: if (pnt + hdr->length + 2 > end)
! 68: return;
! 69:
! 70: memcpy (&mpc, pnt + 2, sizeof(struct capability_mp_data));
! 71:
! 72: if (hdr->code == CAPABILITY_CODE_MP)
! 73: {
! 74: vty_out (vty, " Capability error for: Multi protocol ");
! 75:
! 76: switch (ntohs (mpc.afi))
! 77: {
! 78: case AFI_IP:
! 79: vty_out (vty, "AFI IPv4, ");
! 80: break;
! 81: case AFI_IP6:
! 82: vty_out (vty, "AFI IPv6, ");
! 83: break;
! 84: default:
! 85: vty_out (vty, "AFI Unknown %d, ", ntohs (mpc.afi));
! 86: break;
! 87: }
! 88: switch (mpc.safi)
! 89: {
! 90: case SAFI_UNICAST:
! 91: vty_out (vty, "SAFI Unicast");
! 92: break;
! 93: case SAFI_MULTICAST:
! 94: vty_out (vty, "SAFI Multicast");
! 95: break;
! 96: case SAFI_UNICAST_MULTICAST:
! 97: vty_out (vty, "SAFI Unicast Multicast");
! 98: break;
! 99: case BGP_SAFI_VPNV4:
! 100: vty_out (vty, "SAFI MPLS-VPN");
! 101: break;
! 102: default:
! 103: vty_out (vty, "SAFI Unknown %d ", mpc.safi);
! 104: break;
! 105: }
! 106: vty_out (vty, "%s", VTY_NEWLINE);
! 107: }
! 108: else if (hdr->code >= 128)
! 109: vty_out (vty, " Capability error: vendor specific capability code %d",
! 110: hdr->code);
! 111: else
! 112: vty_out (vty, " Capability error: unknown capability code %d",
! 113: hdr->code);
! 114:
! 115: pnt += hdr->length + 2;
! 116: }
! 117: }
! 118:
! 119: static void
! 120: bgp_capability_mp_data (struct stream *s, struct capability_mp_data *mpc)
! 121: {
! 122: mpc->afi = stream_getw (s);
! 123: mpc->reserved = stream_getc (s);
! 124: mpc->safi = stream_getc (s);
! 125: }
! 126:
! 127: int
! 128: bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi)
! 129: {
! 130: /* VPNvX are AFI specific */
! 131: if ((afi == AFI_IP6 && *safi == BGP_SAFI_VPNV4)
! 132: || (afi == AFI_IP && *safi == BGP_SAFI_VPNV6))
! 133: {
! 134: zlog_warn ("Invalid afi/safi combination (%u/%u)", afi, *safi);
! 135: return 0;
! 136: }
! 137:
! 138: switch (afi)
! 139: {
! 140: case AFI_IP:
! 141: #ifdef HAVE_IPV6
! 142: case AFI_IP6:
! 143: #endif
! 144: switch (*safi)
! 145: {
! 146: /* BGP VPNvX SAFI isn't contigious with others, remap */
! 147: case BGP_SAFI_VPNV4:
! 148: case BGP_SAFI_VPNV6:
! 149: *safi = SAFI_MPLS_VPN;
! 150: case SAFI_UNICAST:
! 151: case SAFI_MULTICAST:
! 152: case SAFI_MPLS_VPN:
! 153: return 1;
! 154: }
! 155: }
! 156: zlog_debug ("unknown afi/safi (%u/%u)", afi, *safi);
! 157:
! 158: return 0;
! 159: }
! 160:
! 161: /* Set negotiated capability value. */
! 162: static int
! 163: bgp_capability_mp (struct peer *peer, struct capability_header *hdr)
! 164: {
! 165: struct capability_mp_data mpc;
! 166: struct stream *s = BGP_INPUT (peer);
! 167:
! 168: bgp_capability_mp_data (s, &mpc);
! 169:
! 170: if (BGP_DEBUG (normal, NORMAL))
! 171: zlog_debug ("%s OPEN has MP_EXT CAP for afi/safi: %u/%u",
! 172: peer->host, mpc.afi, mpc.safi);
! 173:
! 174: if (!bgp_afi_safi_valid_indices (mpc.afi, &mpc.safi))
! 175: return -1;
! 176:
! 177: /* Now safi remapped, and afi/safi are valid array indices */
! 178: peer->afc_recv[mpc.afi][mpc.safi] = 1;
! 179:
! 180: if (peer->afc[mpc.afi][mpc.safi])
! 181: peer->afc_nego[mpc.afi][mpc.safi] = 1;
! 182: else
! 183: return -1;
! 184:
! 185: return 0;
! 186: }
! 187:
! 188: static void
! 189: bgp_capability_orf_not_support (struct peer *peer, afi_t afi, safi_t safi,
! 190: u_char type, u_char mode)
! 191: {
! 192: if (BGP_DEBUG (normal, NORMAL))
! 193: zlog_debug ("%s Addr-family %d/%d has ORF type/mode %d/%d not supported",
! 194: peer->host, afi, safi, type, mode);
! 195: }
! 196:
! 197: static const struct message orf_type_str[] =
! 198: {
! 199: { ORF_TYPE_PREFIX, "Prefixlist" },
! 200: { ORF_TYPE_PREFIX_OLD, "Prefixlist (old)" },
! 201: };
! 202: static const int orf_type_str_max
! 203: = sizeof(orf_type_str)/sizeof(orf_type_str[0]);
! 204:
! 205: static const struct message orf_mode_str[] =
! 206: {
! 207: { ORF_MODE_RECEIVE, "Receive" },
! 208: { ORF_MODE_SEND, "Send" },
! 209: { ORF_MODE_BOTH, "Both" },
! 210: };
! 211: static const int orf_mode_str_max
! 212: = sizeof(orf_mode_str)/sizeof(orf_mode_str[0]);
! 213:
! 214: static int
! 215: bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)
! 216: {
! 217: struct stream *s = BGP_INPUT (peer);
! 218: struct capability_orf_entry entry;
! 219: afi_t afi;
! 220: safi_t safi;
! 221: u_char type;
! 222: u_char mode;
! 223: u_int16_t sm_cap = 0; /* capability send-mode receive */
! 224: u_int16_t rm_cap = 0; /* capability receive-mode receive */
! 225: int i;
! 226:
! 227: /* ORF Entry header */
! 228: bgp_capability_mp_data (s, &entry.mpc);
! 229: entry.num = stream_getc (s);
! 230: afi = entry.mpc.afi;
! 231: safi = entry.mpc.safi;
! 232:
! 233: if (BGP_DEBUG (normal, NORMAL))
! 234: zlog_debug ("%s ORF Cap entry for afi/safi: %u/%u",
! 235: peer->host, entry.mpc.afi, entry.mpc.safi);
! 236:
! 237: /* Check AFI and SAFI. */
! 238: if (!bgp_afi_safi_valid_indices (entry.mpc.afi, &safi))
! 239: {
! 240: zlog_info ("%s Addr-family %d/%d not supported."
! 241: " Ignoring the ORF capability",
! 242: peer->host, entry.mpc.afi, entry.mpc.safi);
! 243: return 0;
! 244: }
! 245:
! 246: /* validate number field */
! 247: if (sizeof (struct capability_orf_entry) + (entry.num * 2) > hdr->length)
! 248: {
! 249: zlog_info ("%s ORF Capability entry length error,"
! 250: " Cap length %u, num %u",
! 251: peer->host, hdr->length, entry.num);
! 252: bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
! 253: return -1;
! 254: }
! 255:
! 256: for (i = 0 ; i < entry.num ; i++)
! 257: {
! 258: type = stream_getc(s);
! 259: mode = stream_getc(s);
! 260:
! 261: /* ORF Mode error check */
! 262: switch (mode)
! 263: {
! 264: case ORF_MODE_BOTH:
! 265: case ORF_MODE_SEND:
! 266: case ORF_MODE_RECEIVE:
! 267: break;
! 268: default:
! 269: bgp_capability_orf_not_support (peer, afi, safi, type, mode);
! 270: continue;
! 271: }
! 272: /* ORF Type and afi/safi error checks */
! 273: /* capcode versus type */
! 274: switch (hdr->code)
! 275: {
! 276: case CAPABILITY_CODE_ORF:
! 277: switch (type)
! 278: {
! 279: case ORF_TYPE_PREFIX:
! 280: break;
! 281: default:
! 282: bgp_capability_orf_not_support (peer, afi, safi, type, mode);
! 283: continue;
! 284: }
! 285: break;
! 286: case CAPABILITY_CODE_ORF_OLD:
! 287: switch (type)
! 288: {
! 289: case ORF_TYPE_PREFIX_OLD:
! 290: break;
! 291: default:
! 292: bgp_capability_orf_not_support (peer, afi, safi, type, mode);
! 293: continue;
! 294: }
! 295: break;
! 296: default:
! 297: bgp_capability_orf_not_support (peer, afi, safi, type, mode);
! 298: continue;
! 299: }
! 300:
! 301: /* AFI vs SAFI */
! 302: if (!((afi == AFI_IP && safi == SAFI_UNICAST)
! 303: || (afi == AFI_IP && safi == SAFI_MULTICAST)
! 304: || (afi == AFI_IP6 && safi == SAFI_UNICAST)))
! 305: {
! 306: bgp_capability_orf_not_support (peer, afi, safi, type, mode);
! 307: continue;
! 308: }
! 309:
! 310: if (BGP_DEBUG (normal, NORMAL))
! 311: zlog_debug ("%s OPEN has %s ORF capability"
! 312: " as %s for afi/safi: %d/%d",
! 313: peer->host, LOOKUP (orf_type_str, type),
! 314: LOOKUP (orf_mode_str, mode),
! 315: entry.mpc.afi, safi);
! 316:
! 317: if (hdr->code == CAPABILITY_CODE_ORF)
! 318: {
! 319: sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV;
! 320: rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV;
! 321: }
! 322: else if (hdr->code == CAPABILITY_CODE_ORF_OLD)
! 323: {
! 324: sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV;
! 325: rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV;
! 326: }
! 327: else
! 328: {
! 329: bgp_capability_orf_not_support (peer, afi, safi, type, mode);
! 330: continue;
! 331: }
! 332:
! 333: switch (mode)
! 334: {
! 335: case ORF_MODE_BOTH:
! 336: SET_FLAG (peer->af_cap[afi][safi], sm_cap);
! 337: SET_FLAG (peer->af_cap[afi][safi], rm_cap);
! 338: break;
! 339: case ORF_MODE_SEND:
! 340: SET_FLAG (peer->af_cap[afi][safi], sm_cap);
! 341: break;
! 342: case ORF_MODE_RECEIVE:
! 343: SET_FLAG (peer->af_cap[afi][safi], rm_cap);
! 344: break;
! 345: }
! 346: }
! 347: return 0;
! 348: }
! 349:
! 350: static int
! 351: bgp_capability_orf (struct peer *peer, struct capability_header *hdr)
! 352: {
! 353: struct stream *s = BGP_INPUT (peer);
! 354: size_t end = stream_get_getp (s) + hdr->length;
! 355:
! 356: assert (stream_get_getp(s) + sizeof(struct capability_orf_entry) <= end);
! 357:
! 358: /* We must have at least one ORF entry, as the caller has already done
! 359: * minimum length validation for the capability code - for ORF there must
! 360: * at least one ORF entry (header and unknown number of pairs of bytes).
! 361: */
! 362: do
! 363: {
! 364: if (bgp_capability_orf_entry (peer, hdr) == -1)
! 365: return -1;
! 366: }
! 367: while (stream_get_getp(s) + sizeof(struct capability_orf_entry) < end);
! 368:
! 369: return 0;
! 370: }
! 371:
! 372: static int
! 373: bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)
! 374: {
! 375: struct stream *s = BGP_INPUT (peer);
! 376: u_int16_t restart_flag_time;
! 377: int restart_bit = 0;
! 378: size_t end = stream_get_getp (s) + caphdr->length;
! 379:
! 380: SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV);
! 381: restart_flag_time = stream_getw(s);
! 382: if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT))
! 383: restart_bit = 1;
! 384: UNSET_FLAG (restart_flag_time, 0xF000);
! 385: peer->v_gr_restart = restart_flag_time;
! 386:
! 387: if (BGP_DEBUG (normal, NORMAL))
! 388: {
! 389: zlog_debug ("%s OPEN has Graceful Restart capability", peer->host);
! 390: zlog_debug ("%s Peer has%srestarted. Restart Time : %d",
! 391: peer->host, restart_bit ? " " : " not ",
! 392: peer->v_gr_restart);
! 393: }
! 394:
! 395: while (stream_get_getp (s) + 4 < end)
! 396: {
! 397: afi_t afi = stream_getw (s);
! 398: safi_t safi = stream_getc (s);
! 399: u_char flag = stream_getc (s);
! 400:
! 401: if (!bgp_afi_safi_valid_indices (afi, &safi))
! 402: {
! 403: if (BGP_DEBUG (normal, NORMAL))
! 404: zlog_debug ("%s Addr-family %d/%d(afi/safi) not supported."
! 405: " Ignore the Graceful Restart capability",
! 406: peer->host, afi, safi);
! 407: }
! 408: else if (!peer->afc[afi][safi])
! 409: {
! 410: if (BGP_DEBUG (normal, NORMAL))
! 411: zlog_debug ("%s Addr-family %d/%d(afi/safi) not enabled."
! 412: " Ignore the Graceful Restart capability",
! 413: peer->host, afi, safi);
! 414: }
! 415: else
! 416: {
! 417: if (BGP_DEBUG (normal, NORMAL))
! 418: zlog_debug ("%s Address family %s is%spreserved", peer->host,
! 419: afi_safi_print (afi, safi),
! 420: CHECK_FLAG (peer->af_cap[afi][safi],
! 421: PEER_CAP_RESTART_AF_PRESERVE_RCV)
! 422: ? " " : " not ");
! 423:
! 424: SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV);
! 425: if (CHECK_FLAG (flag, RESTART_F_BIT))
! 426: SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV);
! 427:
! 428: }
! 429: }
! 430: return 0;
! 431: }
! 432:
! 433: static as_t
! 434: bgp_capability_as4 (struct peer *peer, struct capability_header *hdr)
! 435: {
! 436: as_t as4 = stream_getl (BGP_INPUT(peer));
! 437:
! 438: if (BGP_DEBUG (as4, AS4))
! 439: zlog_debug ("%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u",
! 440: peer->host, as4);
! 441: SET_FLAG (peer->cap, PEER_CAP_AS4_RCV);
! 442:
! 443: return as4;
! 444: }
! 445:
! 446: static const struct message capcode_str[] =
! 447: {
! 448: { CAPABILITY_CODE_MP, "MultiProtocol Extensions" },
! 449: { CAPABILITY_CODE_REFRESH, "Route Refresh" },
! 450: { CAPABILITY_CODE_ORF, "Cooperative Route Filtering" },
! 451: { CAPABILITY_CODE_RESTART, "Graceful Restart" },
! 452: { CAPABILITY_CODE_AS4, "4-octet AS number" },
! 453: { CAPABILITY_CODE_DYNAMIC, "Dynamic" },
! 454: { CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)" },
! 455: { CAPABILITY_CODE_ORF_OLD, "ORF (Old)" },
! 456: };
! 457: static const int capcode_str_max = sizeof(capcode_str)/sizeof(capcode_str[0]);
! 458:
! 459: /* Minimum sizes for length field of each cap (so not inc. the header) */
! 460: static const size_t cap_minsizes[] =
! 461: {
! 462: [CAPABILITY_CODE_MP] = sizeof (struct capability_mp_data),
! 463: [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN,
! 464: [CAPABILITY_CODE_ORF] = sizeof (struct capability_orf_entry),
! 465: [CAPABILITY_CODE_RESTART] = sizeof (struct capability_gr),
! 466: [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN,
! 467: [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN,
! 468: [CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN,
! 469: [CAPABILITY_CODE_ORF_OLD] = sizeof (struct capability_orf_entry),
! 470: };
! 471:
! 472: /* Parse given capability.
! 473: * XXX: This is reading into a stream, but not using stream API
! 474: */
! 475: static int
! 476: bgp_capability_parse (struct peer *peer, size_t length, u_char **error)
! 477: {
! 478: int ret;
! 479: struct stream *s = BGP_INPUT (peer);
! 480: size_t end = stream_get_getp (s) + length;
! 481:
! 482: assert (STREAM_READABLE (s) >= length);
! 483:
! 484: while (stream_get_getp (s) < end)
! 485: {
! 486: size_t start;
! 487: u_char *sp = stream_pnt (s);
! 488: struct capability_header caphdr;
! 489:
! 490: /* We need at least capability code and capability length. */
! 491: if (stream_get_getp(s) + 2 > end)
! 492: {
! 493: zlog_info ("%s Capability length error (< header)", peer->host);
! 494: bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
! 495: return -1;
! 496: }
! 497:
! 498: caphdr.code = stream_getc (s);
! 499: caphdr.length = stream_getc (s);
! 500: start = stream_get_getp (s);
! 501:
! 502: /* Capability length check sanity check. */
! 503: if (start + caphdr.length > end)
! 504: {
! 505: zlog_info ("%s Capability length error (< length)", peer->host);
! 506: bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
! 507: return -1;
! 508: }
! 509:
! 510: if (BGP_DEBUG (normal, NORMAL))
! 511: zlog_debug ("%s OPEN has %s capability (%u), length %u",
! 512: peer->host,
! 513: LOOKUP (capcode_str, caphdr.code),
! 514: caphdr.code, caphdr.length);
! 515:
! 516: /* Length sanity check, type-specific, for known capabilities */
! 517: switch (caphdr.code)
! 518: {
! 519: case CAPABILITY_CODE_MP:
! 520: case CAPABILITY_CODE_REFRESH:
! 521: case CAPABILITY_CODE_REFRESH_OLD:
! 522: case CAPABILITY_CODE_ORF:
! 523: case CAPABILITY_CODE_ORF_OLD:
! 524: case CAPABILITY_CODE_RESTART:
! 525: case CAPABILITY_CODE_AS4:
! 526: case CAPABILITY_CODE_DYNAMIC:
! 527: /* Check length. */
! 528: if (caphdr.length < cap_minsizes[caphdr.code])
! 529: {
! 530: zlog_info ("%s %s Capability length error: got %u,"
! 531: " expected at least %u",
! 532: peer->host,
! 533: LOOKUP (capcode_str, caphdr.code),
! 534: caphdr.length,
! 535: (unsigned) cap_minsizes[caphdr.code]);
! 536: bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
! 537: return -1;
! 538: }
! 539: /* we deliberately ignore unknown codes, see below */
! 540: default:
! 541: break;
! 542: }
! 543:
! 544: switch (caphdr.code)
! 545: {
! 546: case CAPABILITY_CODE_MP:
! 547: {
! 548: /* Ignore capability when override-capability is set. */
! 549: if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
! 550: {
! 551: /* Set negotiated value. */
! 552: ret = bgp_capability_mp (peer, &caphdr);
! 553:
! 554: /* Unsupported Capability. */
! 555: if (ret < 0)
! 556: {
! 557: /* Store return data. */
! 558: memcpy (*error, sp, caphdr.length + 2);
! 559: *error += caphdr.length + 2;
! 560: }
! 561: }
! 562: }
! 563: break;
! 564: case CAPABILITY_CODE_REFRESH:
! 565: case CAPABILITY_CODE_REFRESH_OLD:
! 566: {
! 567: /* BGP refresh capability */
! 568: if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD)
! 569: SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV);
! 570: else
! 571: SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV);
! 572: }
! 573: break;
! 574: case CAPABILITY_CODE_ORF:
! 575: case CAPABILITY_CODE_ORF_OLD:
! 576: if (bgp_capability_orf (peer, &caphdr))
! 577: return -1;
! 578: break;
! 579: case CAPABILITY_CODE_RESTART:
! 580: if (bgp_capability_restart (peer, &caphdr))
! 581: return -1;
! 582: break;
! 583: case CAPABILITY_CODE_DYNAMIC:
! 584: SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
! 585: break;
! 586: case CAPABILITY_CODE_AS4:
! 587: /* Already handled as a special-case parsing of the capabilities
! 588: * at the beginning of OPEN processing. So we care not a jot
! 589: * for the value really, only error case.
! 590: */
! 591: if (!bgp_capability_as4 (peer, &caphdr))
! 592: return -1;
! 593: break;
! 594: default:
! 595: if (caphdr.code > 128)
! 596: {
! 597: /* We don't send Notification for unknown vendor specific
! 598: capabilities. It seems reasonable for now... */
! 599: zlog_warn ("%s Vendor specific capability %d",
! 600: peer->host, caphdr.code);
! 601: }
! 602: else
! 603: {
! 604: zlog_warn ("%s unrecognized capability code: %d - ignored",
! 605: peer->host, caphdr.code);
! 606: memcpy (*error, sp, caphdr.length + 2);
! 607: *error += caphdr.length + 2;
! 608: }
! 609: }
! 610: if (stream_get_getp(s) != (start + caphdr.length))
! 611: {
! 612: if (stream_get_getp(s) > (start + caphdr.length))
! 613: zlog_warn ("%s Cap-parser for %s read past cap-length, %u!",
! 614: peer->host, LOOKUP (capcode_str, caphdr.code),
! 615: caphdr.length);
! 616: stream_set_getp (s, start + caphdr.length);
! 617: }
! 618: }
! 619: return 0;
! 620: }
! 621:
! 622: static int
! 623: bgp_auth_parse (struct peer *peer, size_t length)
! 624: {
! 625: bgp_notify_send (peer,
! 626: BGP_NOTIFY_OPEN_ERR,
! 627: BGP_NOTIFY_OPEN_AUTH_FAILURE);
! 628: return -1;
! 629: }
! 630:
! 631: static int
! 632: strict_capability_same (struct peer *peer)
! 633: {
! 634: int i, j;
! 635:
! 636: for (i = AFI_IP; i < AFI_MAX; i++)
! 637: for (j = SAFI_UNICAST; j < SAFI_MAX; j++)
! 638: if (peer->afc[i][j] != peer->afc_nego[i][j])
! 639: return 0;
! 640: return 1;
! 641: }
! 642:
! 643: /* peek into option, stores ASN to *as4 if the AS4 capability was found.
! 644: * Returns 0 if no as4 found, as4cap value otherwise.
! 645: */
! 646: as_t
! 647: peek_for_as4_capability (struct peer *peer, u_char length)
! 648: {
! 649: struct stream *s = BGP_INPUT (peer);
! 650: size_t orig_getp = stream_get_getp (s);
! 651: size_t end = orig_getp + length;
! 652: as_t as4 = 0;
! 653:
! 654: /* The full capability parser will better flag the error.. */
! 655: if (STREAM_READABLE(s) < length)
! 656: return 0;
! 657:
! 658: if (BGP_DEBUG (as4, AS4))
! 659: zlog_info ("%s [AS4] rcv OPEN w/ OPTION parameter len: %u,"
! 660: " peeking for as4",
! 661: peer->host, length);
! 662: /* the error cases we DONT handle, we ONLY try to read as4 out of
! 663: * correctly formatted options.
! 664: */
! 665: while (stream_get_getp(s) < end)
! 666: {
! 667: u_char opt_type;
! 668: u_char opt_length;
! 669:
! 670: /* Check the length. */
! 671: if (stream_get_getp (s) + 2 > end)
! 672: goto end;
! 673:
! 674: /* Fetch option type and length. */
! 675: opt_type = stream_getc (s);
! 676: opt_length = stream_getc (s);
! 677:
! 678: /* Option length check. */
! 679: if (stream_get_getp (s) + opt_length > end)
! 680: goto end;
! 681:
! 682: if (opt_type == BGP_OPEN_OPT_CAP)
! 683: {
! 684: unsigned long capd_start = stream_get_getp (s);
! 685: unsigned long capd_end = capd_start + opt_length;
! 686:
! 687: assert (capd_end <= end);
! 688:
! 689: while (stream_get_getp (s) < capd_end)
! 690: {
! 691: struct capability_header hdr;
! 692:
! 693: if (stream_get_getp (s) + 2 > capd_end)
! 694: goto end;
! 695:
! 696: hdr.code = stream_getc (s);
! 697: hdr.length = stream_getc (s);
! 698:
! 699: if ((stream_get_getp(s) + hdr.length) > capd_end)
! 700: goto end;
! 701:
! 702: if (hdr.code == CAPABILITY_CODE_AS4)
! 703: {
! 704: if (hdr.length != CAPABILITY_CODE_AS4_LEN)
! 705: goto end;
! 706:
! 707: if (BGP_DEBUG (as4, AS4))
! 708: zlog_info ("[AS4] found AS4 capability, about to parse");
! 709: as4 = bgp_capability_as4 (peer, &hdr);
! 710:
! 711: goto end;
! 712: }
! 713: stream_forward_getp (s, hdr.length);
! 714: }
! 715: }
! 716: }
! 717:
! 718: end:
! 719: stream_set_getp (s, orig_getp);
! 720: return as4;
! 721: }
! 722:
! 723: /* Parse open option */
! 724: int
! 725: bgp_open_option_parse (struct peer *peer, u_char length, int *capability)
! 726: {
! 727: int ret;
! 728: u_char *error;
! 729: u_char error_data[BGP_MAX_PACKET_SIZE];
! 730: struct stream *s = BGP_INPUT(peer);
! 731: size_t end = stream_get_getp (s) + length;
! 732:
! 733: ret = 0;
! 734: error = error_data;
! 735:
! 736: if (BGP_DEBUG (normal, NORMAL))
! 737: zlog_debug ("%s rcv OPEN w/ OPTION parameter len: %u",
! 738: peer->host, length);
! 739:
! 740: while (stream_get_getp(s) < end)
! 741: {
! 742: u_char opt_type;
! 743: u_char opt_length;
! 744:
! 745: /* Must have at least an OPEN option header */
! 746: if (STREAM_READABLE(s) < 2)
! 747: {
! 748: zlog_info ("%s Option length error", peer->host);
! 749: bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
! 750: return -1;
! 751: }
! 752:
! 753: /* Fetch option type and length. */
! 754: opt_type = stream_getc (s);
! 755: opt_length = stream_getc (s);
! 756:
! 757: /* Option length check. */
! 758: if (STREAM_READABLE (s) < opt_length)
! 759: {
! 760: zlog_info ("%s Option length error", peer->host);
! 761: bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
! 762: return -1;
! 763: }
! 764:
! 765: if (BGP_DEBUG (normal, NORMAL))
! 766: zlog_debug ("%s rcvd OPEN w/ optional parameter type %u (%s) len %u",
! 767: peer->host, opt_type,
! 768: opt_type == BGP_OPEN_OPT_AUTH ? "Authentication" :
! 769: opt_type == BGP_OPEN_OPT_CAP ? "Capability" : "Unknown",
! 770: opt_length);
! 771:
! 772: switch (opt_type)
! 773: {
! 774: case BGP_OPEN_OPT_AUTH:
! 775: ret = bgp_auth_parse (peer, opt_length);
! 776: break;
! 777: case BGP_OPEN_OPT_CAP:
! 778: ret = bgp_capability_parse (peer, opt_length, &error);
! 779: *capability = 1;
! 780: break;
! 781: default:
! 782: bgp_notify_send (peer,
! 783: BGP_NOTIFY_OPEN_ERR,
! 784: BGP_NOTIFY_OPEN_UNSUP_PARAM);
! 785: ret = -1;
! 786: break;
! 787: }
! 788:
! 789: /* Parse error. To accumulate all unsupported capability codes,
! 790: bgp_capability_parse does not return -1 when encounter
! 791: unsupported capability code. To detect that, please check
! 792: error and erro_data pointer, like below. */
! 793: if (ret < 0)
! 794: return -1;
! 795: }
! 796:
! 797: /* All OPEN option is parsed. Check capability when strict compare
! 798: flag is enabled.*/
! 799: if (CHECK_FLAG (peer->flags, PEER_FLAG_STRICT_CAP_MATCH))
! 800: {
! 801: /* If Unsupported Capability exists. */
! 802: if (error != error_data)
! 803: {
! 804: bgp_notify_send_with_data (peer,
! 805: BGP_NOTIFY_OPEN_ERR,
! 806: BGP_NOTIFY_OPEN_UNSUP_CAPBL,
! 807: error_data, error - error_data);
! 808: return -1;
! 809: }
! 810:
! 811: /* Check local capability does not negotiated with remote
! 812: peer. */
! 813: if (! strict_capability_same (peer))
! 814: {
! 815: bgp_notify_send (peer,
! 816: BGP_NOTIFY_OPEN_ERR,
! 817: BGP_NOTIFY_OPEN_UNSUP_CAPBL);
! 818: return -1;
! 819: }
! 820: }
! 821:
! 822: /* Check there is no common capability send Unsupported Capability
! 823: error. */
! 824: if (*capability && ! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
! 825: {
! 826: if (! peer->afc_nego[AFI_IP][SAFI_UNICAST]
! 827: && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST]
! 828: && ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
! 829: && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST]
! 830: && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST])
! 831: {
! 832: plog_err (peer->log, "%s [Error] No common capability", peer->host);
! 833:
! 834: if (error != error_data)
! 835:
! 836: bgp_notify_send_with_data (peer,
! 837: BGP_NOTIFY_OPEN_ERR,
! 838: BGP_NOTIFY_OPEN_UNSUP_CAPBL,
! 839: error_data, error - error_data);
! 840: else
! 841: bgp_notify_send (peer,
! 842: BGP_NOTIFY_OPEN_ERR,
! 843: BGP_NOTIFY_OPEN_UNSUP_CAPBL);
! 844: return -1;
! 845: }
! 846: }
! 847: return 0;
! 848: }
! 849:
! 850: static void
! 851: bgp_open_capability_orf (struct stream *s, struct peer *peer,
! 852: afi_t afi, safi_t safi, u_char code)
! 853: {
! 854: u_char cap_len;
! 855: u_char orf_len;
! 856: unsigned long capp;
! 857: unsigned long orfp;
! 858: unsigned long numberp;
! 859: int number_of_orfs = 0;
! 860:
! 861: if (safi == SAFI_MPLS_VPN)
! 862: safi = BGP_SAFI_VPNV4;
! 863:
! 864: stream_putc (s, BGP_OPEN_OPT_CAP);
! 865: capp = stream_get_endp (s); /* Set Capability Len Pointer */
! 866: stream_putc (s, 0); /* Capability Length */
! 867: stream_putc (s, code); /* Capability Code */
! 868: orfp = stream_get_endp (s); /* Set ORF Len Pointer */
! 869: stream_putc (s, 0); /* ORF Length */
! 870: stream_putw (s, afi);
! 871: stream_putc (s, 0);
! 872: stream_putc (s, safi);
! 873: numberp = stream_get_endp (s); /* Set Number Pointer */
! 874: stream_putc (s, 0); /* Number of ORFs */
! 875:
! 876: /* Address Prefix ORF */
! 877: if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
! 878: || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
! 879: {
! 880: stream_putc (s, (code == CAPABILITY_CODE_ORF ?
! 881: ORF_TYPE_PREFIX : ORF_TYPE_PREFIX_OLD));
! 882:
! 883: if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
! 884: && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
! 885: {
! 886: SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV);
! 887: SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV);
! 888: stream_putc (s, ORF_MODE_BOTH);
! 889: }
! 890: else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM))
! 891: {
! 892: SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV);
! 893: stream_putc (s, ORF_MODE_SEND);
! 894: }
! 895: else
! 896: {
! 897: SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV);
! 898: stream_putc (s, ORF_MODE_RECEIVE);
! 899: }
! 900: number_of_orfs++;
! 901: }
! 902:
! 903: /* Total Number of ORFs. */
! 904: stream_putc_at (s, numberp, number_of_orfs);
! 905:
! 906: /* Total ORF Len. */
! 907: orf_len = stream_get_endp (s) - orfp - 1;
! 908: stream_putc_at (s, orfp, orf_len);
! 909:
! 910: /* Total Capability Len. */
! 911: cap_len = stream_get_endp (s) - capp - 1;
! 912: stream_putc_at (s, capp, cap_len);
! 913: }
! 914:
! 915: /* Fill in capability open option to the packet. */
! 916: void
! 917: bgp_open_capability (struct stream *s, struct peer *peer)
! 918: {
! 919: u_char len;
! 920: unsigned long cp;
! 921: afi_t afi;
! 922: safi_t safi;
! 923: as_t local_as;
! 924:
! 925: /* Remember current pointer for Opt Parm Len. */
! 926: cp = stream_get_endp (s);
! 927:
! 928: /* Opt Parm Len. */
! 929: stream_putc (s, 0);
! 930:
! 931: /* Do not send capability. */
! 932: if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN)
! 933: || CHECK_FLAG (peer->flags, PEER_FLAG_DONT_CAPABILITY))
! 934: return;
! 935:
! 936: /* IPv4 unicast. */
! 937: if (peer->afc[AFI_IP][SAFI_UNICAST])
! 938: {
! 939: peer->afc_adv[AFI_IP][SAFI_UNICAST] = 1;
! 940: stream_putc (s, BGP_OPEN_OPT_CAP);
! 941: stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
! 942: stream_putc (s, CAPABILITY_CODE_MP);
! 943: stream_putc (s, CAPABILITY_CODE_MP_LEN);
! 944: stream_putw (s, AFI_IP);
! 945: stream_putc (s, 0);
! 946: stream_putc (s, SAFI_UNICAST);
! 947: }
! 948: /* IPv4 multicast. */
! 949: if (peer->afc[AFI_IP][SAFI_MULTICAST])
! 950: {
! 951: peer->afc_adv[AFI_IP][SAFI_MULTICAST] = 1;
! 952: stream_putc (s, BGP_OPEN_OPT_CAP);
! 953: stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
! 954: stream_putc (s, CAPABILITY_CODE_MP);
! 955: stream_putc (s, CAPABILITY_CODE_MP_LEN);
! 956: stream_putw (s, AFI_IP);
! 957: stream_putc (s, 0);
! 958: stream_putc (s, SAFI_MULTICAST);
! 959: }
! 960: /* IPv4 VPN */
! 961: if (peer->afc[AFI_IP][SAFI_MPLS_VPN])
! 962: {
! 963: peer->afc_adv[AFI_IP][SAFI_MPLS_VPN] = 1;
! 964: stream_putc (s, BGP_OPEN_OPT_CAP);
! 965: stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
! 966: stream_putc (s, CAPABILITY_CODE_MP);
! 967: stream_putc (s, CAPABILITY_CODE_MP_LEN);
! 968: stream_putw (s, AFI_IP);
! 969: stream_putc (s, 0);
! 970: stream_putc (s, BGP_SAFI_VPNV4);
! 971: }
! 972: #ifdef HAVE_IPV6
! 973: /* IPv6 unicast. */
! 974: if (peer->afc[AFI_IP6][SAFI_UNICAST])
! 975: {
! 976: peer->afc_adv[AFI_IP6][SAFI_UNICAST] = 1;
! 977: stream_putc (s, BGP_OPEN_OPT_CAP);
! 978: stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
! 979: stream_putc (s, CAPABILITY_CODE_MP);
! 980: stream_putc (s, CAPABILITY_CODE_MP_LEN);
! 981: stream_putw (s, AFI_IP6);
! 982: stream_putc (s, 0);
! 983: stream_putc (s, SAFI_UNICAST);
! 984: }
! 985: /* IPv6 multicast. */
! 986: if (peer->afc[AFI_IP6][SAFI_MULTICAST])
! 987: {
! 988: peer->afc_adv[AFI_IP6][SAFI_MULTICAST] = 1;
! 989: stream_putc (s, BGP_OPEN_OPT_CAP);
! 990: stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
! 991: stream_putc (s, CAPABILITY_CODE_MP);
! 992: stream_putc (s, CAPABILITY_CODE_MP_LEN);
! 993: stream_putw (s, AFI_IP6);
! 994: stream_putc (s, 0);
! 995: stream_putc (s, SAFI_MULTICAST);
! 996: }
! 997: #endif /* HAVE_IPV6 */
! 998:
! 999: /* Route refresh. */
! 1000: SET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV);
! 1001: stream_putc (s, BGP_OPEN_OPT_CAP);
! 1002: stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2);
! 1003: stream_putc (s, CAPABILITY_CODE_REFRESH_OLD);
! 1004: stream_putc (s, CAPABILITY_CODE_REFRESH_LEN);
! 1005: stream_putc (s, BGP_OPEN_OPT_CAP);
! 1006: stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2);
! 1007: stream_putc (s, CAPABILITY_CODE_REFRESH);
! 1008: stream_putc (s, CAPABILITY_CODE_REFRESH_LEN);
! 1009:
! 1010: /* AS4 */
! 1011: SET_FLAG (peer->cap, PEER_CAP_AS4_ADV);
! 1012: stream_putc (s, BGP_OPEN_OPT_CAP);
! 1013: stream_putc (s, CAPABILITY_CODE_AS4_LEN + 2);
! 1014: stream_putc (s, CAPABILITY_CODE_AS4);
! 1015: stream_putc (s, CAPABILITY_CODE_AS4_LEN);
! 1016: if ( peer->change_local_as )
! 1017: local_as = peer->change_local_as;
! 1018: else
! 1019: local_as = peer->local_as;
! 1020: stream_putl (s, local_as );
! 1021:
! 1022: /* ORF capability. */
! 1023: for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
! 1024: for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
! 1025: if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
! 1026: || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
! 1027: {
! 1028: bgp_open_capability_orf (s, peer, afi, safi, CAPABILITY_CODE_ORF_OLD);
! 1029: bgp_open_capability_orf (s, peer, afi, safi, CAPABILITY_CODE_ORF);
! 1030: }
! 1031:
! 1032: /* Dynamic capability. */
! 1033: if (CHECK_FLAG (peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY))
! 1034: {
! 1035: SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV);
! 1036: stream_putc (s, BGP_OPEN_OPT_CAP);
! 1037: stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN + 2);
! 1038: stream_putc (s, CAPABILITY_CODE_DYNAMIC);
! 1039: stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN);
! 1040: }
! 1041:
! 1042: /* Graceful restart capability */
! 1043: if (bgp_flag_check (peer->bgp, BGP_FLAG_GRACEFUL_RESTART))
! 1044: {
! 1045: SET_FLAG (peer->cap, PEER_CAP_RESTART_ADV);
! 1046: stream_putc (s, BGP_OPEN_OPT_CAP);
! 1047: stream_putc (s, CAPABILITY_CODE_RESTART_LEN + 2);
! 1048: stream_putc (s, CAPABILITY_CODE_RESTART);
! 1049: stream_putc (s, CAPABILITY_CODE_RESTART_LEN);
! 1050: stream_putw (s, peer->bgp->restart_time);
! 1051: }
! 1052:
! 1053: /* Total Opt Parm Len. */
! 1054: len = stream_get_endp (s) - cp - 1;
! 1055: stream_putc_at (s, cp, len);
! 1056: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>