[RFC] Remove more code when IP_MULTICAST=n

The idea of this patch originates from a patch by Matt Mackall in the
Linux Tiny project, adding a new CONFIG_IGMP option to compile out
net/ipv4/igmp.o on embedded devices running applications that don't
care about multicast.

After discussion with David Woodhouse, we wondered why introducing a
new option is necessary: couldn't all the IGMP code be compiled out
when IP_MULTICAST=n (IP_MULTICAST is an already existing option) ?

This patch implements this idea: net/ipv4/igmp.o and multicast-related
socket operations get compiled out when IP_MULTICAST=N. However, my
understanding of the network stack internals is too limited to be sure
that it actually makes sense, which is why I'm sending this patch
simply for comments on what could be done. In particular :

 * I'm not sure why net/ipv4/igmp.o was needed when IP_MULTICAST=n ;

 * I'm not sure that returning -ENOPROTOOPT for socket operations
   related to multicast management is correct when IP_MULTICAST=n.

For reference, the size savings are as follows, before and after the
patch, for a x86 kernel with IP_MULTICAST=n.

   text    data     bss     dec     hex filename
2034992  157896  270336 2463224  2595f8 vmlinux
2024260  157856  270336 2452452  256be4 vmlinux.new
 -10732     -40       0  -10772   -2A14 +/-

Remaining to fix:

 * Virtual server support, using ip_mc_join_group() in
   ipv4/ipvs/ip_vs_sync.c

Signed-off-by: Thomas Petazzoni <[EMAIL PROTECTED]>

---
 include/linux/igmp.h       |   11 +++++++++
 net/ipv4/Makefile          |    3 +-
 net/ipv4/af_inet.c         |    2 -
 net/ipv4/igmp.c            |   50 +--------------------------------------------
 net/ipv4/ip_sockglue.c     |    4 +++
 net/ipv4/sysctl_net_ipv4.c |    3 --
 6 files changed, 20 insertions(+), 53 deletions(-)

Index: linuxdev/include/linux/igmp.h
===================================================================
--- linuxdev.orig/include/linux/igmp.h
+++ linuxdev/include/linux/igmp.h
@@ -215,6 +215,7 @@
 #define IGMPV3_QQIC(value) IGMPV3_EXP(0x80, 4, 3, value)
 #define IGMPV3_MRC(value) IGMPV3_EXP(0x80, 4, 3, value)
 
+#ifdef CONFIG_IP_MULTICAST
 extern int ip_check_mc(struct in_device *dev, __be32 mc_addr, __be32 src_addr, 
u16 proto);
 extern int igmp_rcv(struct sk_buff *);
 extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr);
@@ -235,6 +236,16 @@
 extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr);
 extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr);
 extern void ip_mc_rejoin_group(struct ip_mc_list *im);
+#else
+#define ip_check_mc(a, b, c, d) ({ 0; })
+#define ip_mc_sf_allow(a, b, c, d) ({ 1; })
+#define ip_mc_init_dev(a) ({ })
+#define ip_mc_up(a) ({ })
+#define ip_mc_down(a) ({ })
+#define ip_mc_destroy_dev(a) ({ })
+#define ip_mc_init_dev(a) ({ })
+#define ip_mc_drop_socket(a) ({ })
+#endif
 
 #endif
 #endif
Index: linuxdev/net/ipv4/Makefile
===================================================================
--- linuxdev.orig/net/ipv4/Makefile
+++ linuxdev/net/ipv4/Makefile
@@ -9,7 +9,7 @@
             tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \
             tcp_minisocks.o tcp_cong.o \
             datagram.o raw.o udp.o udplite.o \
-            arp.o icmp.o devinet.o af_inet.o  igmp.o \
+            arp.o icmp.o devinet.o af_inet.o \
             fib_frontend.o fib_semantics.o \
             inet_fragment.o
 
@@ -19,6 +19,7 @@
 obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o
 obj-$(CONFIG_IP_MROUTE) += ipmr.o
+obj-$(CONFIG_IP_MULTICAST) += igmp.o
 obj-$(CONFIG_NET_IPIP) += ipip.o
 obj-$(CONFIG_NET_IPGRE) += ip_gre.o
 obj-$(CONFIG_SYN_COOKIES) += syncookies.o
