[bgpd] Add support for AS_PATHLIMIT / draft-ietf-idr-as-pathlimit
2007-07-31 Paul Jakma <paul.jakma@sun.com>
* (general) Support for draft-ietf-idr-as-pathlimit-03.
* bgp_attr.h: (struct attr) Add pathlimit struct
bgp_attr.c: (attr_str) Add BGP_ATTR_AS_PATHLIMIT string.
(attrhash_key_make) tally pathlimit too
(attrhash_cmp) cmp pathlimit attr
(bgp_attr_aspathlimit) New, parse AS_PATHLIMIT attr.
(bgp_attr_parse) ditto
(bgp_packet_attribute) Write out AS_PATHLIMIT when set
(bgp_dump_routes_attr) ditto
* bgp_route.h: (struct bgp_static) Add TTL field
* bgp_route.c: (bgp_announce_check) Drop paths that are over
their hop-count TTL before sending via EBGP.
Mangle ASN in pathlimit for confeds/private as best we can.
(bgp_static_update_{rsclient,main}) Add any configure pathlimit
information.
(bgp_pathlimit_update_parents) New, update atomic-aggr setting for
parents of an aspathlimit'ed static.
(bgp_static_set) Add TTL argument, for all the 'bgp network'
commands.
Call previous for TTL changed statics.
(bgp_static_unset) Call pathlimit_update_parents.
(various bgp network commands) Add 'pathlimit <0-255>' qualifier
to all the various forms, bar route-map - which can set ttl
itself.
* bgp_routemap.c: (general) Add support for 'set pathlimit ttl' and
'match pathlimit as'.
* doc/bgpd.texi: Document 'network ... pathlimit <ttl>'
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 07c9413..23d9586 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -56,6 +56,8 @@
{ 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 @@
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 @@
&& 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 @@
}
}
+/* 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 @@
{
/* 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 @@
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 @@
}
}
}
-
+
+ /* 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 @@
}
#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);