]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/ipv4/igmp.c
igmp: refine skb allocations
[net-next-2.6.git] / net / ipv4 / igmp.c
index afb1e82a59f9acea63d1037f0ca5414cb8df58bf..e0e77e297de32148356da4c309856dacabee2387 100644 (file)
@@ -300,6 +300,8 @@ igmp_scount(struct ip_mc_list *pmc, int type, int gdeleted, int sdeleted)
        return scount;
 }
 
+#define igmp_skb_size(skb) (*(unsigned int *)((skb)->cb))
+
 static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
 {
        struct sk_buff *skb;
@@ -308,9 +310,16 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
        struct igmpv3_report *pig;
        struct net *net = dev_net(dev);
 
-       skb = alloc_skb(size + LL_ALLOCATED_SPACE(dev), GFP_ATOMIC);
-       if (skb == NULL)
-               return NULL;
+       while (1) {
+               skb = alloc_skb(size + LL_ALLOCATED_SPACE(dev),
+                               GFP_ATOMIC | __GFP_NOWARN);
+               if (skb)
+                       break;
+               size >>= 1;
+               if (size < 256)
+                       return NULL;
+       }
+       igmp_skb_size(skb) = size;
 
        {
                struct flowi fl = { .oif = dev->ifindex,
@@ -399,7 +408,7 @@ static struct sk_buff *add_grhead(struct sk_buff *skb, struct ip_mc_list *pmc,
        return skb;
 }
 
-#define AVAILABLE(skb) ((skb) ? ((skb)->dev ? (skb)->dev->mtu - (skb)->len : \
+#define AVAILABLE(skb) ((skb) ? ((skb)->dev ? igmp_skb_size(skb) - (skb)->len : \
        skb_tailroom(skb)) : 0)
 
 static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc,
@@ -1267,26 +1276,32 @@ EXPORT_SYMBOL(ip_mc_inc_group);
 
 /*
  *     Resend IGMP JOIN report; used for bonding.
+ *     Called with rcu_read_lock()
  */
-void ip_mc_rejoin_group(struct ip_mc_list *im)
+void ip_mc_rejoin_groups(struct in_device *in_dev)
 {
 #ifdef CONFIG_IP_MULTICAST
-       struct in_device *in_dev = im->interface;
+       struct ip_mc_list *im;
+       int type;
 
-       if (im->multiaddr == IGMP_ALL_HOSTS)
-               return;
+       for_each_pmc_rcu(in_dev, im) {
+               if (im->multiaddr == IGMP_ALL_HOSTS)
+                       continue;
 
-       /* a failover is happening and switches
-        * must be notified immediately */
-       if (IGMP_V1_SEEN(in_dev))
-               igmp_send_report(in_dev, im, IGMP_HOST_MEMBERSHIP_REPORT);
-       else if (IGMP_V2_SEEN(in_dev))
-               igmp_send_report(in_dev, im, IGMPV2_HOST_MEMBERSHIP_REPORT);
-       else
-               igmp_send_report(in_dev, im, IGMPV3_HOST_MEMBERSHIP_REPORT);
+               /* a failover is happening and switches
+                * must be notified immediately
+                */
+               if (IGMP_V1_SEEN(in_dev))
+                       type = IGMP_HOST_MEMBERSHIP_REPORT;
+               else if (IGMP_V2_SEEN(in_dev))
+                       type = IGMPV2_HOST_MEMBERSHIP_REPORT;
+               else
+                       type = IGMPV3_HOST_MEMBERSHIP_REPORT;
+               igmp_send_report(in_dev, im, type);
+       }
 #endif
 }
-EXPORT_SYMBOL(ip_mc_rejoin_group);
+EXPORT_SYMBOL(ip_mc_rejoin_groups);
 
 /*
  *     A socket has left a multicast group on device dev