Index: linuxdev/net/ipv4/af_inet.c
===================================================================
--- linuxdev.orig/net/ipv4/af_inet.c
+++ linuxdev/net/ipv4/af_inet.c
@@ -115,8 +115,6 @@
 #include <linux/mroute.h>
 #endif
 
-extern void ip_mc_drop_socket(struct sock *sk);
-
 /* The inetsw table contains everything that inet_create needs to
  * build a new socket.
  */
Index: linuxdev/net/ipv4/igmp.c
===================================================================
--- linuxdev.orig/net/ipv4/igmp.c
+++ linuxdev/net/ipv4/igmp.c
@@ -108,7 +108,6 @@
 #define IP_MAX_MEMBERSHIPS     20
 #define IP_MAX_MSF             10
 
-#ifdef CONFIG_IP_MULTICAST
 /* Parameter names and values are taken from igmp-v2-06 draft */
 
 #define IGMP_V1_Router_Present_Timeout         (400*HZ)
@@ -143,7 +142,6 @@
 static void igmpv3_clear_delrec(struct in_device *in_dev);
 static int sf_setstate(struct ip_mc_list *pmc);
 static void sf_markstate(struct ip_mc_list *pmc);
-#endif
 static void ip_mc_clear_src(struct ip_mc_list *pmc);
 static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
                         int sfcount, __be32 *psfsrc, int delta);
@@ -156,8 +154,6 @@
        }
 }
 
-#ifdef CONFIG_IP_MULTICAST
-
 /*
  *     Timer management
  */
@@ -975,8 +971,6 @@
        return 0;
 }
 
-#endif
-
 
 /*
  *     Add a filter to a device
@@ -1011,7 +1005,6 @@
                dev_mc_delete(dev,buf,dev->addr_len,0);
 }
 
-#ifdef CONFIG_IP_MULTICAST
 /*
  * deleted ip_mc_list manipulation
  */
@@ -1112,21 +1105,17 @@
        }
        read_unlock(&in_dev->mc_list_lock);
 }
-#endif
 
 static void igmp_group_dropped(struct ip_mc_list *im)
 {
        struct in_device *in_dev = im->interface;
-#ifdef CONFIG_IP_MULTICAST
        int reporter;
-#endif
 
        if (im->loaded) {
                im->loaded = 0;
                ip_mc_filter_del(in_dev, im->multiaddr);
        }
 
-#ifdef CONFIG_IP_MULTICAST
        if (im->multiaddr == IGMP_ALL_HOSTS)
                return;
 
@@ -1147,7 +1136,6 @@
                igmp_ifc_event(in_dev);
        }
 done:
-#endif
        ip_mc_clear_src(im);
 }
 
@@ -1160,7 +1148,6 @@
                ip_mc_filter_add(in_dev, im->multiaddr);
        }
 
-#ifdef CONFIG_IP_MULTICAST
        if (im->multiaddr == IGMP_ALL_HOSTS)
                return;
 
@@ -1177,7 +1164,6 @@
        im->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
                IGMP_Unsolicited_Report_Count;
        igmp_ifc_event(in_dev);
-#endif
 }
 
 
@@ -1224,21 +1210,17 @@
        im->crcount = 0;
        atomic_set(&im->refcnt, 1);
        spin_lock_init(&im->lock);
-#ifdef CONFIG_IP_MULTICAST
        im->tm_running=0;
        setup_timer(&im->timer, &igmp_timer_expire, (unsigned long)im);
        im->unsolicit_count = IGMP_Unsolicited_Report_Count;
        im->reporter = 0;
        im->gsquery = 0;
-#endif
        im->loaded = 0;
        write_lock_bh(&in_dev->mc_list_lock);
        im->next=in_dev->mc_list;
        in_dev->mc_list=im;
        write_unlock_bh(&in_dev->mc_list_lock);
-#ifdef CONFIG_IP_MULTICAST
        igmpv3_del_delrec(in_dev, im->multiaddr);
-#endif
        igmp_group_added(im);
        if (!in_dev->dead)
                ip_rt_multicast_event(in_dev);
