diff options
Diffstat (limited to 'bgpd/bgp_attr.c')
-rw-r--r-- | bgpd/bgp_attr.c | 82 |
1 files changed, 79 insertions, 3 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 07c94130..23d95865 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -56,6 +56,8 @@ static struct message attr_str [] = { BGP_ATTR_RCID_PATH, "RCID_PATH" }, { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" }, { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" }, + { BGP_ATTR_EXT_COMMUNITIES, "BGP_ATTR_EXT_COMMUNITIES" }, + { BGP_ATTR_AS_PATHLIMIT, "BGP_ATTR_AS_PATHLIMIT" }, { 0, NULL } }; int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]); @@ -345,6 +347,11 @@ attrhash_key_make (void *p) key += attr->nexthop.s_addr; key += attr->med; key += attr->local_pref; + if (attr->pathlimit.as) + { + key += attr->pathlimit.ttl; + key += attr->pathlimit.as; + } if (attr->extra) { @@ -396,7 +403,9 @@ attrhash_cmp (void *p1, void *p2) && attr1->aspath == attr2->aspath && attr1->community == attr2->community && attr1->med == attr2->med - && attr1->local_pref == attr2->local_pref) + && attr1->local_pref == attr2->local_pref + && attr1->pathlimit.ttl == attr2->pathlimit.ttl + && attr1->pathlimit.as == attr2->pathlimit.as) { struct attr_extra *ae1 = attr1->extra; struct attr_extra *ae2 = attr2->extra; @@ -676,6 +685,42 @@ bgp_attr_flush (struct attr *attr) } } +/* Parse AS_PATHLIMIT attribute in an UPDATE */ +static int +bgp_attr_aspathlimit (struct peer *peer, bgp_size_t length, + struct attr *attr, u_char flag, u_char *startp) +{ + bgp_size_t total; + + total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + + if (flag != (BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL)) + { + zlog (peer->log, LOG_ERR, + "AS-Pathlimit attribute flag isn't transitive %d", flag); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + return -1; + } + + if (length != 5) + { + zlog (peer->log, LOG_ERR, + "AS-Pathlimit length, %u, is not 5", length); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + return -1; + } + + attr->pathlimit.ttl = stream_getc (BGP_INPUT(peer)); + attr->pathlimit.as = stream_getl (BGP_INPUT(peer)); + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT); + return 0; +} /* Get origin attribute of the update message. */ static int bgp_attr_origin (struct peer *peer, bgp_size_t length, @@ -1290,7 +1335,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, { /* XXX warning: long int format, int arg (arg 5) */ zlog (peer->log, LOG_WARNING, - "%s error BGP attribute length %ld is smaller than min len", + "%s error BGP attribute length %lu is smaller than min len", peer->host, endp - STREAM_PNT (BGP_INPUT (peer))); bgp_notify_send (peer, @@ -1386,6 +1431,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, case BGP_ATTR_EXT_COMMUNITIES: ret = bgp_attr_ext_communities (peer, length, attr, flag); break; + case BGP_ATTR_AS_PATHLIMIT: + ret = bgp_attr_aspathlimit (peer, length, attr, flag, startp); + break; default: ret = bgp_attr_unknown (peer, attr, flag, type, length, startp); break; @@ -1824,7 +1872,25 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, } } } - + + /* AS-Pathlimit */ + if (attr->pathlimit.ttl) + { + u_int32_t as = attr->pathlimit.as; + + /* should already have been done in announce_check(), + * but just in case.. + */ + if (!as) + as = peer->local_as; + + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_AS_PATHLIMIT); + stream_putc (s, 5); + stream_putc (s, attr->pathlimit.ttl); + stream_putl (s, as); + } + /* Unknown transit attribute. */ if (attr->extra && attr->extra->transit) stream_put (s, attr->extra->transit->val, attr->extra->transit->length); @@ -2034,6 +2100,16 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, } #endif /* HAVE_IPV6 */ + /* AS-Pathlimit */ + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT)) + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_AS_PATHLIMIT); + stream_putc (s, 5); + stream_putc (s, attr->pathlimit.ttl); + stream_putl (s, attr->pathlimit.as); + } + /* Return total size of attribute. */ len = stream_get_endp (s) - cp - 2; stream_putw_at (s, cp, len); |