Some sysctl related code and data structures are never referenced when CONFIG_SYSCTL is not set. While this is usually harmless, it produces a build failure since sysctl shared variables exist, due to missing sysctl_vals symbol: ld: net/mpls/af_mpls.o: in function `mpls_platform_labels': af_mpls.c:(.text+0x162a): undefined reference to `sysctl_vals' ld: net/mpls/af_mpls.o:(.rodata+0x830): undefined reference to `sysctl_vals' ld: net/mpls/af_mpls.o:(.rodata+0x838): undefined reference to `sysctl_vals' ld: net/mpls/af_mpls.o:(.rodata+0x870): undefined reference to `sysctl_vals' Fix this by moving all sysctl related code under #ifdef CONFIG_SYSCTL Reported-by: Randy Dunlap <rdunlap@xxxxxxxxxxxxx> Signed-off-by: Matteo Croce <mcroce@xxxxxxxxxx> --- net/mpls/af_mpls.c | 389 ++++++++++++++++++++++++--------------------- 1 file changed, 204 insertions(+), 185 deletions(-) diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index c312741df2ce..5aacbf129ec5 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -37,9 +37,6 @@ #define MPLS_NEIGH_TABLE_UNSPEC (NEIGH_LINK_TABLE + 1) -static int label_limit = (1 << 20) - 1; -static int ttl_max = 255; - #if IS_ENABLED(CONFIG_NET_IP_TUNNEL) static size_t ipgre_mpls_encap_hlen(struct ip_tunnel_encap *e) { @@ -1179,31 +1176,6 @@ static int mpls_netconf_msgsize_devconf(int type) return size; } -static void mpls_netconf_notify_devconf(struct net *net, int event, - int type, struct mpls_dev *mdev) -{ - struct sk_buff *skb; - int err = -ENOBUFS; - - skb = nlmsg_new(mpls_netconf_msgsize_devconf(type), GFP_KERNEL); - if (!skb) - goto errout; - - err = mpls_netconf_fill_devconf(skb, mdev, 0, 0, event, 0, type); - if (err < 0) { - /* -EMSGSIZE implies BUG in mpls_netconf_msgsize_devconf() */ - WARN_ON(err == -EMSGSIZE); - kfree_skb(skb); - goto errout; - } - - rtnl_notify(skb, net, 0, RTNLGRP_MPLS_NETCONF, NULL, GFP_KERNEL); - return; -errout: - if (err < 0) - rtnl_set_sk_err(net, RTNLGRP_MPLS_NETCONF, err); -} - static const struct nla_policy devconf_mpls_policy[NETCONFA_MAX + 1] = { [NETCONFA_IFINDEX] = { .len = sizeof(int) }, }; @@ -1362,6 +1334,36 @@ static int mpls_netconf_dump_devconf(struct sk_buff *skb, #define MPLS_PERDEV_SYSCTL_OFFSET(field) \ (&((struct mpls_dev *)0)->field) +#ifdef CONFIG_SYSCTL + +static int label_limit = (1 << 20) - 1; +static int ttl_max = 255; + +static void mpls_netconf_notify_devconf(struct net *net, int event, + int type, struct mpls_dev *mdev) +{ + struct sk_buff *skb; + int err = -ENOBUFS; + + skb = nlmsg_new(mpls_netconf_msgsize_devconf(type), GFP_KERNEL); + if (!skb) + goto errout; + + err = mpls_netconf_fill_devconf(skb, mdev, 0, 0, event, 0, type); + if (err < 0) { + /* -EMSGSIZE implies BUG in mpls_netconf_msgsize_devconf() */ + WARN_ON(err == -EMSGSIZE); + kfree_skb(skb); + goto errout; + } + + rtnl_notify(skb, net, 0, RTNLGRP_MPLS_NETCONF, NULL, GFP_KERNEL); + return; +errout: + if (err < 0) + rtnl_set_sk_err(net, RTNLGRP_MPLS_NETCONF, err); +} + static int mpls_conf_proc(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) @@ -1445,6 +1447,173 @@ static void mpls_dev_sysctl_unregister(struct net_device *dev, mpls_netconf_notify_devconf(net, RTM_DELNETCONF, 0, mdev); } +static int resize_platform_label_table(struct net *net, size_t limit) +{ + size_t size = sizeof(struct mpls_route *) * limit; + size_t old_limit; + size_t cp_size; + struct mpls_route __rcu **labels = NULL, **old; + struct mpls_route *rt0 = NULL, *rt2 = NULL; + unsigned index; + + if (size) { + labels = kvzalloc(size, GFP_KERNEL); + if (!labels) + goto nolabels; + } + + /* In case the predefined labels need to be populated */ + if (limit > MPLS_LABEL_IPV4NULL) { + struct net_device *lo = net->loopback_dev; + rt0 = mpls_rt_alloc(1, lo->addr_len, 0); + if (IS_ERR(rt0)) + goto nort0; + RCU_INIT_POINTER(rt0->rt_nh->nh_dev, lo); + rt0->rt_protocol = RTPROT_KERNEL; + rt0->rt_payload_type = MPT_IPV4; + rt0->rt_ttl_propagate = MPLS_TTL_PROP_DEFAULT; + rt0->rt_nh->nh_via_table = NEIGH_LINK_TABLE; + rt0->rt_nh->nh_via_alen = lo->addr_len; + memcpy(__mpls_nh_via(rt0, rt0->rt_nh), lo->dev_addr, + lo->addr_len); + } + if (limit > MPLS_LABEL_IPV6NULL) { + struct net_device *lo = net->loopback_dev; + rt2 = mpls_rt_alloc(1, lo->addr_len, 0); + if (IS_ERR(rt2)) + goto nort2; + RCU_INIT_POINTER(rt2->rt_nh->nh_dev, lo); + rt2->rt_protocol = RTPROT_KERNEL; + rt2->rt_payload_type = MPT_IPV6; + rt2->rt_ttl_propagate = MPLS_TTL_PROP_DEFAULT; + rt2->rt_nh->nh_via_table = NEIGH_LINK_TABLE; + rt2->rt_nh->nh_via_alen = lo->addr_len; + memcpy(__mpls_nh_via(rt2, rt2->rt_nh), lo->dev_addr, + lo->addr_len); + } + + rtnl_lock(); + /* Remember the original table */ + old = rtnl_dereference(net->mpls.platform_label); + old_limit = net->mpls.platform_labels; + + /* Free any labels beyond the new table */ + for (index = limit; index < old_limit; index++) + mpls_route_update(net, index, NULL, NULL); + + /* Copy over the old labels */ + cp_size = size; + if (old_limit < limit) + cp_size = old_limit * sizeof(struct mpls_route *); + + memcpy(labels, old, cp_size); + + /* If needed set the predefined labels */ + if ((old_limit <= MPLS_LABEL_IPV6NULL) && + (limit > MPLS_LABEL_IPV6NULL)) { + RCU_INIT_POINTER(labels[MPLS_LABEL_IPV6NULL], rt2); + rt2 = NULL; + } + + if ((old_limit <= MPLS_LABEL_IPV4NULL) && + (limit > MPLS_LABEL_IPV4NULL)) { + RCU_INIT_POINTER(labels[MPLS_LABEL_IPV4NULL], rt0); + rt0 = NULL; + } + + /* Update the global pointers */ + net->mpls.platform_labels = limit; + rcu_assign_pointer(net->mpls.platform_label, labels); + + rtnl_unlock(); + + mpls_rt_free(rt2); + mpls_rt_free(rt0); + + if (old) { + synchronize_rcu(); + kvfree(old); + } + return 0; + +nort2: + mpls_rt_free(rt0); +nort0: + kvfree(labels); +nolabels: + return -ENOMEM; +} + +static int mpls_platform_labels(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct net *net = table->data; + int platform_labels = net->mpls.platform_labels; + int ret; + struct ctl_table tmp = { + .procname = table->procname, + .data = &platform_labels, + .maxlen = sizeof(int), + .mode = table->mode, + .extra1 = SYSCTL_ZERO, + .extra2 = &label_limit, + }; + + ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); + + if (write && ret == 0) + ret = resize_platform_label_table(net, platform_labels); + + return ret; +} + +#define MPLS_NS_SYSCTL_OFFSET(field) \ + (&((struct net *)0)->field) + +static const struct ctl_table mpls_table[] = { + { + .procname = "platform_labels", + .data = NULL, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = mpls_platform_labels, + }, + { + .procname = "ip_ttl_propagate", + .data = MPLS_NS_SYSCTL_OFFSET(mpls.ip_ttl_propagate), + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, + { + .procname = "default_ttl", + .data = MPLS_NS_SYSCTL_OFFSET(mpls.default_ttl), + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ONE, + .extra2 = &ttl_max, + }, + { } +}; + +#else + +static int mpls_dev_sysctl_register(struct net_device *dev, + struct mpls_dev *mdev) +{ + return 0; +} + +static void mpls_dev_sysctl_unregister(struct net_device *dev, + struct mpls_dev *mdev) +{ +} + +#endif + static struct mpls_dev *mpls_add_dev(struct net_device *dev) { struct mpls_dev *mdev; @@ -2497,168 +2666,12 @@ static int mpls_getroute(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, return err; } -static int resize_platform_label_table(struct net *net, size_t limit) -{ - size_t size = sizeof(struct mpls_route *) * limit; - size_t old_limit; - size_t cp_size; - struct mpls_route __rcu **labels = NULL, **old; - struct mpls_route *rt0 = NULL, *rt2 = NULL; - unsigned index; - - if (size) { - labels = kvzalloc(size, GFP_KERNEL); - if (!labels) - goto nolabels; - } - - /* In case the predefined labels need to be populated */ - if (limit > MPLS_LABEL_IPV4NULL) { - struct net_device *lo = net->loopback_dev; - rt0 = mpls_rt_alloc(1, lo->addr_len, 0); - if (IS_ERR(rt0)) - goto nort0; - RCU_INIT_POINTER(rt0->rt_nh->nh_dev, lo); - rt0->rt_protocol = RTPROT_KERNEL; - rt0->rt_payload_type = MPT_IPV4; - rt0->rt_ttl_propagate = MPLS_TTL_PROP_DEFAULT; - rt0->rt_nh->nh_via_table = NEIGH_LINK_TABLE; - rt0->rt_nh->nh_via_alen = lo->addr_len; - memcpy(__mpls_nh_via(rt0, rt0->rt_nh), lo->dev_addr, - lo->addr_len); - } - if (limit > MPLS_LABEL_IPV6NULL) { - struct net_device *lo = net->loopback_dev; - rt2 = mpls_rt_alloc(1, lo->addr_len, 0); - if (IS_ERR(rt2)) - goto nort2; - RCU_INIT_POINTER(rt2->rt_nh->nh_dev, lo); - rt2->rt_protocol = RTPROT_KERNEL; - rt2->rt_payload_type = MPT_IPV6; - rt2->rt_ttl_propagate = MPLS_TTL_PROP_DEFAULT; - rt2->rt_nh->nh_via_table = NEIGH_LINK_TABLE; - rt2->rt_nh->nh_via_alen = lo->addr_len; - memcpy(__mpls_nh_via(rt2, rt2->rt_nh), lo->dev_addr, - lo->addr_len); - } - - rtnl_lock(); - /* Remember the original table */ - old = rtnl_dereference(net->mpls.platform_label); - old_limit = net->mpls.platform_labels; - - /* Free any labels beyond the new table */ - for (index = limit; index < old_limit; index++) - mpls_route_update(net, index, NULL, NULL); - - /* Copy over the old labels */ - cp_size = size; - if (old_limit < limit) - cp_size = old_limit * sizeof(struct mpls_route *); - - memcpy(labels, old, cp_size); - - /* If needed set the predefined labels */ - if ((old_limit <= MPLS_LABEL_IPV6NULL) && - (limit > MPLS_LABEL_IPV6NULL)) { - RCU_INIT_POINTER(labels[MPLS_LABEL_IPV6NULL], rt2); - rt2 = NULL; - } - - if ((old_limit <= MPLS_LABEL_IPV4NULL) && - (limit > MPLS_LABEL_IPV4NULL)) { - RCU_INIT_POINTER(labels[MPLS_LABEL_IPV4NULL], rt0); - rt0 = NULL; - } - - /* Update the global pointers */ - net->mpls.platform_labels = limit; - rcu_assign_pointer(net->mpls.platform_label, labels); - - rtnl_unlock(); - - mpls_rt_free(rt2); - mpls_rt_free(rt0); - - if (old) { - synchronize_rcu(); - kvfree(old); - } - return 0; - -nort2: - mpls_rt_free(rt0); -nort0: - kvfree(labels); -nolabels: - return -ENOMEM; -} - -static int mpls_platform_labels(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - struct net *net = table->data; - int platform_labels = net->mpls.platform_labels; - int ret; - struct ctl_table tmp = { - .procname = table->procname, - .data = &platform_labels, - .maxlen = sizeof(int), - .mode = table->mode, - .extra1 = SYSCTL_ZERO, - .extra2 = &label_limit, - }; - - ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); - - if (write && ret == 0) - ret = resize_platform_label_table(net, platform_labels); - - return ret; -} - -#define MPLS_NS_SYSCTL_OFFSET(field) \ - (&((struct net *)0)->field) - -static const struct ctl_table mpls_table[] = { - { - .procname = "platform_labels", - .data = NULL, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = mpls_platform_labels, - }, - { - .procname = "ip_ttl_propagate", - .data = MPLS_NS_SYSCTL_OFFSET(mpls.ip_ttl_propagate), - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = SYSCTL_ZERO, - .extra2 = SYSCTL_ONE, - }, - { - .procname = "default_ttl", - .data = MPLS_NS_SYSCTL_OFFSET(mpls.default_ttl), - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = SYSCTL_ONE, - .extra2 = &ttl_max, - }, - { } -}; - static int mpls_net_init(struct net *net) { +#ifdef CONFIG_SYSCTL struct ctl_table *table; int i; - net->mpls.platform_labels = 0; - net->mpls.platform_label = NULL; - net->mpls.ip_ttl_propagate = 1; - net->mpls.default_ttl = 255; - table = kmemdup(mpls_table, sizeof(mpls_table), GFP_KERNEL); if (table == NULL) return -ENOMEM; @@ -2674,6 +2687,12 @@ static int mpls_net_init(struct net *net) kfree(table); return -ENOMEM; } +#endif + + net->mpls.platform_labels = 0; + net->mpls.platform_label = NULL; + net->mpls.ip_ttl_propagate = 1; + net->mpls.default_ttl = 255; return 0; } -- 2.21.0