@@ -1251,7 +1233,6 @@
  */
 void ip_mc_rejoin_group(struct ip_mc_list *im)
 {
-#ifdef CONFIG_IP_MULTICAST
        struct in_device *in_dev = im->interface;
 
        if (im->multiaddr == IGMP_ALL_HOSTS)
@@ -1265,7 +1246,6 @@
        im->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
                IGMP_Unsolicited_Report_Count;
        igmp_ifc_event(in_dev);
-#endif
 }
 
 /*
@@ -1314,7 +1294,6 @@
        for (i=in_dev->mc_list; i; i=i->next)
                igmp_group_dropped(i);
 
-#ifdef CONFIG_IP_MULTICAST
        in_dev->mr_ifc_count = 0;
        if (del_timer(&in_dev->mr_ifc_timer))
                __in_dev_put(in_dev);
@@ -1322,7 +1301,6 @@
        if (del_timer(&in_dev->mr_gq_timer))
                __in_dev_put(in_dev);
        igmpv3_clear_delrec(in_dev);
-#endif
 
        ip_mc_dec_group(in_dev, IGMP_ALL_HOSTS);
 }
@@ -1335,7 +1313,6 @@
                return;
 
        in_dev->mc_tomb = NULL;
-#ifdef CONFIG_IP_MULTICAST
        in_dev->mr_gq_running = 0;
        setup_timer(&in_dev->mr_gq_timer, igmp_gq_timer_expire,
                        (unsigned long)in_dev);
@@ -1343,7 +1320,6 @@
        setup_timer(&in_dev->mr_ifc_timer, igmp_ifc_timer_expire,
                        (unsigned long)in_dev);
        in_dev->mr_qrv = IGMP_Unsolicited_Report_Count;
-#endif
 
        rwlock_init(&in_dev->mc_list_lock);
        spin_lock_init(&in_dev->mc_tomb_lock);
@@ -1455,16 +1431,14 @@
                ip_rt_multicast_event(pmc->interface);
        }
        if (!psf->sf_count[MCAST_INCLUDE] && !psf->sf_count[MCAST_EXCLUDE]) {
-#ifdef CONFIG_IP_MULTICAST
                struct in_device *in_dev = pmc->interface;
-#endif
 
                /* no more filters for this source */
                if (psf_prev)
                        psf_prev->sf_next = psf->sf_next;
                else
                        pmc->sources = psf->sf_next;
-#ifdef CONFIG_IP_MULTICAST
+
                if (psf->sf_oldin &&
                    !IGMP_V1_SEEN(in_dev) && !IGMP_V2_SEEN(in_dev)) {
                        psf->sf_crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
@@ -1473,15 +1447,13 @@
                        pmc->tomb = psf;
                        rv = 1;
                } else
-#endif
+
                        kfree(psf);
        }
        return rv;
 }
 
-#ifndef CONFIG_IP_MULTICAST
 #define igmp_ifc_event(x)      do { } while (0)
-#endif
 
 static int ip_mc_del_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
                         int sfcount, __be32 *psfsrc, int delta)
@@ -1504,9 +1476,7 @@
        }
        spin_lock_bh(&pmc->lock);
        read_unlock(&in_dev->mc_list_lock);
-#ifdef CONFIG_IP_MULTICAST
        sf_markstate(pmc);
-#endif
        if (!delta) {
                err = -EINVAL;
                if (!pmc->sfcount[sfmode])
@@ -1524,13 +1494,10 @@
        if (pmc->sfmode == MCAST_EXCLUDE &&
            pmc->sfcount[MCAST_EXCLUDE] == 0 &&
            pmc->sfcount[MCAST_INCLUDE]) {
-#ifdef CONFIG_IP_MULTICAST
                struct ip_sf_list *psf;
-#endif
 
                /* filter mode change */
                pmc->sfmode = MCAST_INCLUDE;
-#ifdef CONFIG_IP_MULTICAST
                pmc->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
                        IGMP_Unsolicited_Report_Count;
                in_dev->mr_ifc_count = pmc->crcount;
@@ -1539,7 +1506,6 @@
                igmp_ifc_event(pmc->interface);
        } else if (sf_setstate(pmc) || changerec) {
                igmp_ifc_event(pmc->interface);
-#endif
        }
 out_unlock:
        spin_unlock_bh(&pmc->lock);
@@ -1577,7 +1543,6 @@
        return 0;
 }
 
-#ifdef CONFIG_IP_MULTICAST
 static void sf_markstate(struct ip_mc_list *pmc)
 {
        struct ip_sf_list *psf;
@@ -1651,7 +1616,6 @@
        }
        return rv;
 }
-#endif
 
 /*
  * Add multicast source filter list to the interface list
@@ -1678,9 +1642,7 @@
        spin_lock_bh(&pmc->lock);
        read_unlock(&in_dev->mc_list_lock);
 
-#ifdef CONFIG_IP_MULTICAST
        sf_markstate(pmc);
-#endif
        isexclude = pmc->sfmode == MCAST_EXCLUDE;
        if (!delta)
                pmc->sfcount[sfmode]++;
@@ -1697,17 +1659,14 @@
                for (j=0; j<i; j++)
                        (void) ip_mc_del1_src(pmc, sfmode, &psfsrc[i]);
        } else if (isexclude != (pmc->sfcount[MCAST_EXCLUDE] != 0)) {
-#ifdef CONFIG_IP_MULTICAST
                struct ip_sf_list *psf;
                in_dev = pmc->interface;
-#endif
 
                /* filter mode change */
                if (pmc->sfcount[MCAST_EXCLUDE])
                        pmc->sfmode = MCAST_EXCLUDE;
                else if (pmc->sfcount[MCAST_INCLUDE])
                        pmc->sfmode = MCAST_INCLUDE;
-#ifdef CONFIG_IP_MULTICAST
                /* else no filters; keep old mode for reports */
 
                pmc->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
@@ -1718,7 +1677,6 @@
                igmp_ifc_event(in_dev);
        } else if (sf_setstate(pmc)) {
                igmp_ifc_event(in_dev);
-#endif
        }
        spin_unlock_bh(&pmc->lock);
        return err;
@@ -2404,13 +2362,9 @@
                struct ip_mc_list *im = (struct ip_mc_list *)v;
                struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
                char   *querier;
-#ifdef CONFIG_IP_MULTICAST
                querier = IGMP_V1_SEEN(state->in_dev) ? "V1" :
                          IGMP_V2_SEEN(state->in_dev) ? "V2" :
                          "V3";
-#else
-               querier = "NONE";
-#endif
 
                if (state->in_dev->mc_list == im) {
                        seq_printf(seq, "%d\t%-10s: %5d %7s\n",
Index: linuxdev/net/ipv4/ip_sockglue.c
===================================================================
--- linuxdev.orig/net/ipv4/ip_sockglue.c
+++ linuxdev/net/ipv4/ip_sockglue.c
@@ -544,6 +544,7 @@
                if (!val)
                        skb_queue_purge(&sk->sk_error_queue);
                break;
+#ifdef CONFIG_IP_MULTICAST
        case IP_MULTICAST_TTL:
                if (sk->sk_type == SOCK_STREAM)
                        goto e_inval;
@@ -860,6 +861,7 @@
                kfree(gsf);
                break;
        }
+#endif
        case IP_ROUTER_ALERT:
                err = ip_ra_control(sk, val ? 1 : 0, NULL);
                break;
@@ -1044,6 +1046,7 @@
        case IP_RECVERR:
                val = inet->recverr;
                break;
+#ifdef CONFIG_IP_MULTICAST
        case IP_MULTICAST_TTL:
                val = inet->mc_ttl;
                break;
@@ -1099,6 +1102,7 @@
                release_sock(sk);
                return err;
        }
+#endif
        case IP_PKTOPTIONS:
        {
                struct msghdr msg;
Index: linuxdev/net/ipv4/sysctl_net_ipv4.c
===================================================================
--- linuxdev.orig/net/ipv4/sysctl_net_ipv4.c
+++ linuxdev/net/ipv4/sysctl_net_ipv4.c
@@ -411,8 +411,6 @@
                .mode           = 0644,
                .proc_handler   = &proc_dointvec
        },
-
-#endif
        {
                .ctl_name       = NET_IPV4_IGMP_MAX_MSF,
                .procname       = "igmp_max_msf",
@@ -421,6 +419,7 @@
                .mode           = 0644,
                .proc_handler   = &proc_dointvec
        },
+#endif
        {
                .ctl_name       = NET_IPV4_INET_PEER_THRESHOLD,
                .procname       = "inet_peer_threshold",


-- 
Thomas Petazzoni, Free Electrons
Kernel, drivers and embedded Linux development,
consulting, training and support.
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe linux-embedded" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to