From 42a0c05408c4151442e6a0ec1c6889acbcfe9c17 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Fri, 12 Aug 2011 21:03:43 +0200 Subject: BGP Extended communities. --- nest/a-set.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 163 insertions(+), 14 deletions(-) (limited to 'nest/a-set.c') diff --git a/nest/a-set.c b/nest/a-set.c index 3cbd635..020d097 100644 --- a/nest/a-set.c +++ b/nest/a-set.c @@ -36,10 +36,11 @@ int_set_format(struct adata *set, int way, int from, byte *buf, unsigned int siz { u32 *z = (u32 *) set->data; byte *end = buf + size - 24; + int from2 = MAX(from, 0); int to = set->length / 4; int i; - for (i = MAX(from, 0); i < to; i++) + for (i = from2; i < to; i++) { if (buf > end) { @@ -50,7 +51,7 @@ int_set_format(struct adata *set, int way, int from, byte *buf, unsigned int siz return i; } - if (i > from) + if (i > from2) *buf++ = ' '; if (way) @@ -62,6 +63,84 @@ int_set_format(struct adata *set, int way, int from, byte *buf, unsigned int siz return 0; } +int +ec_format(byte *buf, u64 ec) +{ + u32 type, key, val; + char tbuf[16], *kind; + + type = ec >> 48; + switch (type & 0xf0ff) + { + case EC_RT: kind = "rt"; break; + case EC_RO: kind = "ro"; break; + + default: + kind = tbuf; + bsprintf(kind, "unknown 0x%x", type); + } + + switch (ec >> 56) + { + /* RFC 4360 3.1. Two-Octet AS Specific Extended Community */ + case 0x00: + case 0x40: + key = (ec >> 32) & 0xFFFF; + val = ec; + return bsprintf(buf, "(%s, %u, %u)", kind, key, val); + + /* RFC 4360 3.2. IPv4 Address Specific Extended Community */ + case 0x01: + case 0x41: + key = ec >> 16; + val = ec & 0xFFFF; + return bsprintf(buf, "(%s, %R, %u)", kind, key, val); + + /* RFC 5668 4-Octet AS Specific BGP Extended Community */ + case 0x02: + case 0x42: + key = ec >> 16; + val = ec & 0xFFFF; + return bsprintf(buf, "(%s, %u, %u)", kind, key, val); + + /* Generic format for unknown kinds of extended communities */ + default: + key = ec >> 32; + val = ec; + return bsprintf(buf, "(generic, 0x%x, 0x%x)", key, val); + } + +} + +int +ec_set_format(struct adata *set, int from, byte *buf, unsigned int size) +{ + u32 *z = int_set_get_data(set); + byte *end = buf + size - 24; + int from2 = MAX(from, 0); + int to = int_set_get_size(set); + int i; + + for (i = from2; i < to; i += 2) + { + if (buf > end) + { + if (from < 0) + strcpy(buf, " ..."); + else + *buf = 0; + return i; + } + + if (i > from2) + *buf++ = ' '; + + buf += ec_format(buf, ec_get(z, i)); + } + *buf = 0; + return 0; +} + int int_set_contains(struct adata *list, u32 val) { @@ -69,10 +148,32 @@ int_set_contains(struct adata *list, u32 val) return 0; u32 *l = (u32 *) list->data; - unsigned int i; - for (i=0; ilength/4; i++) + int len = int_set_get_size(list); + int i; + + for (i = 0; i < len; i++) if (*l++ == val) return 1; + + return 0; +} + +int +ec_set_contains(struct adata *list, u64 val) +{ + if (!list) + return 0; + + u32 *l = int_set_get_data(list); + int len = int_set_get_size(list); + u32 eh = ec_hi(val); + u32 el = ec_lo(val); + int i; + + for (i=0; i < len; i += 2) + if (l[i] == eh && l[i+1] == el) + return 1; + return 0; } @@ -86,7 +187,7 @@ int_set_add(struct linpool *pool, struct adata *list, u32 val) return list; len = list ? list->length : 0; - res = lp_alloc(pool, len + sizeof(struct adata) + 4); + res = lp_alloc(pool, sizeof(struct adata) + len + 4); res->length = len + 4; * (u32 *) res->data = val; if (list) @@ -95,23 +196,71 @@ int_set_add(struct linpool *pool, struct adata *list, u32 val) } struct adata * -int_set_del(struct linpool *pool, struct adata *list, u32 val) +ec_set_add(struct linpool *pool, struct adata *list, u64 val) { - struct adata *res; - u32 *l, *k; - unsigned int i; + if (ec_set_contains(list, val)) + return list; + + int olen = list ? list->length : 0; + struct adata *res = lp_alloc(pool, sizeof(struct adata) + olen + 8); + res->length = olen + 8; + + if (list) + memcpy(res->data, list->data, list->length); + + u32 *l = (u32 *) (res->data + res->length - 8); + l[0] = ec_hi(val); + l[1] = ec_lo(val); + + return res; +} + +struct adata * +int_set_del(struct linpool *pool, struct adata *list, u32 val) +{ if (!int_set_contains(list, val)) return list; - res = lp_alloc(pool, list->length + sizeof(struct adata) - 4); - res->length = list->length-4; + struct adata *res; + res = lp_alloc(pool, sizeof(struct adata) + list->length - 4); + res->length = list->length - 4; + + u32 *l = int_set_get_data(list); + u32 *k = int_set_get_data(res); + int len = int_set_get_size(list); + int i; - l = (u32 *) list->data; - k = (u32 *) res->data; - for (i=0; ilength/4; i++) + for (i = 0; i < len; i++) if (l[i] != val) *k++ = l[i]; return res; } + +struct adata * +ec_set_del(struct linpool *pool, struct adata *list, u64 val) +{ + if (!ec_set_contains(list, val)) + return list; + + struct adata *res; + res = lp_alloc(pool, sizeof(struct adata) + list->length - 8); + res->length = list->length - 8; + + u32 *l = int_set_get_data(list); + u32 *k = int_set_get_data(res); + int len = int_set_get_size(list); + u32 eh = ec_hi(val); + u32 el = ec_lo(val); + int i; + + for (i=0; i < len; i += 2) + if (! (l[i] == eh && l[i+1] == el)) + { + *k++ = l[i]; + *k++ = l[i+1]; + } + + return res; +} -- cgit v1.2.3