patch for 2.1.89 ipv[4,6] mcast

Bill Hawes (whawes@star.net)
Sat, 07 Mar 1998 18:21:22 -0500


This is a multi-part message in MIME format.
--------------26E36498D61A797ED07F4A07
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Following David Miller's suggestion, the attached patch removes the locking for
ipv4 and ipv6 mcast delivery. I've added a comment that the calls are made from
a BH context and don't require hash locking.

I've also added a minor performance enhancement by not freeing the cloned skb if
a socket is unable to queue it. Since some amount of work goes into cloning it,
and it can probably be used for the next socket, the code now keeps the cloned
skb and then checks at the end for any left over.

Regards,
Bill
--------------26E36498D61A797ED07F4A07
Content-Type: text/plain; charset=us-ascii; name="net_udp89-patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="net_udp89-patch"

--- linux-2.1.89/net/ipv4/udp.c.old Sat Mar 7 11:32:23 1998
+++ linux-2.1.89/net/ipv4/udp.c Sat Mar 7 15:53:51 1998
@@ -1033,17 +1033,18 @@

/*
* Multicasts and broadcasts go to each listener.
+ *
+ * Note: called only from the BH handler context,
+ * so we don't need to lock the hashes.
*/
static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh,
u32 saddr, u32 daddr)
{
struct sock *sk;
- int given = 0;

- SOCKHASH_LOCK();
sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)];
sk = udp_v4_mcast_next(sk, uh->dest, saddr, uh->source, daddr);
- if(sk) {
+ if (sk) {
struct sock *sknext = NULL;

do {
@@ -1058,10 +1059,7 @@
udp_deliver(sk, skb1);
sk = sknext;
} while(sknext);
- given = 1;
- }
- SOCKHASH_UNLOCK();
- if(!given)
+ } else
kfree_skb(skb);
return 0;
}
--- linux-2.1.89/net/ipv6/udp.c.old Sat Mar 7 11:32:23 1998
+++ linux-2.1.89/net/ipv6/udp.c Sat Mar 7 15:58:55 1998
@@ -448,32 +448,43 @@
return NULL;
}

+/*
+ * Note: called only from the BH handler context,
+ * so we don't need to lock the hashes.
+ */
static void udpv6_mcast_deliver(struct udphdr *uh,
struct in6_addr *saddr, struct in6_addr *daddr,
struct sk_buff *skb)
{
struct sock *sk, *sk2;
+ struct sk_buff *buff;

- SOCKHASH_LOCK();
sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)];
sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr);
- if(sk) {
- sk2 = sk;
- while((sk2 = udp_v6_mcast_next(sk2->next,
- uh->dest, saddr,
- uh->source, daddr))) {
- struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC);
- if (buff && sock_queue_rcv_skb(sk2, buff) < 0) {
- buff->sk = NULL;
- kfree_skb(buff);
- }
+ if (!sk)
+ goto free_skb;
+
+ buff = NULL;
+ sk2 = sk;
+ while((sk2 = udp_v6_mcast_next(sk2->next, uh->dest, saddr,
+ uh->source, daddr))) {
+ if (!buff) {
+ buff = skb_clone(skb, GFP_ATOMIC);
+ if (!buff)
+ continue;
}
+ if (sock_queue_rcv_skb(sk2, buff) >= 0)
+ buff = NULL;
+ }
+ if (buff) {
+ buff->sk = NULL;
+ kfree_skb(buff);
}
- if(!sk || sock_queue_rcv_skb(sk, skb) < 0) {
+ if (sock_queue_rcv_skb(sk, skb) < 0) {
+ free_skb:
skb->sk = NULL;
kfree_skb(skb);
}
- SOCKHASH_UNLOCK();
}

int udpv6_rcv(struct sk_buff *skb, struct device *dev,

--------------26E36498D61A797ED07F4A07--

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu