lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Message-Id: <20100327.203120.98894145.davem@davemloft.net> Date: Sat, 27 Mar 2010 20:31:20 -0700 (PDT) From: David Miller <davem@...emloft.net> To: netdev@...r.kernel.org CC: herbert@...dor.apana.org.au Subject: [PATCH RFC] inetpeer: Support ipv6 addresses. inetpeer: Support ipv6 addresses. Signed-off-by: David S. Miller <davem@...emloft.net> --- This a first step based upon the talks we were having the other week about potentially moving the dst metrics out into the inetpeer cache. The next step would be to move the peer pointer into dst_entry (or some common encapsulator datastructure that ipv4 and ipv6 could share, inet_dst_entry or something like that), and provide the necessary rt6_bind_peer() function for ipv6. A small set of changes could then add timewait recycling support to ipv6 essentially for free (commonize code, provide some wrapper for route type specific code). The limited dst metric usage in DecNET could then be moved into the DecNET route entry struct. This way we don't have to support DecNET in the inetpeer cache just for the sake of it's metrics. :-) Finally, we can really move the metrics array into the inetpeer entries. How does this sound? diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h index 87b1df0..2924302 100644 --- a/include/net/inetpeer.h +++ b/include/net/inetpeer.h @@ -13,10 +13,18 @@ #include <linux/spinlock.h> #include <asm/atomic.h> +typedef struct { + union { + __be32 a4; + __be32 a6[4]; + }; + __u16 family; +} inet_peer_address_t; + struct inet_peer { /* group together avl_left,avl_right,v4daddr to speedup lookups */ struct inet_peer *avl_left, *avl_right; - __be32 v4daddr; /* peer's address */ + inet_peer_address_t daddr; __u32 avl_height; struct list_head unused; __u32 dtime; /* the time of last use of not @@ -31,7 +39,7 @@ struct inet_peer { void inet_initpeers(void) __init; /* can be called with or without local BH being disabled */ -struct inet_peer *inet_getpeer(__be32 daddr, int create); +struct inet_peer *inet_getpeer(inet_peer_address_t *daddr, int create); /* can be called from BH context or outside */ extern void inet_putpeer(struct inet_peer *p); diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index 6bcfe52..87066eb 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -19,6 +19,7 @@ #include <linux/net.h> #include <net/ip.h> #include <net/inetpeer.h> +#include <net/ipv6.h> /* * Theory of operations. @@ -136,6 +137,47 @@ static void unlink_from_unused(struct inet_peer *p) spin_unlock_bh(&inet_peer_unused_lock); } +static inline bool inet_peer_addr_equal(inet_peer_address_t *a, inet_peer_address_t *b) +{ + if (a->family == b->family) { + switch (a->family) { + case AF_INET: + if (a->a4 == b->a4) + return true; + break; + case AF_INET6: + if (!ipv6_addr_cmp((struct in6_addr *)a, + (struct in6_addr *)b)) + return true; + break; + default: + break; + } + } + return false; +} + +static inline u32 inet_peer_key(inet_peer_address_t *a) +{ + u32 key; + + switch (a->family) { + case AF_INET: + key = (__force __u32) a->a4; + break; + case AF_INET6: + key = ((__force __u32)a->a6[0] ^ + (__force __u32)a->a6[1] ^ + (__force __u32)a->a6[2] ^ + (__force __u32)a->a6[3]); + break; + default: + key = 0; + break; + } + return key; +} + /* * Called with local BH disabled and the pool lock held. * _stack is known to be NULL or not at compile time, @@ -143,15 +185,16 @@ static void unlink_from_unused(struct inet_peer *p) */ #define lookup(_daddr, _stack) \ ({ \ + u32 key = inet_peer_key(_daddr); \ struct inet_peer *u, **v; \ if (_stack != NULL) { \ stackptr = _stack; \ *stackptr++ = &peer_root; \ } \ for (u = peer_root; u != peer_avl_empty; ) { \ - if (_daddr == u->v4daddr) \ + if (inet_peer_addr_equal(_daddr, &u->daddr)) \ break; \ - if ((__force __u32)_daddr < (__force __u32)u->v4daddr) \ + if (key < inet_peer_key(&u->daddr)) \ v = &u->avl_left; \ else \ v = &u->avl_right; \ @@ -280,7 +323,7 @@ static void unlink_from_pool(struct inet_peer *p) if (atomic_read(&p->refcnt) == 1) { struct inet_peer **stack[PEER_MAXDEPTH]; struct inet_peer ***stackptr, ***delp; - if (lookup(p->v4daddr, stack) != p) + if (lookup(&p->daddr, stack) != p) BUG(); delp = stackptr - 1; /* *delp[0] == p */ if (p->avl_left == peer_avl_empty) { @@ -292,7 +335,7 @@ static void unlink_from_pool(struct inet_peer *p) t = lookup_rightempty(p); BUG_ON(*stackptr[-1] != t); **--stackptr = t->avl_left; - /* t is removed, t->v4daddr > x->v4daddr for any + /* t is removed, t->daddr > x->daddr for any * x in p->avl_left subtree. * Put t in the old place of p. */ *delp[0] = t; @@ -358,7 +401,7 @@ static int cleanup_once(unsigned long ttl) } /* Called with or without local BH being disabled. */ -struct inet_peer *inet_getpeer(__be32 daddr, int create) +struct inet_peer *inet_getpeer(inet_peer_address_t *daddr, int create) { struct inet_peer *p, *n; struct inet_peer **stack[PEER_MAXDEPTH], ***stackptr; @@ -384,10 +427,11 @@ struct inet_peer *inet_getpeer(__be32 daddr, int create) n = kmem_cache_alloc(peer_cachep, GFP_ATOMIC); if (n == NULL) return NULL; - n->v4daddr = daddr; + n->daddr = *daddr; atomic_set(&n->refcnt, 1); atomic_set(&n->rid, 0); - atomic_set(&n->ip_id_count, secure_ip_id(daddr)); + if (daddr->family == AF_INET) + atomic_set(&n->ip_id_count, secure_ip_id(daddr->a4)); n->tcp_ts_stamp = 0; write_lock_bh(&peer_pool_lock); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index b59430b..681c8b9 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -142,8 +142,14 @@ static void ip4_frag_init(struct inet_frag_queue *q, void *a) qp->saddr = arg->iph->saddr; qp->daddr = arg->iph->daddr; qp->user = arg->user; - qp->peer = sysctl_ipfrag_max_dist ? - inet_getpeer(arg->iph->saddr, 1) : NULL; + if (sysctl_ipfrag_max_dist) { + inet_peer_address_t addr; + + addr.a4 = arg->iph->saddr; + addr.family = AF_INET; + qp->peer = inet_getpeer(&addr, 1); + } else + qp->peer = NULL; } static __inline__ void ip4_frag_free(struct inet_frag_queue *q) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 32d3961..9334e29 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1287,9 +1287,12 @@ skip_hashing: void rt_bind_peer(struct rtable *rt, int create) { static DEFINE_SPINLOCK(rt_peer_lock); + inet_peer_address_t addr; struct inet_peer *peer; - peer = inet_getpeer(rt->rt_dst, create); + addr.a4 = rt->rt_dst; + addr.family = AF_INET; + peer = inet_getpeer(&addr, create); spin_lock_bh(&rt_peer_lock); if (rt->peer == NULL) { diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index f4df5f9..9de6a12 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1350,7 +1350,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) tcp_death_row.sysctl_tw_recycle && (dst = inet_csk_route_req(sk, req)) != NULL && (peer = rt_get_peer((struct rtable *)dst)) != NULL && - peer->v4daddr == saddr) { + peer->daddr.a4 == saddr) { if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL && (s32)(peer->tcp_ts - req->ts_recent) > TCP_PAWS_WINDOW) { @@ -1770,7 +1770,11 @@ int tcp_v4_remember_stamp(struct sock *sk) int release_it = 0; if (!rt || rt->rt_dst != inet->inet_daddr) { - peer = inet_getpeer(inet->inet_daddr, 1); + inet_peer_address_t addr; + + addr.a4 = inet->inet_daddr; + addr.family = AF_INET; + peer = inet_getpeer(&addr, 1); release_it = 1; } else { if (!rt->peer) @@ -1795,8 +1799,12 @@ int tcp_v4_remember_stamp(struct sock *sk) int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw) { - struct inet_peer *peer = inet_getpeer(tw->tw_daddr, 1); + inet_peer_address_t addr; + struct inet_peer *peer; + addr.a4 = tw->tw_daddr; + addr.family = AF_INET; + peer = inet_getpeer(&addr, 1); if (peer) { const struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@...r.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists