summaryrefslogtreecommitdiff
path: root/bgpd/bgp_attr.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_attr.c')
-rw-r--r--bgpd/bgp_attr.c82
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);