diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2008-10-27 00:20:22 +0100 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2008-10-27 00:20:22 +0100 |
commit | a98fbf0f12b5e83e25afa0f585ca6a4d4ac5f6bf (patch) | |
tree | f6c215cd05ec9278696fae7b8814b5071a4b3c6a /nest | |
parent | a3b70dc499b64f41aa776b5b4afee5c7bfb8dfa6 (diff) | |
parent | 1567edea8d3da7da08092eef15bb3bd4544c6464 (diff) |
Merge branch 'dev' into out
Diffstat (limited to 'nest')
-rw-r--r-- | nest/a-path.c | 223 | ||||
-rw-r--r-- | nest/a-set.c | 8 | ||||
-rw-r--r-- | nest/attrs.h | 25 |
3 files changed, 214 insertions, 42 deletions
diff --git a/nest/a-path.c b/nest/a-path.c index 1b08f809..5e3ecfd4 100644 --- a/nest/a-path.c +++ b/nest/a-path.c @@ -14,38 +14,139 @@ #include "lib/unaligned.h" #include "lib/string.h" + +/* Global AS4 support, shared by all BGP instances. + * This specifies whether BA_AS_PATH attributes contain 2 or 4 B per ASN + */ + +int bgp_as4_support = 1; + +static void +put_as(byte *data, u32 as) +{ + if (bgp_as4_support) + put_u32(data, as); + else if (as <= 0xFFFF) + put_u16(data, as); + else + bug("put_as: Try to put 32bit AS to 16bit AS Path"); +} + +static inline u32 +get_as(byte *data) +{ + return bgp_as4_support ? get_u32(data) : get_u16(data); +} + struct adata * -as_path_prepend(struct linpool *pool, struct adata *olda, int as) +as_path_prepend(struct linpool *pool, struct adata *olda, u32 as) { + int bs = bgp_as4_support ? 4 : 2; struct adata *newa; - if (olda->length && olda->data[0] == AS_PATH_SEQUENCE && - olda->data[1] < 255) /* Starting with sequence => just prepend the AS number */ + if (olda->length && olda->data[0] == AS_PATH_SEQUENCE && olda->data[1] < 255) + /* Starting with sequence => just prepend the AS number */ { - newa = lp_alloc(pool, sizeof(struct adata) + olda->length + 2); - newa->length = olda->length + 2; - newa->data[0] = 2; + int nl = olda->length + bs; + newa = lp_alloc(pool, sizeof(struct adata) + nl); + newa->length = nl; + newa->data[0] = AS_PATH_SEQUENCE; newa->data[1] = olda->data[1] + 1; - memcpy(newa->data+4, olda->data+2, olda->length-2); + memcpy(newa->data + bs + 2, olda->data + 2, olda->length - 2); } - else /* Create new path segment */ + else /* Create new path segment */ { - newa = lp_alloc(pool, sizeof(struct adata) + olda->length + 4); - newa->length = olda->length + 4; - newa->data[0] = 2; + int nl = olda->length + bs + 2; + newa = lp_alloc(pool, sizeof(struct adata) + nl); + newa->length = nl; + newa->data[0] = AS_PATH_SEQUENCE; newa->data[1] = 1; - memcpy(newa->data+4, olda->data, olda->length); + memcpy(newa->data + bs + 2, olda->data, olda->length); } - put_u16(newa->data+2, as); + put_as(newa->data + 2, as); return newa; } +int +as_path_convert_to_old(struct adata *path, byte *dst, int *new_used) +{ + byte *src = path->data; + byte *src_end = src + path->length; + byte *dst_start = dst; + u32 as; + int i, n; + *new_used = 0; + + while (src < src_end) + { + n = src[1]; + *dst++ = *src++; + *dst++ = *src++; + + for(i=0; i<n; i++) + { + as = get_u32(src); + if (as > 0xFFFF) + { + as = AS_TRANS; + *new_used = 1; + } + put_u16(dst, as); + src += 4; + dst += 2; + } + } + + return dst - dst_start; +} + +int +as_path_convert_to_new(struct adata *path, byte *dst, int req_as) +{ + byte *src = path->data; + byte *src_end = src + path->length; + byte *dst_start = dst; + u32 as; + int i, t, n; + + + while ((src < src_end) && (req_as > 0)) + { + t = *src++; + n = *src++; + + if (t == AS_PATH_SEQUENCE) + { + if (n > req_as) + n = req_as; + + req_as -= n; + } + else // t == AS_PATH_SET + req_as--; + + *dst++ = t; + *dst++ = n; + + for(i=0; i<n; i++) + { + as = get_u16(src); + put_u32(dst, as); + src += 2; + dst += 4; + } + } + + return dst - dst_start; +} + void as_path_format(struct adata *path, byte *buf, unsigned int size) { + int bs = bgp_as4_support ? 4 : 2; byte *p = path->data; byte *e = p + path->length; - byte *end = buf + size - 8; + byte *end = buf + size - 16; int sp = 1; int l, isset; @@ -69,8 +170,8 @@ as_path_format(struct adata *path, byte *buf, unsigned int size) { if (!sp) *buf++ = ' '; - buf += bsprintf(buf, "%d", get_u16(p)); - p += 2; + buf += bsprintf(buf, "%u", get_as(p)); + p += bs; sp = 0; } if (isset) @@ -86,6 +187,7 @@ as_path_format(struct adata *path, byte *buf, unsigned int size) int as_path_getlen(struct adata *path) { + int bs = bgp_as4_support ? 4 : 2; int res = 0; u8 *p = path->data; u8 *q = p+path->length; @@ -95,8 +197,8 @@ as_path_getlen(struct adata *path) { switch (*p++) { - case AS_PATH_SET: len = *p++; res++; p += 2*len; break; - case AS_PATH_SEQUENCE: len = *p++; res+=len; p += 2*len; break; + case AS_PATH_SET: len = *p++; res++; p += bs * len; break; + case AS_PATH_SEQUENCE: len = *p++; res += len; p += bs * len; break; default: bug("as_path_getlen: Invalid path segment"); } } @@ -104,9 +206,11 @@ as_path_getlen(struct adata *path) } int -as_path_get_first(struct adata *path) +as_path_get_first(struct adata *path, u32 *orig_as) { - int res = -1; + int bs = bgp_as4_support ? 4 : 2; + int found = 0; + u32 res = 0; u8 *p = path->data; u8 *q = p+path->length; int len; @@ -117,36 +221,84 @@ as_path_get_first(struct adata *path) { case AS_PATH_SET: if (len = *p++) - res = get_u16(p); - p += 2*len; + { + found = 1; + res = get_as(p); + p += bs * len; + } break; case AS_PATH_SEQUENCE: if (len = *p++) - res = get_u16(p+2*(len-1)); - p += 2*len; + { + found = 1; + res = get_as(p + bs * (len - 1)); + p += bs * len; + } break; default: bug("as_path_get_first: Invalid path segment"); } } - return res; + + *orig_as = res; + return found; +} + +int +as_path_get_last(struct adata *path, u32 *last_as) +{ + u8 *p = path->data; + + if ((path->length == 0) || (p[0] != AS_PATH_SEQUENCE) || (p[1] == 0)) + return 0; + else + { + *last_as = get_as(p+2); + return 1; + } } +int +as_path_is_member(struct adata *path, u32 as) +{ + int bs = bgp_as4_support ? 4 : 2; + u8 *p = path->data; + u8 *q = p+path->length; + int i, n; + + while (p<q) + { + n = p[1]; + p += 2; + for(i=0; i<n; i++) + { + if (get_as(p) == as) + return 1; + p += bs; + } + } + return 0; +} + + + #define MASK_PLUS do { mask = mask->next; if (!mask) return next == q; \ - asterisk = (mask->val == PM_ANY); \ + asterisk = mask->any; \ if (asterisk) { mask = mask->next; if (!mask) { return 1; } } \ } while(0) int as_path_match(struct adata *path, struct f_path_mask *mask) { + int bs = bgp_as4_support ? 4 : 2; int i; int asterisk = 0; u8 *p = path->data; u8 *q = p+path->length; int len; u8 *next; + u32 as; - asterisk = (mask->val == PM_ANY); + asterisk = mask->any; if (asterisk) { mask = mask->next; if (!mask) return 1; } @@ -156,20 +308,21 @@ as_path_match(struct adata *path, struct f_path_mask *mask) len = *p++; { u8 *p_save = p; - next = p_save + 2*len; + next = p_save + bs * len; retry: p = p_save; for (i=0; i<len; i++) { - if (asterisk && (get_u16(p) == mask->val)) { + as = get_as(p); + if (asterisk && (as == mask->val)) { MASK_PLUS; goto retry; } - if (!asterisk && (get_u16(p) == mask->val)) { + if (!asterisk && (as == mask->val)) { p = next; MASK_PLUS; goto okay; } - p+=2; + p += bs; } if (!asterisk) return 0; @@ -180,15 +333,15 @@ as_path_match(struct adata *path, struct f_path_mask *mask) case AS_PATH_SEQUENCE: len = *p++; for (i=0; i<len; i++) { - next = p+2; - if (asterisk && (get_u16(p) == mask->val)) + as = get_as(p); + if (asterisk && (as == mask->val)) MASK_PLUS; else if (!asterisk) { - if (get_u16(p) != mask->val) + if (as != mask->val) return 0; MASK_PLUS; } - p+=2; + p += bs; } break; diff --git a/nest/a-set.c b/nest/a-set.c index 44407141..69c090b7 100644 --- a/nest/a-set.c +++ b/nest/a-set.c @@ -40,10 +40,12 @@ int_set_format(struct adata *set, byte *buf, unsigned int size) struct adata * int_set_add(struct linpool *pool, struct adata *list, u32 val) { - struct adata *res = lp_alloc(pool, list->length + sizeof(struct adata) + 4); - res->length = list->length+4; + int len = list ? list->length : 0; + struct adata *res = lp_alloc(pool, len + sizeof(struct adata) + 4); + res->length = len + 4; * (u32 *) res->data = val; - memcpy((char *) res->data + 4, list->data, list->length); + if (list) + memcpy((char *) res->data + 4, list->data, list->length); return res; } diff --git a/nest/attrs.h b/nest/attrs.h index abd6b9e9..fee2c2c8 100644 --- a/nest/attrs.h +++ b/nest/attrs.h @@ -14,16 +14,30 @@ #define AS_PATH_SET 1 /* Types of path segments */ #define AS_PATH_SEQUENCE 2 -struct adata *as_path_prepend(struct linpool *pool, struct adata *olda, int as); +#define AS_PATH_MAXLEN 10000 + +#define AS_TRANS 23456 +/* AS_TRANS is used when we need to store 32bit ASN larger than 0xFFFF + * to 16bit slot (like in 16bit AS_PATH). See RFC 4893 for details + */ + +struct adata *as_path_prepend(struct linpool *pool, struct adata *olda, u32 as); +int as_path_convert_to_old(struct adata *path, byte *dst, int *new_used); +int as_path_convert_to_new(struct adata *path, byte *dst, int req_as); void as_path_format(struct adata *path, byte *buf, unsigned int size); int as_path_getlen(struct adata *path); -int as_path_get_first(struct adata *path); +int as_path_get_first(struct adata *path, u32 *orig_as); +int as_path_get_last(struct adata *path, u32 *last_as); +int as_path_is_member(struct adata *path, u32 as); + struct f_path_mask { struct f_path_mask *next; - int val; + u32 val; + int any; }; -#define PM_ANY -1 + +// #define PM_ANY -1 int as_path_match(struct adata *path, struct f_path_mask *mask); @@ -34,4 +48,7 @@ struct adata *int_set_add(struct linpool *pool, struct adata *list, u32 val); int int_set_contains(struct adata *list, u32 val); struct adata *int_set_del(struct linpool *pool, struct adata *list, u32 val); +static inline int int_set_get_size(struct adata *list) +{ return list->length / 4; } + #endif |