Message ID | 20131003173946.GA5684@sbohrermbp13-local.rgmadvisors.com |
---|---|
State | RFC, archived |
Delegated to: | David Miller |
Headers | show |
On Thu, 2013-10-03 at 12:39 -0500, Shawn Bohrer wrote: > On Wed, Oct 02, 2013 at 02:38:52PM -0700, Eric Dumazet wrote: > > I suggested that for unicast, you do a limited lookup to the first > > socket found in bucket. > > > > If its an exact match, you take the socket. > > > > If not, you give up, and do not scan the whole chain. > > So something like the following? > > > diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c > index 02185a5..d202e5b 100644 > --- a/net/ipv4/udp.c > +++ b/net/ipv4/udp.c > @@ -1849,7 +1849,42 @@ begin: > } > rcu_read_unlock(); > return result; > +} > > +/* For unicast we should only early demux connected sockets or we can > + * break forwarding setups. The chains here can be long so only check > + * if the first socket is an exact match and if not move on. > + */ > +static struct sock *__udp4_lib_demux_lookup(struct net *net, > + __be16 loc_port, __be32 loc_addr, > + __be16 rmt_port, __be32 rmt_addr, > + int dif) > +{ > + struct sock *sk, *result; > + struct hlist_nulls_node *node; > + unsigned short hnum = ntohs(loc_port); > + unsigned int slot = udp_hashfn(net, hnum, udp_table.mask); > + struct udp_hslot *hslot = &udp_table.hash[slot]; > + const int exact_match = 18; > + int score; > + > + rcu_read_lock(); > + result = NULL; > + sk_nulls_for_each_rcu(sk, node, &hslot->head) { > + score = compute_score(sk, net, rmt_addr, hnum, rmt_port, > + loc_addr, loc_port, dif); > + if (score == exact_match) > + result = sk; > + /* Only check first socket in chain */ > + break; > + } > + > + if (result) { > + if (unlikely(!atomic_inc_not_zero_hint(&result->sk_refcnt, 2))) > + result = NULL; > + } > + rcu_read_unlock(); > + return result; > } > Just do the tuple comparison instead of compute_score(), since you know we want full L4 match. The standard way is to use the INET_MATCH() macro -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 02185a5..d202e5b 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1849,7 +1849,42 @@ begin: } rcu_read_unlock(); return result; +} +/* For unicast we should only early demux connected sockets or we can + * break forwarding setups. The chains here can be long so only check + * if the first socket is an exact match and if not move on. + */ +static struct sock *__udp4_lib_demux_lookup(struct net *net, + __be16 loc_port, __be32 loc_addr, + __be16 rmt_port, __be32 rmt_addr, + int dif) +{ + struct sock *sk, *result; + struct hlist_nulls_node *node; + unsigned short hnum = ntohs(loc_port); + unsigned int slot = udp_hashfn(net, hnum, udp_table.mask); + struct udp_hslot *hslot = &udp_table.hash[slot]; + const int exact_match = 18; + int score; + + rcu_read_lock(); + result = NULL; + sk_nulls_for_each_rcu(sk, node, &hslot->head) { + score = compute_score(sk, net, rmt_addr, hnum, rmt_port, + loc_addr, loc_port, dif); + if (score == exact_match) + result = sk; + /* Only check first socket in chain */ + break; + } + + if (result) { + if (unlikely(!atomic_inc_not_zero_hint(&result->sk_refcnt, 2))) + result = NULL; + } + rcu_read_unlock(); + return result; } void udp_v4_early_demux(struct sk_buff *skb) @@ -1870,8 +1905,8 @@ void udp_v4_early_demux(struct sk_buff *skb) sk = __udp4_lib_mcast_demux_lookup(net, uh->dest, iph->daddr, uh->source, iph->saddr, dif); else if (skb->pkt_type == PACKET_HOST) - sk = __udp4_lib_lookup(net, iph->saddr, uh->source, - iph->daddr, uh->dest, dif, &udp_table); + sk = __udp4_lib_demux_lookup(net, uh->dest, iph->daddr, + uh->source, iph->saddr, dif); else return;