📄 bgp_attr.c
字号:
u_char snpa_num; u_char snpa_len; u_char *lim; bgp_size_t nlri_len; int ret; struct stream *s; /* Set end of packet. */ s = peer->ibuf; lim = stream_pnt (s) + length; /* Load AFI, SAFI. */ afi = stream_getw (s); safi = stream_getc (s); /* Get nexthop length. */ attr->mp_nexthop_len = stream_getc (s); /* Nexthop length check. */ switch (attr->mp_nexthop_len) { case 4: stream_get (&attr->mp_nexthop_global_in, s, 4); break; case 12: { u_int32_t rd_high; u_int32_t rd_low; rd_high = stream_getl (s); rd_low = stream_getl (s); stream_get (&attr->mp_nexthop_global_in, s, 4); } break;#ifdef HAVE_IPV6 case 16: stream_get (&attr->mp_nexthop_global, s, 16); break; case 32: stream_get (&attr->mp_nexthop_global, s, 16); stream_get (&attr->mp_nexthop_local, s, 16); if (! IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local)) { char buf1[INET6_ADDRSTRLEN]; char buf2[INET6_ADDRSTRLEN]; if (BGP_DEBUG (update, UPDATE_IN)) zlog_warn ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host, inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf1, INET6_ADDRSTRLEN), inet_ntop (AF_INET6, &attr->mp_nexthop_local, buf2, INET6_ADDRSTRLEN)); attr->mp_nexthop_len = 16; } break;#endif /* HAVE_IPV6 */ default: zlog_info ("Wrong multiprotocol next hop length: %d", attr->mp_nexthop_len); return -1; break; } snpa_num = stream_getc (s); while (snpa_num--) { snpa_len = stream_getc (s); stream_forward (s, (snpa_len + 1) >> 1); } nlri_len = lim - stream_pnt (s); if (safi != BGP_SAFI_VPNV4) { ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len); if (ret < 0) return -1; } mp_update->afi = afi; mp_update->safi = safi; mp_update->nlri = stream_pnt (s); mp_update->length = nlri_len; stream_forward (s, nlri_len); return 0;}/* Multiprotocol unreachable parse */intbgp_mp_unreach_parse (struct peer *peer, int length, struct bgp_nlri *mp_withdraw){ struct stream *s; u_int16_t afi; u_char safi; u_char *lim; u_int16_t withdraw_len; int ret; s = peer->ibuf; lim = stream_pnt (s) + length; afi = stream_getw (s); safi = stream_getc (s); withdraw_len = lim - stream_pnt (s); if (safi != BGP_SAFI_VPNV4) { ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len); if (ret < 0) return -1; } mp_withdraw->afi = afi; mp_withdraw->safi = safi; mp_withdraw->nlri = stream_pnt (s); mp_withdraw->length = withdraw_len; stream_forward (s, withdraw_len); return 0;}/* Extended Community attribute. */intbgp_attr_ext_communities (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag){ if (length == 0) attr->ecommunity = NULL; else { attr->ecommunity = ecommunity_parse (stream_pnt (peer->ibuf), length); stream_forward (peer->ibuf, length); } attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); return 0;}/* BGP unknown attribute treatment. */intbgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag, u_char type, bgp_size_t length, u_char *startp){ bgp_size_t total; struct transit *transit; if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s Unknown attribute is received (type %d, length %d)", peer->host, type, length); /* Forward read pointer of input stream. */ stream_forward (peer->ibuf, length); /* Adjest total length to include type and length. */ total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* If any of the mandatory well-known attributes are not recognized, then the Error Subcode is set to Unrecognized Well-known Attribute. The Data field contains the unrecognized attribute (type, length and value). */ if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) { /* Adjust startp to do not include flag value. */ bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_UNREC_ATTR, startp, total); return -1; } /* Unrecognized non-transitive optional attributes must be quietly ignored and not passed along to other BGP peers. */ if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) return 0; /* If a path with recognized transitive optional attribute is accepted and passed along to other BGP peers and the Partial bit in the Attribute Flags octet is set to 1 by some previous AS, it is not set back to 0 by the current AS. */ SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL); /* Store transitive attribute to the end of attr->transit. */ if (! attr->transit) { attr->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit)); memset (attr->transit, 0, sizeof (struct transit)); } transit = attr->transit; if (transit->val) transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val, transit->length + total); else transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total); memcpy (transit->val + transit->length, startp, total); transit->length += total; return 0;}/* Read attribute of update packet. This function is called from bgp_update() in bgpd.c. */intbgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw){ int ret; u_char flag; u_char type; bgp_size_t length; u_char *startp, *endp; u_char *attr_endp; u_char seen[BGP_ATTR_BITMAP_SIZE]; /* Initialize bitmap. */ memset (seen, 0, BGP_ATTR_BITMAP_SIZE); /* End pointer of BGP attribute. */ endp = BGP_INPUT_PNT (peer) + size; /* Get attributes to the end of attribute length. */ while (BGP_INPUT_PNT (peer) < endp) { /* Check remaining length check.*/ if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN) { zlog (peer->log, LOG_WARNING, "%s error BGP attribute length %d is smaller than min len", peer->host, endp - STREAM_PNT (BGP_INPUT (peer))); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); return -1; } /* Fetch attribute flag and type. */ startp = BGP_INPUT_PNT (peer); flag = stream_getc (BGP_INPUT (peer)); type = stream_getc (BGP_INPUT (peer)); /* Check extended attribue length bit. */ if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)) length = stream_getw (BGP_INPUT (peer)); else length = stream_getc (BGP_INPUT (peer)); /* If any attribute appears more than once in the UPDATE message, then the Error Subcode is set to Malformed Attribute List. */ if (CHECK_BITMAP (seen, type)) { zlog (peer->log, LOG_WARNING, "%s error BGP attribute type %d appears twice in a message", peer->host, type); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); return -1; } /* Set type to bitmap to check duplicate attribute. `type' is unsigned char so it never overflow bitmap range. */ SET_BITMAP (seen, type); /* Overflow check. */ attr_endp = BGP_INPUT_PNT (peer) + length; if (attr_endp > endp) { zlog (peer->log, LOG_WARNING, "%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); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); return -1; } /* OK check attribute and store it's value. */ switch (type) { case BGP_ATTR_ORIGIN: ret = bgp_attr_origin (peer, length, attr, flag, startp); break; case BGP_ATTR_AS_PATH: ret = bgp_attr_aspath (peer, length, attr, flag, startp); break; case BGP_ATTR_NEXT_HOP: ret = bgp_attr_nexthop (peer, length, attr, flag, startp); break; case BGP_ATTR_MULTI_EXIT_DISC: ret = bgp_attr_med (peer, length, attr, flag, startp); break; case BGP_ATTR_LOCAL_PREF: ret = bgp_attr_local_pref (peer, length, attr, flag); break; case BGP_ATTR_ATOMIC_AGGREGATE: ret = bgp_attr_atomic (peer, length, attr, flag); break; case BGP_ATTR_AGGREGATOR: ret = bgp_attr_aggregator (peer, length, attr, flag); break; case BGP_ATTR_COMMUNITIES: ret = bgp_attr_community (peer, length, attr, flag); break; case BGP_ATTR_ORIGINATOR_ID: ret = bgp_attr_originator_id (peer, length, attr, flag); break; case BGP_ATTR_CLUSTER_LIST: ret = bgp_attr_cluster_list (peer, length, attr, flag); break; case BGP_ATTR_MP_REACH_NLRI: ret = bgp_mp_reach_parse (peer, length, attr, mp_update); break; case BGP_ATTR_MP_UNREACH_NLRI: ret = bgp_mp_unreach_parse (peer, length, mp_withdraw); break; case BGP_ATTR_EXT_COMMUNITIES: ret = bgp_attr_ext_communities (peer, length, attr, flag); break; default: ret = bgp_attr_unknown (peer, attr, flag, type, length, startp); break; } /* If error occured immediately return to the caller. */ if (ret < 0) return ret; /* Check the fetched length. */ if (BGP_INPUT_PNT (peer) != attr_endp) { zlog (peer->log, LOG_WARNING, "%s BGP attribute fetch error", peer->host); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); return -1; } } /* Check final read pointer is same as end pointer. */ if (BGP_INPUT_PNT (peer) != endp) { zlog (peer->log, LOG_WARNING, "%s BGP attribute length mismatch", peer->host); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); return -1; } /* Finally intern unknown attribute. */ if (attr->transit) attr->transit = transit_intern (attr->transit); return 0;}/* Well-known attribute check. */intbgp_attr_check (struct peer *peer, struct attr *attr){ u_char type = 0; if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN))) type = BGP_ATTR_ORIGIN; if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))) type = BGP_ATTR_AS_PATH; if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))) type = BGP_ATTR_NEXT_HOP; if (peer_sort (peer) == BGP_PEER_IBGP && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) type = BGP_ATTR_LOCAL_PREF; if (type) { zlog (peer->log, LOG_WARNING, "%s Missing well-known attribute %d.", peer->host, type); bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MISS_ATTR, &type, 1); return -1; } return 0;}int stream_put_prefix (struct stream *, struct prefix *);/* Make attribute packet. */bgp_size_tbgp_packet_attribute (struct bgp *bgp, struct peer *peer, struct stream *s, struct attr *attr, struct prefix *p, afi_t afi, safi_t safi, struct peer *from, struct prefix_rd *prd, u_char *tag){ unsigned long cp; struct aspath *aspath; if (! bgp) bgp = bgp_get_default (); /* Remember current pointer. */ cp = stream_get_putp (s); /* Origin attribute. */ stream_putc (s, BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_ORIGIN); stream_putc (s, 1); stream_putc (s, attr->origin); /* AS path attribute. */ /* If remote-peer is EBGP */ if (peer_sort (peer) == BGP_PEER_EBGP && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED) || attr->aspath->length == 0) && ! (CHECK_FLAG (from->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))) { aspath = aspath_dup (attr->aspath); if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) { /* Strip the confed info, and then stuff our path CONFED_ID on the front */ aspath = aspath_delete_confed_seq (aspath); aspath = aspath_add_seq (aspath, bgp->confed_id); } else { aspath = aspath_add_seq (aspath, peer->local_as); if (peer->change_local_as) aspath = aspath_add_seq (aspath, peer->change_local_as); } } else if (peer_sort (peer) == BGP_PEER_CONFED) { /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */ aspath = aspath_dup (attr->aspath); aspath = aspath_add_confed_seq (aspath, peer->local_as); } else aspath = attr->aspath;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -