diff options
Diffstat (limited to 'nest')
-rw-r--r-- | nest/a-path.c | 59 | ||||
-rw-r--r-- | nest/iface.h | 1 | ||||
-rw-r--r-- | nest/neighbor.c | 38 | ||||
-rw-r--r-- | nest/route.h | 1 | ||||
-rw-r--r-- | nest/rt-fib.c | 41 |
5 files changed, 84 insertions, 56 deletions
diff --git a/nest/a-path.c b/nest/a-path.c index c804619..396d463 100644 --- a/nest/a-path.c +++ b/nest/a-path.c @@ -16,53 +16,36 @@ #include "filter/filter.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 inline void put_as(byte *data, u32 as) { put_u32(data, as); } +// static inline u32 get_as(byte *data) { return get_u32(data); } -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); -} +#define put_as put_u32 +#define get_as get_u32 +#define BS 4 struct adata * 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 */ { - int nl = olda->length + bs; + 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); + memcpy(newa->data + BS + 2, olda->data + 2, olda->length - 2); } else /* Create new path segment */ { - int nl = olda->length + bs + 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 + bs + 2, olda->data, olda->length); + memcpy(newa->data + BS + 2, olda->data, olda->length); } put_as(newa->data + 2, as); return newa; @@ -144,7 +127,6 @@ 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 bs = bgp_as4_support ? 4 : 2; byte *p = path->data; byte *e = p + path->length; byte *end = buf + size - 16; @@ -172,7 +154,7 @@ as_path_format(struct adata *path, byte *buf, unsigned int size) if (!sp) *buf++ = ' '; buf += bsprintf(buf, "%u", get_as(p)); - p += bs; + p += BS; sp = 0; } if (isset) @@ -188,8 +170,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; - return as_path_getlen_int(path, bs); + return as_path_getlen_int(path, BS); } int @@ -215,7 +196,6 @@ as_path_getlen_int(struct adata *path, int bs) int as_path_get_last(struct adata *path, u32 *orig_as) { - int bs = bgp_as4_support ? 4 : 2; int found = 0; u32 res = 0; u8 *p = path->data; @@ -230,15 +210,15 @@ as_path_get_last(struct adata *path, u32 *orig_as) if (len = *p++) { found = 0; - p += bs * len; + p += BS * len; } break; case AS_PATH_SEQUENCE: if (len = *p++) { found = 1; - res = get_as(p + bs * (len - 1)); - p += bs * len; + res = get_as(p + BS * (len - 1)); + p += BS * len; } break; default: bug("as_path_get_first: Invalid path segment"); @@ -267,7 +247,6 @@ as_path_get_first(struct adata *path, u32 *last_as) 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; @@ -280,7 +259,7 @@ as_path_is_member(struct adata *path, u32 as) { if (get_as(p) == as) return 1; - p += bs; + p += BS; } } return 0; @@ -301,7 +280,6 @@ struct pm_pos static int parse_path(struct adata *path, struct pm_pos *pos) { - int bs = bgp_as4_support ? 4 : 2; u8 *p = path->data; u8 *q = p + path->length; struct pm_pos *opos = pos; @@ -316,7 +294,7 @@ parse_path(struct adata *path, struct pm_pos *pos) pos->mark = 0; pos->val.sp = p; len = *p; - p += 1 + bs * len; + p += 1 + BS * len; pos++; break; @@ -327,7 +305,7 @@ parse_path(struct adata *path, struct pm_pos *pos) pos->set = 0; pos->mark = 0; pos->val.asn = get_as(p); - p += bs; + p += BS; pos++; } break; @@ -346,13 +324,12 @@ pm_match(struct pm_pos *pos, u32 asn) if (! pos->set) return pos->val.asn == asn; - int bs = bgp_as4_support ? 4 : 2; u8 *p = pos->val.sp; int len = *p++; int i; for (i = 0; i < len; i++) - if (get_as(p + i * bs) == asn) + if (get_as(p + i * BS) == asn) return 1; return 0; diff --git a/nest/iface.h b/nest/iface.h index af98a76..a982c17 100644 --- a/nest/iface.h +++ b/nest/iface.h @@ -99,6 +99,7 @@ typedef struct neighbor { #define NEF_STICKY 1 neighbor *neigh_find(struct proto *, ip_addr *, unsigned flags); +neighbor *neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags); static inline int neigh_connected_to(struct proto *p, ip_addr *a, struct iface *i) { diff --git a/nest/neighbor.c b/nest/neighbor.c index 2c5af6a..a44667f 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -100,13 +100,21 @@ if_connected(ip_addr *a, struct iface *i) /* -1=error, 1=match, 0=no match */ * IP address, neigh_find() returns %NULL. */ + neighbor * neigh_find(struct proto *p, ip_addr *a, unsigned flags) { + return neigh_find2(p, a, NULL, flags); +} + + +neighbor * +neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) +{ neighbor *n; int class, scope = SCOPE_HOST; unsigned int h = neigh_hash(p, a); - struct iface *i, *j; + struct iface *i; WALK_LIST(n, neigh_hash_table[h]) /* Search the cache */ if (n->proto == p && ipa_equal(*a, n->addr)) @@ -115,27 +123,31 @@ neigh_find(struct proto *p, ip_addr *a, unsigned flags) class = ipa_classify(*a); if (class < 0) /* Invalid address */ return NULL; - if ((class & IADDR_SCOPE_MASK) < SCOPE_SITE || + if (((class & IADDR_SCOPE_MASK) == SCOPE_HOST) || + (((class & IADDR_SCOPE_MASK) == SCOPE_LINK) && (ifa == NULL)) || !(class & IADDR_HOST)) return NULL; /* Bad scope or a somecast */ - j = NULL; - WALK_LIST(i, iface_list) - if ((scope = if_connected(a, i)) >= 0) - { - j = i; - break; - } - if (!j && !(flags & NEF_STICKY)) + if (ifa) + scope = if_connected(a, ifa); + else + WALK_LIST(i, iface_list) + if ((scope = if_connected(a, i)) >= 0) + { + ifa = i; + break; + } + + if (!ifa && !(flags & NEF_STICKY)) return NULL; n = sl_alloc(neigh_slab); n->addr = *a; - n->iface = j; - if (j) + n->iface = ifa; + if (ifa) { add_tail(&neigh_hash_table[h], &n->n); - add_tail(&j->neighbors, &n->if_n); + add_tail(&ifa->neighbors, &n->if_n); } else { diff --git a/nest/route.h b/nest/route.h index 1bd23a6..e45a8c6 100644 --- a/nest/route.h +++ b/nest/route.h @@ -37,6 +37,7 @@ struct fib_node { byte pxlen; byte flags; /* User-defined */ byte x0, x1; /* User-defined */ + u32 uid; /* Unique ID based on hash */ ip_addr prefix; /* In host order */ }; diff --git a/nest/rt-fib.c b/nest/rt-fib.c index 8d76f26..510aa76 100644 --- a/nest/rt-fib.c +++ b/nest/rt-fib.c @@ -172,6 +172,28 @@ fib_find(struct fib *f, ip_addr *a, int len) return e; } +/* +int +fib_histogram(struct fib *f) +{ + log(L_WARN "Histogram dump start %d %d", f->hash_size, f->entries); + + int i, j; + struct fib_node *e; + + for (i = 0; i < f->hash_size; i++) + { + j = 0; + for (e = f->hash_table[i]; e != NULL; e = e->next) + j++; + if (j > 0) + log(L_WARN "Histogram line %d: %d", i, j); + } + + log(L_WARN "Histogram dump end"); +} +*/ + /** * fib_get - find or create a FIB node * @f: FIB to work with @@ -187,6 +209,7 @@ fib_get(struct fib *f, ip_addr *a, int len) unsigned int h = ipa_hash(*a); struct fib_node **ee = f->hash_table + (h >> f->hash_shift); struct fib_node *g, *e = *ee; + u32 uid = h << 16; while (e && (e->pxlen != len || !ipa_equal(*a, e->prefix))) e = e->next; @@ -196,17 +219,31 @@ fib_get(struct fib *f, ip_addr *a, int len) if (len < 0 || len > BITS_PER_IP_ADDRESS || !ip_is_prefix(*a,len)) bug("fib_get() called for invalid address"); #endif + + while ((g = *ee) && g->uid < uid) + ee = &g->next; + while ((g = *ee) && g->uid == uid) + { + ee = &g->next; + uid++; + } + + if ((uid >> 16) != h) + log(L_ERR "FIB hash table chains are too long"); + + // log (L_WARN "FIB_GET %I %x %x", *a, h, uid); + e = sl_alloc(f->fib_slab); e->prefix = *a; e->pxlen = len; - while ((g = *ee) && ipa_hash(g->prefix) < h) - ee = &g->next; e->next = *ee; + e->uid = uid; *ee = e; e->readers = NULL; f->init(e); if (f->entries++ > f->entries_max) fib_rehash(f, HASH_HI_STEP); + return e; } |