diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2004-06-22 20:28:59 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2004-06-22 20:28:59 +0000 |
commit | 6fea9855664583f52deafa42b35f7320cad8da93 (patch) | |
tree | 03958bbe9997531e60137428ca3852b1405c29eb /usr.sbin | |
parent | 73fe7b61cd58457249a00cb41a0673dc5db8bbaa (diff) |
Make the RDE IPv6 ready missing is the message handling. The internal
prefix tree changed form a hash table to a per AF RB tree.
OK henning@ some ideas are from Brent Graveland.
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/bgpd/bgpd.h | 27 | ||||
-rw-r--r-- | usr.sbin/bgpd/kroute.c | 57 | ||||
-rw-r--r-- | usr.sbin/bgpd/mrt.c | 6 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.c | 43 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.h | 30 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_prefix.c | 318 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_rib.c | 13 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_update.c | 13 |
8 files changed, 347 insertions, 160 deletions
diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index 2f8c42f4be6..96edba5445e 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.129 2004/06/22 07:22:31 henning Exp $ */ +/* $OpenBSD: bgpd.h,v 1.130 2004/06/22 20:28:58 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -593,16 +593,21 @@ void imsg_free(struct imsg *); int imsg_get_fd(struct imsgbuf *); /* kroute.c */ -int kr_init(int); -int kr_change(struct kroute *); -int kr_delete(struct kroute *); -void kr_shutdown(void); -void kr_fib_couple(void); -void kr_fib_decouple(void); -int kr_dispatch_msg(void); -int kr_nexthop_add(struct bgpd_addr *); -void kr_nexthop_delete(struct bgpd_addr *); -void kr_show_route(struct imsg *); +int kr_init(int); +int kr_change(struct kroute *); +int kr_delete(struct kroute *); +void kr_shutdown(void); +void kr_fib_couple(void); +void kr_fib_decouple(void); +int kr_dispatch_msg(void); +int kr_nexthop_add(struct bgpd_addr *); +void kr_nexthop_delete(struct bgpd_addr *); +void kr_show_route(struct imsg *); +in_addr_t prefixlen2mask(u_int8_t); +int prefix_equal(const struct bgpd_addr *, const struct bgpd_addr *, + int); +void inet6applymask(struct in6_addr *, const struct in6_addr *, int); + /* control.c */ int control_init(void); diff --git a/usr.sbin/bgpd/kroute.c b/usr.sbin/bgpd/kroute.c index d2440c8ee44..07a152c78ac 100644 --- a/usr.sbin/bgpd/kroute.c +++ b/usr.sbin/bgpd/kroute.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kroute.c,v 1.97 2004/06/22 07:22:31 henning Exp $ */ +/* $OpenBSD: kroute.c,v 1.98 2004/06/22 20:28:58 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -98,7 +98,6 @@ void kroute_detach_nexthop(struct knexthop_node *); int protect_lo(void); u_int8_t prefixlen_classful(in_addr_t); u_int8_t mask2prefixlen(in_addr_t); -in_addr_t prefixlen2mask(u_int8_t); void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); void if_change(u_short, int, struct if_data *); void if_announce(void *); @@ -817,6 +816,60 @@ prefixlen2mask(u_int8_t prefixlen) return (0xffffffff << (32 - prefixlen)); } +int +prefix_equal(const struct bgpd_addr *a, const struct bgpd_addr *b, + int prefixlen) +{ + in_addr_t mask; + int i; + u_int8_t m; + + if (a->af != b->af) + return 0; + switch (a->af) { + case AF_INET: + if (prefixlen > 32) + fatalx("prefix_cmp: bad IPv4 prefixlen"); + mask = htonl(prefixlen2mask(prefixlen)); + if ((a->v4.s_addr & mask) == (b->v4.s_addr & mask)) + return (1); + else + return (0); + case AF_INET6: + for (i = 0; i < prefixlen / 8; i++) + if (a->v6.s6_addr[i] != b->v6.s6_addr[i]) + return (0); + i = prefixlen % 8; + if (i) { + m = 0xff00 >> i; + if ((a->v6.s6_addr[prefixlen / 8] & m) != + (b->v6.s6_addr[prefixlen / 8] & m)) + return (0); + } + return (1); + default: + fatalx("prefix_cmp: unknown af"); + } + return (0); +} + +void +inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) +{ + struct in6_addr mask; + int i; + + bzero(&mask, sizeof(mask)); + for (i = 0; i < prefixlen / 8; i++) + mask.s6_addr[i] = 0xff; + i = prefixlen % 8; + if (i) + mask.s6_addr[prefixlen / 8] = 0xff00 >> i; + + for (i = 0; i < 16; i++) + dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; +} + #define ROUNDUP(a, size) \ (((a) & ((size) - 1)) ? (1 + ((a) | ((size) - 1))) : (a)) diff --git a/usr.sbin/bgpd/mrt.c b/usr.sbin/bgpd/mrt.c index 484b7910b32..121800b6eef 100644 --- a/usr.sbin/bgpd/mrt.c +++ b/usr.sbin/bgpd/mrt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mrt.c,v 1.31 2004/06/20 18:35:12 henning Exp $ */ +/* $OpenBSD: mrt.c,v 1.32 2004/06/22 20:28:58 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> @@ -237,10 +237,12 @@ mrt_dump_entry(struct mrt_config *mrt, struct prefix *p, u_int16_t snum, { struct buf *buf; void *bptr; + struct bgpd_addr addr; u_int16_t len, attr_len; attr_len = mrt_attr_length(&p->aspath->flags); len = MRT_DUMP_HEADER_SIZE + attr_len; + pt_getaddr(p->prefix, &addr); if ((buf = imsg_create(mrt->ibuf, IMSG_MRT_MSG, mrt->id, len + MRT_HEADER_SIZE)) == NULL) { @@ -255,7 +257,7 @@ mrt_dump_entry(struct mrt_config *mrt, struct prefix *p, u_int16_t snum, DUMP_SHORT(buf, 0); DUMP_SHORT(buf, snum); - DUMP_NLONG(buf, p->prefix->prefix.v4.s_addr); + DUMP_NLONG(buf, addr.v4.s_addr); DUMP_BYTE(buf, p->prefix->prefixlen); DUMP_BYTE(buf, 1); /* state */ DUMP_LONG(buf, p->lastchange); /* originated */ diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c index d0f366df4ed..24d229c0403 100644 --- a/usr.sbin/bgpd/rde.c +++ b/usr.sbin/bgpd/rde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.117 2004/06/20 18:35:12 henning Exp $ */ +/* $OpenBSD: rde.c,v 1.118 2004/06/22 20:28:58 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -290,7 +290,7 @@ rde_dispatch_imsg_session(struct imsgbuf *ibuf) break; } pid = imsg.hdr.pid; - pt_dump(network_dump_upcall, &pid); + pt_dump(network_dump_upcall, &pid, AF_UNSPEC); imsg_compose_pid(&ibuf_se, IMSG_CTL_END, pid, NULL, 0); break; case IMSG_CTL_SHOW_RIB: @@ -299,7 +299,7 @@ rde_dispatch_imsg_session(struct imsgbuf *ibuf) break; } pid = imsg.hdr.pid; - pt_dump(rde_dump_upcall, &pid); + pt_dump(rde_dump_upcall, &pid, AF_UNSPEC); imsg_compose_pid(&ibuf_se, IMSG_CTL_END, pid, NULL, 0); break; case IMSG_CTL_SHOW_RIB_AS: @@ -404,7 +404,7 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf) mrt.ibuf = &ibuf_main; if (mrt.type == MRT_TABLE_DUMP) { mrt_clear_seq(); - pt_dump(mrt_dump_upcall, &mrt); + pt_dump(mrt_dump_upcall, &mrt, AF_UNSPEC); if (imsg_compose(&ibuf_main, IMSG_MRT_END, mrt.id, NULL, 0) == -1) fatalx("imsg_compose error"); @@ -741,7 +741,7 @@ rde_dump_rib_as(struct prefix *p, pid_t pid) rib.active_cnt = p->aspath->active_cnt; memcpy(&rib.nexthop, &p->aspath->nexthop->true_nexthop, sizeof(rib.nexthop)); - memcpy(&rib.prefix, &p->prefix->prefix, sizeof(rib.prefix)); + pt_getaddr(p->prefix, &rib.prefix); rib.prefixlen = p->prefix->prefixlen; rib.origin = p->aspath->flags.origin; rib.flags = 0; @@ -772,7 +772,7 @@ rde_dump_rib_prefix(struct prefix *p, pid_t pid) struct ctl_show_rib_prefix prefix; prefix.lastchange = p->lastchange; - memcpy(&prefix.prefix, &p->prefix->prefix, sizeof(prefix.prefix)); + pt_getaddr(p->prefix, &prefix.prefix); prefix.prefixlen = p->prefix->prefixlen; prefix.flags = 0; if (p->aspath->nexthop->state == NEXTHOP_REACH) @@ -829,14 +829,16 @@ rde_dump_prefix_upcall(struct pt_entry *pt, void *ptr) struct { pid_t pid; struct ctl_show_rib_prefix *pref; - } *ctl = ptr; - struct prefix *p; - in_addr_t mask; + } *ctl = ptr; + struct prefix *p; + struct bgpd_addr addr; - mask = htonl(0xffffffff << (32 - ctl->pref->prefixlen)); - if (ctl->pref->prefixlen <= pt->prefixlen && - (ctl->pref->prefix.v4.s_addr & mask) == - (pt->prefix.v4.s_addr & mask)) + pt_getaddr(pt, &addr); + if (addr.af != ctl->pref->prefix.af) + return; + if (ctl->pref->prefixlen > pt->prefixlen) + return; + if (prefix_equal(&ctl->pref->prefix, &addr, ctl->pref->prefixlen)) LIST_FOREACH(p, &pt->prefix_h, prefix_l) rde_dump_rib_as(p, ctl->pid); } @@ -856,7 +858,7 @@ rde_dump_prefix(struct ctl_show_rib_prefix *pref, pid_t pid) } else if (pref->flags & F_LONGER) { ctl.pid = pid; ctl.pref = pref; - pt_dump(rde_dump_prefix_upcall, &ctl); + pt_dump(rde_dump_prefix_upcall, &ctl, AF_UNSPEC); } else { if ((pt = pt_get(&pref->prefix, pref->prefixlen)) != NULL) rde_dump_upcall(pt, &pid); @@ -869,7 +871,8 @@ rde_dump_prefix(struct ctl_show_rib_prefix *pref, pid_t pid) void rde_send_kroute(struct prefix *new, struct prefix *old) { - struct kroute kr; + struct kroute kr; + struct bgpd_addr addr; struct prefix *p; enum imsg_type type; @@ -897,7 +900,8 @@ rde_send_kroute(struct prefix *new, struct prefix *old) kr.nexthop.s_addr = p->aspath->nexthop->true_nexthop.v4.s_addr; } - kr.prefix.s_addr = p->prefix->prefix.v4.s_addr; + pt_getaddr(p->prefix, &addr); + kr.prefix.s_addr = addr.v4.s_addr; kr.prefixlen = p->prefix->prefixlen; if (imsg_compose(&ibuf_main, type, 0, &kr, sizeof(kr)) == -1) @@ -1207,7 +1211,7 @@ peer_dump(u_int32_t id, u_int16_t afi, u_int8_t safi) if (afi == AFI_ALL || afi == AFI_IPv4) if (safi == SAFI_ALL || safi == SAFI_UNICAST || safi == SAFI_BOTH) { - pt_dump(up_dump_upcall, peer); + pt_dump(up_dump_upcall, peer, AF_INET); return; } @@ -1280,6 +1284,7 @@ network_dump_upcall(struct pt_entry *pt, void *ptr) { struct prefix *p; struct kroute k; + struct bgpd_addr addr; pid_t pid; memcpy(&pid, ptr, sizeof(pid)); @@ -1287,8 +1292,8 @@ network_dump_upcall(struct pt_entry *pt, void *ptr) LIST_FOREACH(p, &pt->prefix_h, prefix_l) if (p->aspath->nexthop->flags & NEXTHOP_ANNOUNCE) { bzero(&k, sizeof(k)); - memcpy(&k.prefix, &p->prefix->prefix.v4.s_addr, - sizeof(k.prefix)); + pt_getaddr(p->prefix, &addr); + k.prefix = addr.v4; k.prefixlen = p->prefix->prefixlen; if (p->peer == &peerself) k.flags = F_KERNEL; diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h index 319655debae..e82c3b548de 100644 --- a/usr.sbin/bgpd/rde.h +++ b/usr.sbin/bgpd/rde.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.h,v 1.41 2004/06/20 18:35:12 henning Exp $ */ +/* $OpenBSD: rde.h,v 1.42 2004/06/22 20:28:58 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and @@ -179,13 +179,22 @@ struct rde_aspath { struct attr_flags flags; }; +/* generic entry without address specific part */ struct pt_entry { - LIST_ENTRY(pt_entry) pt_l; /* currently we are using a - hash list for prefixes */ - struct bgpd_addr prefix; + RB_ENTRY(pt_entry) pt_e; + sa_family_t af; u_int8_t prefixlen; struct prefix_head prefix_h; struct prefix *active; /* for fast access */ +}; + +struct pt_entry4 { + RB_ENTRY(pt_entry) pt_e; + sa_family_t af; + u_int8_t prefixlen; + struct prefix_head prefix_h; + struct prefix *active; /* for fast access */ + struct in_addr prefix4; /* * Route Flap Damping structures * Currently I think they belong into the prefix but for the moment @@ -193,6 +202,15 @@ struct pt_entry { */ }; +struct pt_entry6 { + RB_ENTRY(pt_entry) pt_e; + sa_family_t af; + u_int8_t prefixlen; + struct prefix_head prefix_h; + struct prefix *active; /* for fast access */ + struct in6_addr prefix6; +}; + struct prefix { LIST_ENTRY(prefix) prefix_l, path_l; struct rde_aspath *aspath; @@ -297,11 +315,13 @@ void up_dump_upcall(struct pt_entry *, void *); void pt_init(void); void pt_shutdown(void); int pt_empty(struct pt_entry *); +void pt_getaddr(struct pt_entry *, struct bgpd_addr *); struct pt_entry *pt_get(struct bgpd_addr *, int); struct pt_entry *pt_add(struct bgpd_addr *, int); void pt_remove(struct pt_entry *); struct pt_entry *pt_lookup(struct bgpd_addr *); -void pt_dump(void (*)(struct pt_entry *, void *), void *); +void pt_dump(void (*)(struct pt_entry *, void *), void *, + sa_family_t); /* rde_filter.c */ enum filter_actions rde_filter(struct rde_peer *, struct attr_flags *, diff --git a/usr.sbin/bgpd/rde_prefix.c b/usr.sbin/bgpd/rde_prefix.c index 7a47fc756c6..d58245a7cc0 100644 --- a/usr.sbin/bgpd/rde_prefix.c +++ b/usr.sbin/bgpd/rde_prefix.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_prefix.c,v 1.13 2004/03/11 17:34:01 henning Exp $ */ +/* $OpenBSD: rde_prefix.c,v 1.14 2004/06/22 20:28:58 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> @@ -43,40 +43,20 @@ */ /* internal prototypes */ -static struct pt_entry *pt_alloc(void); +static struct pt_entry4 *pt_alloc4(void); +static struct pt_entry6 *pt_alloc6(void); static void pt_free(struct pt_entry *); -/* - * currently we are using a hash list to store the prefixes. This may be - * replaced with a red-black trie if necessary. - */ -LIST_HEAD(pt_entryhead, pt_entry); - -struct pt_table { - struct pt_entryhead *pt_hashtbl; - u_int32_t pt_hashmask; -}; +int pt_prefix_cmp(const struct pt_entry *, const struct pt_entry *); #define MIN_PREFIX 0 #define MAX_PREFIX 32 +RB_HEAD(pt_tree, pt_entry); +RB_PROTOTYPE(pt_tree, pt_entry, pt_e, pt_prefix_cmp); +RB_GENERATE(pt_tree, pt_entry, pt_e, pt_prefix_cmp); -/* - * size of the hashtable per prefixlen. The sizes were chosen from a bgp - * dump done on Nov 4. 2003. - */ -u_int32_t pthashsize[MAX_PREFIX + 1 - MIN_PREFIX] = { - /* need to be power of 2 */ - 1, 1, 1, 1, 1, 1, 1, 1, - 16, 8, 8, 16, 32, 64, 256, 256, - 4096, 1024, 2048, 8192, 8192, 4096, 8192, 8192, - 32768, 1, 1, 1, 1, 1, 1, 1, 1 -}; - -struct pt_table pttable[MAX_PREFIX + 1 - MIN_PREFIX]; - -#define PT_HASH(p, plen) \ - &pttable[plen].pt_hashtbl[((p >> plen) ^ (p >> (plen + 5))) & \ - pttable[plen].pt_hashmask] +struct pt_tree pttable4; +struct pt_tree pttable6; /* * Statistics collector. @@ -87,48 +67,29 @@ struct pt_table pttable[MAX_PREFIX + 1 - MIN_PREFIX]; struct pt_stats { u_int64_t pt_alloc; u_int64_t pt_free; - u_int64_t pt_add[MAX_PREFIX + 1 - MIN_PREFIX]; - u_int64_t pt_get[MAX_PREFIX + 1 - MIN_PREFIX]; - u_int64_t pt_remove[MAX_PREFIX + 1 - MIN_PREFIX]; + u_int64_t pt_add; + u_int64_t pt_get; + u_int64_t pt_remove; u_int64_t pt_lookup; u_int64_t pt_dump; } ptstats; /* simple macros to update statistics */ #define PT_STAT(x) (ptstats.x++) -#define PT_STAT2(x, p) (ptstats.x[p]++) void pt_init(void) { - int i; - u_int32_t j; - - for (i = MIN_PREFIX; i <= MAX_PREFIX; i++) { - pttable[i].pt_hashtbl = calloc(pthashsize[i], - sizeof(struct pt_entryhead)); - if (pttable[i].pt_hashtbl == NULL) - fatal("pt_init"); - - for (j = 0; j < pthashsize[i]; j++) - LIST_INIT(&pttable[i].pt_hashtbl[j]); - - pttable[i].pt_hashmask = pthashsize[i] - 1; - } + RB_INIT(&pttable4); + RB_INIT(&pttable6); } void pt_shutdown(void) { - int i; - u_int32_t j; - - for (i = MIN_PREFIX; i <= MAX_PREFIX; i++) { - for (j = 0; j < pthashsize[i]; j++) - if (!LIST_EMPTY(&pttable[i].pt_hashtbl[j])) - log_warnx("pt_free: free non-free table " - "[%d][%d]", i, j); - free(pttable[i].pt_hashtbl); - } + if (!RB_EMPTY(&pttable4)) + log_debug("pt_shutdown: IPv4 tree is not empty."); + if (!RB_EMPTY(&pttable6)) + log_debug("pt_shutdown: IPv6 tree is not empty."); } int @@ -138,109 +99,242 @@ pt_empty(struct pt_entry *pte) return LIST_EMPTY(&pte->prefix_h); } +void +pt_getaddr(struct pt_entry *pte, struct bgpd_addr *addr) +{ + bzero(addr, sizeof(struct bgpd_addr)); + switch (pte->af) { + case AF_INET: + addr->af = pte->af; + addr->v4 = ((struct pt_entry4 *)pte)->prefix4; + break; + case AF_INET6: + addr->af = pte->af; + memcpy(&addr->v6, &((struct pt_entry6 *)pte)->prefix6, + sizeof(addr->v6)); + /* XXX scope_id ??? */ + break; + default: + fatalx("pt_getaddr: unknown af"); + } +} + struct pt_entry * pt_get(struct bgpd_addr *prefix, int prefixlen) { - struct pt_entryhead *head; - struct pt_entry *p; - u_int32_t p_hbo; - - ENSURE(MIN_PREFIX <= prefixlen && prefixlen <= MAX_PREFIX); - PT_STAT2(pt_get, prefixlen); - - p_hbo = ntohl(prefix->v4.s_addr); - head = PT_HASH(p_hbo, prefixlen); - ENSURE(head != NULL); - - LIST_FOREACH(p, head, pt_l) { - if (prefix->v4.s_addr == p->prefix.v4.s_addr) - return p; + struct pt_entry4 pte4; + struct pt_entry6 pte6; + in_addr_t addr_hbo; + + PT_STAT(pt_get); + + switch (prefix->af) { + case AF_INET: + if (prefixlen > 32) + fatalx("pt_get: bad IPv4 prefixlen"); + pte4.af = AF_INET; + addr_hbo = ntohl(prefix->v4.s_addr); + pte4.prefix4.s_addr = htonl(addr_hbo & + prefixlen2mask(prefixlen)); + pte4.prefixlen = prefixlen; + return RB_FIND(pt_tree, &pttable4, (struct pt_entry *)&pte4); + case AF_INET6: + if (prefixlen > 128) + fatalx("pt_get: bad IPv6 prefixlen"); + pte6.af = AF_INET6; + pte6.prefixlen = prefixlen; + inet6applymask(&pte6.prefix6, &prefix->v6, prefixlen); + return RB_FIND(pt_tree, &pttable6, (struct pt_entry *)&pte6); + default: + log_warnx("pt_get: unknown af"); } - return NULL; + return (NULL); } struct pt_entry * pt_add(struct bgpd_addr *prefix, int prefixlen) { - struct pt_entryhead *head; - struct pt_entry *p; - u_int32_t p_hbo; + struct pt_tree *tree = NULL; + struct pt_entry *p = NULL; + struct pt_entry4 *p4; + struct pt_entry6 *p6; + in_addr_t addr_hbo; - ENSURE(MIN_PREFIX <= prefixlen && prefixlen <= MAX_PREFIX); ENSURE(pt_get(prefix, prefixlen) == NULL); - PT_STAT2(pt_add, prefixlen); - - p_hbo = ntohl(prefix->v4.s_addr); - head = PT_HASH(p_hbo, prefixlen); - ENSURE(head != NULL); - - p = pt_alloc(); - memcpy(&p->prefix, prefix, sizeof(p->prefix)); - p->prefixlen = prefixlen; + PT_STAT(pt_add); + + switch (prefix->af) { + case AF_INET: + p4 = pt_alloc4(); + if (prefixlen > 32) + fatalx("pt_add: bad IPv4 prefixlen"); + p4->af = AF_INET; + p4->prefixlen = prefixlen; + addr_hbo = ntohl(prefix->v4.s_addr); + p4->prefix4.s_addr = htonl(addr_hbo & + prefixlen2mask(prefixlen)); + p = (struct pt_entry *)p4; + tree = &pttable4; + break; + case AF_INET6: + p6 = pt_alloc6(); + if (prefixlen > 128) + fatalx("pt_add: bad IPv6 prefixlen"); + p6->af = AF_INET6; + p6->prefixlen = prefixlen; + inet6applymask(&p6->prefix6, &prefix->v6, prefixlen); + p = (struct pt_entry *)p6; + tree = &pttable6; + break; + default: + fatalx("pt_add: unknown af"); + } LIST_INIT(&p->prefix_h); - LIST_INSERT_HEAD(head, p, pt_l); + if (RB_INSERT(pt_tree, &pttable4, p) != NULL) { + log_warnx("prefix_add: insert failed"); + return (NULL); + } - return p; + return (p); } void pt_remove(struct pt_entry *pte) { ENSURE(pt_empty(pte)); - PT_STAT2(pt_remove, pte->prefixlen); + PT_STAT(pt_remove); + + switch (pte->af) { + case AF_INET: + if (RB_REMOVE(pt_tree, &pttable4, pte) == NULL) + log_warnx("pt_remove: remove failed."); + break; + case AF_INET6: + if (RB_REMOVE(pt_tree, &pttable6, pte) == NULL) + log_warnx("pt_remove: remove failed."); + break; + default: + fatalx("pt_remove: unknown af"); + } - LIST_REMOVE(pte, pt_l); pt_free(pte); } struct pt_entry * pt_lookup(struct bgpd_addr *prefix) { - struct bgpd_addr pmasked; struct pt_entry *p; - u_int32_t addr_hbo; int i; PT_STAT(pt_lookup); - bzero(&pmasked, sizeof(pmasked)); - pmasked.af = AF_INET; - addr_hbo = ntohl(prefix->v4.s_addr); - for (i = MAX_PREFIX; i >= MIN_PREFIX; i--) { - pmasked.v4.s_addr = htonl(addr_hbo & (0xffffffff << (32 - i))); - p = pt_get(&pmasked, i); - if (p != NULL) - return (p); + switch (prefix->af) { + case AF_INET: + for (i = 32; i >= 0; i--) { + p = pt_get(prefix, i); + if (p != NULL) + return (p); + } + break; + case AF_INET6: + for (i = 128; i >= 0; i--) { + p = pt_get(prefix, i); + if (p != NULL) + return (p); + } + break; + default: + fatalx("pt_lookup: unknown af"); } return (NULL); } void -pt_dump(void (*upcall)(struct pt_entry *, void *), void *arg) +pt_dump(void (*upcall)(struct pt_entry *, void *), void *arg, sa_family_t af) { - struct pt_entry *p; - int i; - u_int32_t j; + struct pt_entry *p; + + if (af == AF_INET || af == AF_UNSPEC) + RB_FOREACH(p, pt_tree, &pttable4) + upcall(p, arg); + if (af == AF_INET6 || af == AF_UNSPEC) + RB_FOREACH(p, pt_tree, &pttable6) + upcall(p, arg); +} - PT_STAT(pt_dump); - for (i = MAX_PREFIX; i >= MIN_PREFIX; i--) { - for (j = 0; j < pthashsize[i]; j++) - LIST_FOREACH(p, &pttable[i].pt_hashtbl[j], pt_l) - upcall(p, arg); +int +pt_prefix_cmp(const struct pt_entry *a, const struct pt_entry *b) +{ + const struct pt_entry4 *a4, *b4; + const struct pt_entry6 *a6, *b6; + int i; + + if (a == NULL) + return (1); + if (b == NULL) + return (-1); + + if (a->af != b->af) + log_debug("af non equal a %d b %d\n", a->af, b->af); + ENSURE(a->af == b->af); + + switch (a->af) { + case AF_INET: + a4 = (const struct pt_entry4 *)a; + b4 = (const struct pt_entry4 *)b; + if (ntohl(a4->prefix4.s_addr) > ntohl(b4->prefix4.s_addr)) + return (1); + if (ntohl(a4->prefix4.s_addr) < ntohl(b4->prefix4.s_addr)) + return (-1); + if (a4->prefixlen > b4->prefixlen) + return (1); + if (a4->prefixlen < b4->prefixlen) + return (-1); + return (0); + case AF_INET6: + a6 = (const struct pt_entry6 *)a; + b6 = (const struct pt_entry6 *)b; + + i = memcmp(&a6->prefix6, &b6->prefix6, sizeof(struct in6_addr)); + if (i > 0) + return (1); + if (i < 0) + return (-1); + if (a6->prefixlen < b6->prefixlen) + return (-1); + if (a6->prefixlen > b6->prefixlen) + return (1); + return (0); + + default: + fatalx("pt_prefix_cmp: unknown af"); } + return (-1); } /* returns a zeroed pt_entry function may not return on fail */ -static struct pt_entry * -pt_alloc(void) +static struct pt_entry4 * +pt_alloc4(void) { - struct pt_entry *p; + struct pt_entry4 *p; + + PT_STAT(pt_alloc); + p = calloc(1, sizeof(*p)); + if (p == NULL) + fatal("pt_alloc"); + return (p); +} + +static struct pt_entry6 * +pt_alloc6(void) +{ + struct pt_entry6 *p; PT_STAT(pt_alloc); p = calloc(1, sizeof(*p)); if (p == NULL) fatal("pt_alloc"); - return p; + return (p); } static void diff --git a/usr.sbin/bgpd/rde_rib.c b/usr.sbin/bgpd/rde_rib.c index b1793e85ee9..c93d0498631 100644 --- a/usr.sbin/bgpd/rde_rib.c +++ b/usr.sbin/bgpd/rde_rib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_rib.c,v 1.47 2004/06/22 07:22:31 henning Exp $ */ +/* $OpenBSD: rde_rib.c,v 1.48 2004/06/22 20:28:58 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> @@ -178,13 +178,15 @@ void path_remove(struct rde_aspath *asp) { struct prefix *p; + struct bgpd_addr addr; RIB_STAT(path_remove); while ((p = LIST_FIRST(&asp->prefix_h)) != NULL) { /* Commit is done in peer_down() */ + pt_getaddr(p->prefix, &addr); rde_send_pftable(p->aspath->flags.pftable, - &p->prefix->prefix, p->prefix->prefixlen, 1); + &addr, p->prefix->prefixlen, 1); prefix_destroy(p); } @@ -305,14 +307,17 @@ struct prefix * prefix_get(struct rde_aspath *asp, struct bgpd_addr *prefix, int prefixlen) { struct prefix *p; + struct bgpd_addr addr; RIB_STAT(prefix_get); ENSURE(asp != NULL); LIST_FOREACH(p, &asp->prefix_h, path_l) { ENSURE(p->prefix != NULL); - if (p->prefix->prefixlen == prefixlen && - p->prefix->prefix.v4.s_addr == prefix->v4.s_addr) { + if (p->prefix->prefixlen != prefixlen) + continue; + pt_getaddr(p->prefix, &addr); + if (prefix_equal(&addr, prefix, prefixlen)) { ENSURE(p->aspath == asp); return p; } diff --git a/usr.sbin/bgpd/rde_update.c b/usr.sbin/bgpd/rde_update.c index 3d0db418b8d..88adabcc2b9 100644 --- a/usr.sbin/bgpd/rde_update.c +++ b/usr.sbin/bgpd/rde_update.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_update.c,v 1.19 2004/06/20 18:35:12 henning Exp $ */ +/* $OpenBSD: rde_update.c,v 1.20 2004/06/22 20:28:58 claudio Exp $ */ /* * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org> @@ -213,6 +213,7 @@ up_generate_updates(struct rde_peer *peer, struct update_prefix *p; struct attr *atr; struct attr_flags attrs; + struct bgpd_addr addr; ENSURE(peer->state == PEER_UP); /* @@ -302,7 +303,8 @@ up_generate_updates(struct rde_peer *peer, /* copy attributes for output filter */ attr_copy(&attrs, &old->aspath->flags); - if (rde_filter(peer, &attrs, &old->prefix->prefix, + pt_getaddr(old->prefix, &addr); + if (rde_filter(peer, &attrs, &addr, old->prefix->prefixlen, DIR_OUT) == ACTION_DENY) { attr_free(&attrs); return; @@ -314,7 +316,7 @@ up_generate_updates(struct rde_peer *peer, if (p == NULL) fatal("up_queue_update"); - p->prefix = old->prefix->prefix; + p->prefix = addr; p->prefixlen = old->prefix->prefixlen; if (up_add(peer, p, NULL) == -1) log_warnx("queuing withdraw failed."); @@ -395,7 +397,8 @@ up_generate_updates(struct rde_peer *peer, /* copy attributes for output filter */ attr_copy(&attrs, &new->aspath->flags); - if (rde_filter(peer, &attrs, &new->prefix->prefix, + pt_getaddr(new->prefix, &addr); + if (rde_filter(peer, &attrs, &addr, new->prefix->prefixlen, DIR_OUT) == ACTION_DENY) { attr_free(&attrs); up_generate_updates(peer, NULL, old); @@ -439,7 +442,7 @@ up_generate_updates(struct rde_peer *peer, * but currently I don't care. */ a->attr_hash = aspath_hash(attrs.aspath); - p->prefix = new->prefix->prefix; + p->prefix = addr; p->prefixlen = new->prefix->prefixlen; /* no longer needed */ |