diff options
author | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2016-12-07 14:11:28 +0100 |
---|---|---|
committer | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2016-12-07 14:20:52 +0100 |
commit | d15b0b0a1b494c14b139d2d28706d82cd6e2f139 (patch) | |
tree | f704869689e1acab9a4f3417849ac5853188310d /nest | |
parent | 5df4073c81942ea119de90a81431bae71c87157b (diff) |
BGP redesign
Integrated and extensible BGP with generalized AFI handling,
support for IPv4+IPv6 AFI and unicast+multicast SAFI.
Diffstat (limited to 'nest')
-rw-r--r-- | nest/a-path.c | 434 | ||||
-rw-r--r-- | nest/a-set.c | 84 | ||||
-rw-r--r-- | nest/attrs.h | 76 | ||||
-rw-r--r-- | nest/cmds.c | 1 | ||||
-rw-r--r-- | nest/proto.c | 10 | ||||
-rw-r--r-- | nest/protocol.h | 12 | ||||
-rw-r--r-- | nest/route.h | 17 | ||||
-rw-r--r-- | nest/rt-attr.c | 2 | ||||
-rw-r--r-- | nest/rt-table.c | 4 |
9 files changed, 498 insertions, 142 deletions
diff --git a/nest/a-path.c b/nest/a-path.c index 158cc93b..6ced703d 100644 --- a/nest/a-path.c +++ b/nest/a-path.c @@ -22,112 +22,313 @@ #define get_as get_u32 #define BS 4 /* Default block size of ASN (autonomous system number) */ -struct adata * -as_path_prepend(struct linpool *pool, struct adata *olda, u32 as) +#define BAD(DSC, VAL) ({ err_dsc = DSC; err_val = VAL; goto bad; }) + +int +as_path_valid(byte *data, uint len, int bs, char *err, uint elen) { - struct adata *newa; + byte *pos = data; + char *err_dsc = NULL; + uint err_val = 0; + + while (len) + { + if (len < 2) + BAD("segment framing error", 0); + + /* Process one AS path segment */ + uint type = pos[0]; + uint slen = 2 + bs * pos[1]; + + if (len < slen) + BAD("segment framing error", len); + + /* XXXX handle CONFED segments */ + if ((type != AS_PATH_SET) && (type != AS_PATH_SEQUENCE)) + BAD("unknown segment", type); + + if (pos[1] == 0) + BAD("zero-length segment", type); - if (olda->length && olda->data[0] == AS_PATH_SEQUENCE && olda->data[1] < 255) - /* Starting with sequence => just prepend the AS number */ + pos += slen; + len -= slen; + } + + return 1; + +bad: + if (err) + if (bsnprintf(err, elen, "%s (%u) at %d", err_dsc, err_val, (int) (pos - data)) < 0) + err[0] = 0; + + return 0; +} + +int +as_path_16to32(byte *dst, byte *src, uint len) +{ + byte *dst0 = dst; + byte *end = src + len; + uint i, n; + + while (src < end) + { + n = src[1]; + *dst++ = *src++; + *dst++ = *src++; + + for (i = 0; i < n; i++) { - 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 + BS + 2, olda->data + 2, olda->length - 2); + put_u32(dst, get_u16(src)); + src += 2; + dst += 4; } - else /* Create new path segment */ + } + + return dst - dst0; +} + +int +as_path_32to16(byte *dst, byte *src, uint len) +{ + byte *dst0 = dst; + byte *end = src + len; + uint i, n; + + while (src < end) + { + n = src[1]; + *dst++ = *src++; + *dst++ = *src++; + + for (i = 0; i < n; i++) { - 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 + BS + 2, olda->data, olda->length); + put_u16(dst, get_u32(src)); + src += 4; + dst += 2; } - put_as(newa->data + 2, as); - return newa; + } + + return dst - dst0; } int -as_path_convert_to_old(struct adata *path, byte *dst, int *new_used) +as_path_contains_as4(const struct adata *path) { - byte *src = path->data; - byte *src_end = src + path->length; - byte *dst_start = dst; - u32 as; - int i, n; - *new_used = 0; + const byte *pos = path->data; + const byte *end = pos + path->length; + uint i, n; + + while (pos < end) + { + n = pos[1]; + pos += 2; - while (src < src_end) + for (i = 0; i < n; i++) { - n = src[1]; - *dst++ = *src++; - *dst++ = *src++; + if (get_as(pos) > 0xFFFF) + return 1; - 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; - } + pos += BS; } + } - return dst - dst_start; + return 0; } int -as_path_convert_to_new(struct adata *path, byte *dst, int req_as) +as_path_contains_confed(const struct adata *path) +{ + const byte *pos = path->data; + const byte *end = pos + path->length; + + while (pos < end) + { + uint type = pos[0]; + uint slen = 2 + BS * pos[1]; + + if ((type == AS_PATH_CONFED_SEQUENCE) || + (type == AS_PATH_CONFED_SET)) + return 1; + + pos += slen; + } + + return 0; +} + +static void +as_path_strip_confed_(byte *dst, const byte *src, uint len) +{ + const byte *end = src + len; + + while (src < end) + { + uint type = src[0]; + uint slen = 2 + BS * src[1]; + + /* Copy regular segments */ + if ((type == AS_PATH_SET) || (type == AS_PATH_SEQUENCE)) + { + memcpy(dst, src, slen); + dst += slen; + } + + src += slen; + } +} + +struct adata * +as_path_strip_confed(struct linpool *pool, const struct adata *op) +{ + struct adata *np = lp_alloc_adata(pool, op->length); + as_path_strip_confed_(np->data, op->data, op->length); + return np; +} + +struct adata * +as_path_prepend2(struct linpool *pool, const struct adata *op, int seq, u32 as, int strip) { - byte *src = path->data; - byte *src_end = src + path->length; - byte *dst_start = dst; + struct adata *np; + const byte *pos = op->data; + uint len = op->length; + + if (len && (pos[0] == seq) && (pos[1] < 255)) + { + /* Starting with matching segment => just prepend the AS number */ + np = lp_alloc_adata(pool, len + BS); + np->data[0] = seq; + np->data[1] = pos[1] + 1; + put_as(np->data + 2, as); + + uint dlen = BS * pos[1]; + memcpy(np->data + 2 + BS, pos + 2, dlen); + ADVANCE(pos, len, 2 + dlen); + } + else + { + /* Create a new path segment */ + np = lp_alloc_adata(pool, len + 2 + BS); + np->data[0] = seq; + np->data[1] = 1; + put_as(np->data + 2, as); + } + + if (len) + { + byte *dst = np->data + 2 + BS * np->data[1]; + + if (strip) + as_path_strip_confed_(dst, pos, len); + else + memcpy(dst, pos, len); + } + + return np; +} + + +struct adata * +as_path_to_old(struct linpool *pool, const struct adata *path) +{ + struct adata *res = lp_alloc_adata(pool, path->length); + byte *pos = res->data; + byte *end = pos + res->length; + uint i, n; u32 as; - int i, t, n; + /* Copy the whole path */ + memcpy(res->data, path->data, path->length); + + /* Replace 32-bit AS numbers with AS_TRANS */ + while (pos < end) + { + n = pos[1]; + pos += 2; - while ((src < src_end) && (req_as > 0)) + for (i = 0; i < n; i++) { - t = *src++; - n = *src++; + as = get_as(pos); + if (as > 0xFFFF) + put_as(pos, AS_TRANS); - if (t == AS_PATH_SEQUENCE) - { - if (n > req_as) - n = req_as; + pos += BS; + } + } - req_as -= n; - } - else // t == AS_PATH_SET - req_as--; + return res; +} - *dst++ = t; - *dst++ = n; +/* + * Cut the path to the length @num, measured to the usual path metric. Note that + * AS_CONFED_* segments have zero length and must be added if they are on edge. + * In contrast to other as_path_* functions, @path is modified in place. + */ +void +as_path_cut(struct adata *path, uint num) +{ + byte *pos = path->data; + byte *end = pos + path->length; - for(i=0; i<n; i++) - { - as = get_u16(src); - put_u32(dst, as); - src += 2; - dst += 4; - } + while (pos < end) + { + uint t = pos[0]; + uint l = pos[1]; + uint n = 0; + + switch (t) + { + case AS_PATH_SET: n = 1; break; + case AS_PATH_SEQUENCE: n = l; break; + case AS_PATH_CONFED_SEQUENCE: n = 0; break; + case AS_PATH_CONFED_SET: n = 0; break; + default: bug("as_path_cut: Invalid path segment"); + } + + /* Cannot add whole segment, so try partial one and finish */ + if (num < n) + { + if (num) + { + pos[1] = num; + pos += 2 + BS * num; + } + + break; } - return dst - dst_start; + num -= n; + pos += 2 + BS * l; + } + + path->length = pos - path->data; +} + +/* + * Merge (concatenate) paths @p1 and @p2 and return the result. + * In contrast to other as_path_* functions, @p1 and @p2 may be reused. + */ +struct adata * +as_path_merge(struct linpool *pool, struct adata *p1, struct adata *p2) +{ + if (p1->length == 0) + return p2; + + if (p2->length == 0) + return p1; + + struct adata *res = lp_alloc_adata(pool, p1->length + p2->length); + memcpy(res->data, p1->data, p1->length); + memcpy(res->data + p1->length, p2->data, p2->length); + + return res; } void -as_path_format(struct adata *path, byte *buf, uint size) +as_path_format(const struct adata *path, byte *buf, uint size) { - byte *p = path->data; - byte *e = p + path->length; + const byte *p = path->data; + const byte *e = p + path->length; byte *end = buf + size - 16; int sp = 1; int l, isset; @@ -167,38 +368,41 @@ as_path_format(struct adata *path, byte *buf, uint size) } int -as_path_getlen(struct adata *path) +as_path_getlen(const struct adata *path) { - return as_path_getlen_int(path, BS); -} + const byte *pos = path->data; + const byte *end = pos + path->length; + uint res = 0; -int -as_path_getlen_int(struct adata *path, int bs) -{ - int res = 0; - u8 *p = path->data; - u8 *q = p+path->length; - int len; + while (pos < end) + { + uint t = pos[0]; + uint l = pos[1]; + uint n = 0; - while (p<q) + switch (t) { - switch (*p++) - { - 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"); - } + case AS_PATH_SET: n = 1; break; + case AS_PATH_SEQUENCE: n = l; break; + case AS_PATH_CONFED_SEQUENCE: n = 0; break; + case AS_PATH_CONFED_SET: n = 0; break; + default: bug("as_path_getlen: Invalid path segment"); } + + res += n; + pos += 2 + BS * l; + } + return res; } int -as_path_get_last(struct adata *path, u32 *orig_as) +as_path_get_last(const struct adata *path, u32 *orig_as) { int found = 0; u32 res = 0; - u8 *p = path->data; - u8 *q = p+path->length; + const u8 *p = path->data; + const u8 *q = p+path->length; int len; while (p<q) @@ -230,10 +434,10 @@ as_path_get_last(struct adata *path, u32 *orig_as) } u32 -as_path_get_last_nonaggregated(struct adata *path) +as_path_get_last_nonaggregated(const struct adata *path) { - u8 *p = path->data; - u8 *q = p+path->length; + const u8 *p = path->data; + const u8 *q = p+path->length; u32 res = 0; int len; @@ -257,11 +461,10 @@ as_path_get_last_nonaggregated(struct adata *path) return res; } - int -as_path_get_first(struct adata *path, u32 *last_as) +as_path_get_first(const struct adata *path, u32 *last_as) { - u8 *p = path->data; + const u8 *p = path->data; if ((path->length == 0) || (p[0] != AS_PATH_SEQUENCE) || (p[1] == 0)) return 0; @@ -273,10 +476,10 @@ as_path_get_first(struct adata *path, u32 *last_as) } int -as_path_contains(struct adata *path, u32 as, int min) +as_path_contains(const struct adata *path, u32 as, int min) { - u8 *p = path->data; - u8 *q = p+path->length; + const u8 *p = path->data; + const u8 *q = p+path->length; int num = 0; int i, n; @@ -296,10 +499,10 @@ as_path_contains(struct adata *path, u32 as, int min) } int -as_path_match_set(struct adata *path, struct f_tree *set) +as_path_match_set(const struct adata *path, struct f_tree *set) { - u8 *p = path->data; - u8 *q = p+path->length; + const u8 *p = path->data; + const u8 *q = p+path->length; int i, n; while (p<q) @@ -325,8 +528,8 @@ as_path_filter(struct linpool *pool, struct adata *path, struct f_tree *set, u32 return NULL; int len = path->length; - u8 *p = path->data; - u8 *q = path->data + len; + const u8 *p = path->data; + const u8 *q = path->data + len; u8 *d, *d2; int i, bt, sn, dn; u8 buf[len]; @@ -388,16 +591,16 @@ struct pm_pos u8 mark; union { - char *sp; + const char *sp; u32 asn; } val; }; static int -parse_path(struct adata *path, struct pm_pos *pos) +parse_path(const struct adata *path, struct pm_pos *pos) { - u8 *p = path->data; - u8 *q = p + path->length; + const u8 *p = path->data; + const u8 *q = p + path->length; struct pm_pos *opos = pos; int i, len; @@ -429,11 +632,10 @@ parse_path(struct adata *path, struct pm_pos *pos) default: bug("as_path_match: Invalid path component"); } - + return pos - opos; } - static int pm_match(struct pm_pos *pos, u32 asn, u32 asn2) { @@ -441,7 +643,7 @@ pm_match(struct pm_pos *pos, u32 asn, u32 asn2) if (! pos->set) return ((pos->val.asn >= asn) && (pos->val.asn <= asn2)); - u8 *p = pos->val.sp; + const u8 *p = pos->val.sp; int len = *p++; int i; @@ -463,7 +665,7 @@ pm_mark(struct pm_pos *pos, int i, int plen, int *nl, int *nh) if (pos[i].set) pos[i].mark = 1; - + for (j = i + 1; (j < plen) && pos[j].set && (! pos[j].mark); j++) pos[j].mark = 1; pos[j].mark = 1; @@ -500,7 +702,7 @@ pm_mark(struct pm_pos *pos, int i, int plen, int *nl, int *nh) * is marked. */ int -as_path_match(struct adata *path, struct f_path_mask *mask) +as_path_match(const struct adata *path, struct f_path_mask *mask) { struct pm_pos pos[2048 + 1]; int plen = parse_path(path, pos); diff --git a/nest/a-set.c b/nest/a-set.c index bd244e2e..82bf8b0d 100644 --- a/nest/a-set.c +++ b/nest/a-set.c @@ -7,6 +7,8 @@ * Can be freely distributed and used under the terms of the GNU GPL. */ +#include <stdlib.h> + #include "nest/bird.h" #include "nest/route.h" #include "nest/attrs.h" @@ -455,3 +457,85 @@ lc_set_union(struct linpool *pool, struct adata *l1, struct adata *l2) memcpy(res->data + l1->length, tmp, len); return res; } + + +struct adata * +ec_set_del_nontrans(struct linpool *pool, struct adata *set) +{ + adata *res = lp_alloc_adata(pool, set->length); + u32 *src = int_set_get_data(set); + u32 *dst = int_set_get_data(res); + int len = int_set_get_size(set); + int i; + + /* Remove non-transitive communities (EC_TBIT set) */ + for (i = 0; i < len; i += 2) + { + if (src[i] & EC_TBIT) + continue; + + *dst++ = src[i]; + *dst++ = src[i+1]; + } + + res->length = ((byte *) dst) - res->data; + + return res; +} + +static int +int_set_cmp(const void *X, const void *Y) +{ + const u32 *x = X, *y = Y; + return (*x < *y) ? -1 : (*x > *y) ? 1 : 0; +} + +struct adata * +int_set_sort(struct linpool *pool, struct adata *src) +{ + struct adata *dst = lp_alloc_adata(pool, src->length); + memcpy(dst->data, src->data, src->length); + qsort(dst->data, dst->length / 4, 4, int_set_cmp); + return dst; +} + + +static int +ec_set_cmp(const void *X, const void *Y) +{ + u64 x = ec_get(X, 0); + u64 y = ec_get(Y, 0); + return (x < y) ? -1 : (x > y) ? 1 : 0; +} + +struct adata * +ec_set_sort(struct linpool *pool, struct adata *src) +{ + struct adata *dst = lp_alloc_adata(pool, src->length); + memcpy(dst->data, src->data, src->length); + qsort(dst->data, dst->length / 8, 8, ec_set_cmp); + return dst; +} + + +static int +lc_set_cmp(const void *X, const void *Y) +{ + const u32 *x = X, *y = Y; + if (x[0] != y[0]) + return (x[0] > y[0]) ? 1 : -1; + if (x[1] != y[1]) + return (x[1] > y[1]) ? 1 : -1; + if (x[2] != y[2]) + return (x[2] > y[2]) ? 1 : -1; + return 0; +} + +struct adata * +lc_set_sort(struct linpool *pool, struct adata *src) +{ + struct adata *dst = lp_alloc_adata(pool, src->length); + memcpy(dst->data, src->data, src->length); + qsort(dst->data, dst->length / LCOMM_LENGTH, LCOMM_LENGTH, lc_set_cmp); + return dst; +} diff --git a/nest/attrs.h b/nest/attrs.h index 548d71a9..810ff583 100644 --- a/nest/attrs.h +++ b/nest/attrs.h @@ -10,6 +10,9 @@ #define _BIRD_ATTRS_H_ #include <stdint.h> +#include "lib/unaligned.h" +#include "nest/route.h" + /* a-path.c */ @@ -27,19 +30,29 @@ struct f_tree; -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, uint size); -int as_path_getlen(struct adata *path); -int as_path_getlen_int(struct adata *path, int bs); -int as_path_get_first(struct adata *path, u32 *orig_as); -int as_path_get_last(struct adata *path, u32 *last_as); -u32 as_path_get_last_nonaggregated(struct adata *path); -int as_path_contains(struct adata *path, u32 as, int min); -int as_path_match_set(struct adata *path, struct f_tree *set); +int as_path_valid(byte *data, uint len, int bs, char *err, uint elen); +int as_path_16to32(byte *dst, byte *src, uint len); +int as_path_32to16(byte *dst, byte *src, uint len); +int as_path_contains_as4(const struct adata *path); +int as_path_contains_confed(const struct adata *path); +struct adata *as_path_strip_confed(struct linpool *pool, const struct adata *op); +struct adata *as_path_prepend2(struct linpool *pool, const struct adata *op, int seq, u32 as, int strip); +struct adata *as_path_to_old(struct linpool *pool, const struct adata *path); +void as_path_cut(struct adata *path, uint num); +struct adata *as_path_merge(struct linpool *pool, struct adata *p1, struct adata *p2); +void as_path_format(const struct adata *path, byte *buf, uint size); +int as_path_getlen(const struct adata *path); +int as_path_getlen_int(const struct adata *path, int bs); +int as_path_get_first(const struct adata *path, u32 *orig_as); +int as_path_get_last(const struct adata *path, u32 *last_as); +u32 as_path_get_last_nonaggregated(const struct adata *path); +int as_path_contains(const struct adata *path, u32 as, int min); +int as_path_match_set(const struct adata *path, struct f_tree *set); struct adata *as_path_filter(struct linpool *pool, struct adata *path, struct f_tree *set, u32 key, int pos); +static inline struct adata *as_path_prepend(struct linpool *pool, const struct adata *path, u32 as) +{ return as_path_prepend2(pool, path, AS_PATH_SEQUENCE, as, 0); } + #define PM_ASN 0 #define PM_QUESTION 1 @@ -54,7 +67,42 @@ struct f_path_mask { uintptr_t val2; }; -int as_path_match(struct adata *path, struct f_path_mask *mask); +int as_path_match(const struct adata *path, struct f_path_mask *mask); + + +/* Counterparts to appropriate as_path_* functions */ + +static inline int +aggregator_16to32(byte *dst, byte *src) +{ + put_u32(dst, get_u16(src)); + memcpy(dst+4, src+2, 4); + return 8; +} + +static inline int +aggregator_32to16(byte *dst, byte *src) +{ + put_u16(dst, get_u32(src)); + memcpy(dst+2, src+4, 4); + return 6; +} + +static inline int +aggregator_contains_as4(struct adata *a) +{ + return get_u32(a->data) > 0xFFFF; +} + +static inline struct adata * +aggregator_to_old(struct linpool *pool, struct adata *a) +{ + struct adata *d = lp_alloc_adata(pool, 8); + put_u32(d->data, 0xFFFF); + memcpy(d->data + 4, a->data + 4, 4); + return d; +} + /* a-set.c */ @@ -142,5 +190,9 @@ struct adata *int_set_union(struct linpool *pool, struct adata *l1, struct adata struct adata *ec_set_union(struct linpool *pool, struct adata *l1, struct adata *l2); struct adata *lc_set_union(struct linpool *pool, struct adata *l1, struct adata *l2); +struct adata *ec_set_del_nontrans(struct linpool *pool, struct adata *set); +struct adata *int_set_sort(struct linpool *pool, struct adata *src); +struct adata *ec_set_sort(struct linpool *pool, struct adata *src); +struct adata *lc_set_sort(struct linpool *pool, struct adata *src); #endif diff --git a/nest/cmds.c b/nest/cmds.c index 82fdca66..f0a14425 100644 --- a/nest/cmds.c +++ b/nest/cmds.c @@ -80,7 +80,6 @@ print_size(char *dsc, size_t val) extern pool *rt_table_pool; extern pool *rta_pool; -extern pool *proto_pool; void cmd_show_memory(void) diff --git a/nest/proto.c b/nest/proto.c index f2416748..bfbf80d8 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -39,7 +39,7 @@ static int graceful_restart_state; static u32 graceful_restart_locks; static char *p_states[] = { "DOWN", "START", "UP", "STOP" }; -static char *c_states[] UNUSED = { "DOWN", "START", "UP", "FLUSHING" }; +static char *c_states[] = { "DOWN", "START", "UP", "FLUSHING" }; extern struct protocol proto_unix_iface; @@ -304,6 +304,8 @@ channel_do_down(struct channel *c) memset(&c->stats, 0, sizeof(struct proto_stats)); + CALL(c->channel->cleanup, c); + /* Schedule protocol shutddown */ if (proto_is_done(c->proto)) ev_schedule(c->proto->event); @@ -514,7 +516,9 @@ channel_reconfigure(struct channel *c, struct channel_config *cf) channel_verify_limits(c); - CALL(c->channel->reconfigure, c, cf); + /* Execute channel-specific reconfigure hook */ + if (c->channel->reconfigure && !c->channel->reconfigure(c, cf)) + return 0; /* If the channel is not open, it has no routes and we cannot reload it anyways */ if (c->channel_state != CS_UP) @@ -797,7 +801,6 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config if ((nc->protocol != oc->protocol) || (nc->net_type != oc->net_type) || (nc->disabled != p->disabled)) - return 0; p->name = nc->name; @@ -1575,6 +1578,7 @@ void channel_show_info(struct channel *c) { cli_msg(-1006, " Channel %s", c->name); + cli_msg(-1006, " State: %s", c_states[c->channel_state]); cli_msg(-1006, " Table: %s", c->table->name); cli_msg(-1006, " Preference: %d", c->preference); cli_msg(-1006, " Input filter: %s", filter_name(c->in_filter)); diff --git a/nest/protocol.h b/nest/protocol.h index 4b7bfdf3..19414525 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -273,6 +273,7 @@ proto_get_router_id(struct proto_config *pc) /* Moved from route.h to avoid dependency conflicts */ static inline void rte_update(struct proto *p, net_addr *n, rte *new) { rte_update2(p->main_channel, n, new, p->main_source); } +extern pool *proto_pool; extern list proto_list; /* @@ -418,20 +419,22 @@ struct channel_class { uint channel_size; /* Size of channel data structure */ uint config_size; /* Size of channel config data structure */ - struct channel * (*init)(struct channel *, struct channel_config *); /* Create new instance */ + void (*init)(struct channel *, struct channel_config *); /* Create new instance */ int (*reconfigure)(struct channel *, struct channel_config *); /* Try to reconfigure instance, returns success */ int (*start)(struct channel *); /* Start the instance */ - int (*shutdown)(struct channel *); /* Stop the instance */ + void (*shutdown)(struct channel *); /* Stop the instance */ + void (*cleanup)(struct channel *); /* Channel finished flush */ void (*copy_config)(struct channel_config *, struct channel_config *); /* Copy config from given channel instance */ #if 0 + XXXX; void (*preconfig)(struct protocol *, struct config *); /* Just before configuring */ void (*postconfig)(struct proto_config *); /* After configuring each instance */ void (*dump)(struct proto *); /* Debugging dump */ void (*dump_attrs)(struct rte *); /* Dump protocol-dependent attributes */ - void (*cleanup)(struct proto *); /* Called after shutdown when protocol became hungry/down */ + void (*get_status)(struct proto *, byte *buf); /* Get instance status (for `show protocols' command) */ void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs); /* Get route information (for `show route' command) */ int (*get_attr)(struct eattr *, byte *buf, int buflen); /* ASCIIfy dynamic attribute (returns GA_*) */ @@ -440,6 +443,8 @@ struct channel_class { #endif }; +extern struct channel_class channel_bgp; + struct channel_config { node n; const char *name; @@ -484,6 +489,7 @@ struct channel { u8 merge_limit; /* Maximal number of nexthops for RA_MERGED */ u8 in_keep_filtered; /* Routes rejected in import filter are kept */ u8 disabled; + u8 stale; /* Used in reconfiguration */ u8 channel_state; u8 export_state; /* Route export state (ES_*, see below) */ diff --git a/nest/route.h b/nest/route.h index 5104d8f1..8a238860 100644 --- a/nest/route.h +++ b/nest/route.h @@ -457,13 +457,22 @@ typedef struct eattr { #define EAF_TYPE_UNDEF 0x1f /* `force undefined' entry */ #define EAF_EMBEDDED 0x01 /* Data stored in eattr.u.data (part of type spec) */ #define EAF_VAR_LENGTH 0x02 /* Attribute length is variable (part of type spec) */ -#define EAF_ORIGINATED 0x40 /* The attribute has originated locally */ +#define EAF_ORIGINATED 0x20 /* The attribute has originated locally */ +#define EAF_FRESH 0x40 /* An uncached attribute (e.g. modified in export filter) */ #define EAF_TEMP 0x80 /* A temporary attribute (the one stored in the tmp attr list) */ -struct adata { +typedef struct adata { uint length; /* Length of data */ byte data[0]; -}; +} adata; + +static inline struct adata * +lp_alloc_adata(struct linpool *pool, uint len) +{ + struct adata *ad = lp_alloc(pool, sizeof(struct adata) + len); + ad->length = len; + return ad; +} static inline int adata_same(struct adata *a, struct adata *b) { return (a->length == b->length && !memcmp(a->data, b->data, a->length)); } @@ -523,7 +532,7 @@ static inline rta * rta_cow(rta *r, linpool *lp) { return rta_is_cached(r) ? rta void rta_dump(rta *); void rta_dump_all(void); void rta_show(struct cli *, rta *, ea_list *); -void rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr *gw, ip_addr *ll); +void rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr gw, ip_addr ll); /* * rta_set_recursive_next_hop() acquires hostentry from hostcache and fills diff --git a/nest/rt-attr.c b/nest/rt-attr.c index e280bbd9..94f25de8 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -528,7 +528,7 @@ ea_do_prune(ea_list *e) if ((s0->type & EAF_TYPE_MASK) != EAF_TYPE_UNDEF) { *d = *s0; - d->type = (d->type & ~EAF_ORIGINATED) | (s[-1].type & EAF_ORIGINATED); + d->type = (d->type & ~(EAF_ORIGINATED|EAF_FRESH)) | (s[-1].type & EAF_ORIGINATED); d++; i++; } diff --git a/nest/rt-table.c b/nest/rt-table.c index 4260e493..ae56e50a 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -2426,9 +2426,9 @@ rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep) } void -rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr *gw, ip_addr *ll) +rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr gw, ip_addr ll) { - rta_apply_hostentry(a, rt_get_hostentry(tab, *gw, *ll, dep)); + rta_apply_hostentry(a, rt_get_hostentry(tab, gw, ipa_zero(ll) ? gw : ll, dep)); } |