IPv6 FIB configuration conversions
Subsystems (3)
PATCH 1/1 IPv6 FIB configuration conversions
Same approach as for IPv4, simplifies the interface and makes it extendable without breaking the ioctl interface.
Same memory corruption fixes in RTM_GETROUTE as for IPv4.
PATCH 1/5 route: Simplify ip6_del_rt()
Provide a simple ip6_del_rt() for the majority of users and an alternative for the exception via netlink. Avoids code obfuscation.
include/net/ip6_route.h +1 -4
@@ -69,10 +69,7 @@ extern int ip6_ins_rt(struct rt6_info struct nlmsghdr *,void *rtattr, struct netlink_skb_parms *req); -extern int ip6_del_rt (struct rt6_info *, -struct nlmsghdr *, -void *rtattr, -struct netlink_skb_parms *req); +extern int ip6_del_rt (struct rt6_info *); extern int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev,
net/ipv6/addrconf.c +3 -3
@@ -736,7 +736,7 @@ static void ipv6_del_addr(struct inet6_iif (rt && ((rt->rt6i_flags & (RTF_GATEWAY |RTF_DEFAULT )) ==0 )) {if (onlink ==0 ) { -ip6_del_rt (rt,NULL ,NULL ,NULL ); +ip6_del_rt (rt); rt =NULL ; }else if (!(rt->rt6i_flags &RTF_EXPIRES )) { rt->rt6i_expires = expires;
@@ -1662,7 +1662,7 @@ void addrconf_prefix_rcv(struct net_deviif (rt && ((rt->rt6i_flags & (RTF_GATEWAY |RTF_DEFAULT )) ==0 )) {if (rt->rt6i_flags&RTF_EXPIRES ) {if (valid_lft ==0 ) { -ip6_del_rt (rt,NULL ,NULL ,NULL ); +ip6_del_rt (rt); rt =NULL ; }else { rt->rt6i_expires = jiffies + rt_expires;
@@ -3557,7 +3557,7 @@ static void __ipv6_ifa_notify(int event,addrconf_leave_anycast (ifp);addrconf_leave_solict (ifp->idev, &ifp->addr);dst_hold (&ifp->rt->u.dst); -if (ip6_del_rt (ifp->rt,NULL ,NULL ,NULL )) +if (ip6_del_rt (ifp->rt))dst_free (&ifp->rt->u.dst);break ; }
net/ipv6/ndisc.c +2 -2
@@ -961,7 +961,7 @@ static void ndisc_recv_na(struct sk_buffstruct rt6_info *rt; rt =rt6_get_dflt_router (saddr, dev);if (rt) -ip6_del_rt (rt,NULL ,NULL ,NULL ); +ip6_del_rt (rt); } out:
@@ -1114,7 +1114,7 @@ static void ndisc_router_discovery(strucif (rt && lifetime ==0 ) {neigh_clone (neigh); -ip6_del_rt (rt,NULL ,NULL ,NULL ); +ip6_del_rt (rt); rt =NULL ; }
net/ipv6/route.c +12 -6
@@ -457,7 +457,7 @@ int rt6_route_rcv(struct net_device *dev rt =rt6_get_route_info (prefix, rinfo->prefix_len, gwaddr, dev->ifindex);if (rt && !lifetime) { -ip6_del_rt (rt,NULL ,NULL ,NULL ); +ip6_del_rt (rt); rt =NULL ; }
@@ -813,7 +813,7 @@ static struct dst_entry *ip6_negative_adif (rt) {if (rt->rt6i_flags &RTF_CACHE ) -ip6_del_rt (rt,NULL ,NULL ,NULL ); +ip6_del_rt (rt);else dst_release (dst); }
@@ -1218,7 +1218,8 @@ out:return err; } -int ip6_del_rt (struct rt6_info *rt,struct nlmsghdr *nlh,void *_rtattr,struct netlink_skb_parms *req) +static int __ip6_del_rt (struct rt6_info *rt,struct nlmsghdr *nlh, +void *_rtattr,struct netlink_skb_parms *req) {int err;struct fib6_table *table;
@@ -1237,6 +1238,11 @@ int ip6_del_rt(struct rt6_info *rt, strureturn err; } +int ip6_del_rt (struct rt6_info *rt) +{ +return __ip6_del_rt (rt,NULL ,NULL ,NULL ); +} +static int ip6_route_del (struct in6_rtmsg *rtmsg,struct nlmsghdr *nlh,void *_rtattr,struct netlink_skb_parms *req,u32 table_id)
@@ -1271,7 +1277,7 @@ static int ip6_route_del(struct in6_rtmsdst_hold (&rt->u.dst);read_unlock_bh (&table->tb6_lock); -return ip6_del_rt (rt, nlh, _rtattr, req); +return __ip6_del_rt (rt, nlh, _rtattr, req); } }read_unlock_bh (&table->tb6_lock);
@@ -1395,7 +1401,7 @@ restart:call_netevent_notifiers (NETEVENT_REDIRECT , &netevent);if (rt->rt6i_flags&RTF_CACHE ) { -ip6_del_rt (rt,NULL ,NULL ,NULL ); +ip6_del_rt (rt);return ; }
@@ -1631,7 +1637,7 @@ restart:if (rt->rt6i_flags & (RTF_DEFAULT |RTF_ADDRCONF )) {dst_hold (&rt->u.dst);read_unlock_bh (&table->tb6_lock); -ip6_del_rt (rt,NULL ,NULL ,NULL ); +ip6_del_rt (rt); goto restart; } }
PATCH 2/5 route: Simplify ip6_ins_rt()
In reply to Thomas GrafProvide a simple ip6_ins_rt() for the majority of users and an alternative for the exception via netlink. Avoids code obfuscation.
include/net/ip6_route.h +1 -4
@@ -65,10 +65,7 @@ extern int ip6_route_add(struct in6_rtvoid *rtattr, struct netlink_skb_parms *req, u32 table_id); -extern int ip6_ins_rt (struct rt6_info *, -struct nlmsghdr *, -void *rtattr, -struct netlink_skb_parms *req); +extern int ip6_ins_rt (struct rt6_info *);extern int ip6_del_rt (struct rt6_info *); extern int ip6_rt_addr_add(struct in6_addr *addr,
net/ipv6/route.c +12 -7
@@ -546,8 +546,8 @@ struct rt6_info *rt6_lookup(struct in6_abe destroyed. */ -int ip6_ins_rt (struct rt6_info *rt,struct nlmsghdr *nlh, -void *_rtattr,struct netlink_skb_parms *req) +static int __ip6_ins_rt (struct rt6_info *rt,struct nlmsghdr *nlh, +void *_rtattr,struct netlink_skb_parms *req) {int err;struct fib6_table *table;
@@ -560,6 +560,11 @@ int ip6_ins_rt(struct rt6_info *rt, strureturn err; } +int ip6_ins_rt (struct rt6_info *rt) +{ +return __ip6_ins_rt (rt,NULL ,NULL ,NULL ); +} +static struct rt6_info *rt6_alloc_cow (struct rt6_info *ort,struct in6_addr *daddr,struct in6_addr *saddr) {
@@ -657,7 +662,7 @@ restart:dst_hold (&rt->u.dst);if (nrt) { - err =ip6_ins_rt (nrt,NULL ,NULL ,NULL ); + err =ip6_ins_rt (nrt);if (!err) goto out2; }
@@ -752,7 +757,7 @@ restart:dst_hold (&rt->u.dst);if (nrt) { - err =ip6_ins_rt (nrt,NULL ,NULL ,NULL ); + err =ip6_ins_rt (nrt);if (!err) goto out2; }
@@ -1206,7 +1211,7 @@ install_route: rt->u.dst.dev = dev; rt->rt6i_idev = idev; rt->rt6i_table = table; -return ip6_ins_rt (rt, nlh, _rtattr, req); +return __ip6_ins_rt (rt, nlh, _rtattr, req); out:if (dev)
@@ -1393,7 +1398,7 @@ restart: nrt->u.dst.metrics[RTAX_MTU -1 ] =ipv6_get_mtu (neigh->dev); nrt->u.dst.metrics[RTAX_ADVMSS -1 ] =ipv6_advmss (dst_mtu (&nrt->u.dst)); -if (ip6_ins_rt (nrt,NULL ,NULL ,NULL )) +if (ip6_ins_rt (nrt)) goto out; netevent.old = &rt->u.dst;
@@ -1483,7 +1488,7 @@ void rt6_pmtu_discovery(struct in6_addrdst_set_expires (&nrt->u.dst, ip6_rt_mtu_expires); nrt->rt6i_flags |=RTF_DYNAMIC |RTF_EXPIRES ; -ip6_ins_rt (nrt,NULL ,NULL ,NULL ); +ip6_ins_rt (nrt); } out:dst_release (&rt->u.dst);
net/ipv6/addrconf.c +1 -1
@@ -3548,7 +3548,7 @@ static void __ipv6_ifa_notify(int event,switch (event) {case RTM_NEWADDR : -ip6_ins_rt (ifp->rt,NULL ,NULL ,NULL ); +ip6_ins_rt (ifp->rt);if (ifp->idev->cnf.forwarding)addrconf_join_anycast (ifp);break ;
net/ipv6/anycast.c +1 -1
@@ -335,7 +335,7 @@ int ipv6_dev_ac_inc(struct net_device *dwrite_unlock_bh (&idev->lock);dst_hold (&rt->u.dst); -if (ip6_ins_rt (rt,NULL ,NULL ,NULL )) +if (ip6_ins_rt (rt))dst_release (&rt->u.dst);addrconf_join_solict (dev, &aca->aca_addr);
PATCH 3/5 route: FIB6 configuration using struct fib6_config
In reply to Thomas GrafReplaces the struct in6_rtmsg based interface orignating from the ioctl interface with a struct fib6_config based on. Allows changing the interface without breaking the ioctl interface and avoids passing on tons of parameters.
The recently introduced struct nl_info is used to pass on netlink authorship information for notifications.
include/net/ip6_fib.h +27 -11
@@ -16,14 +16,35 @@ #ifdef __KERNEL__ #include <linux/ipv6_route.h> - -#include <net/dst.h> -#include <net/flow.h> #include <linux/rtnetlink.h> #include <linux/spinlock.h> +#include <net/dst.h> +#include <net/flow.h> +#include <net/netlink.h> struct rt6_info; +struct fib6_config +{ + u32 fc_table; + u32 fc_metric; + int fc_dst_len; + int fc_src_len; + int fc_ifindex; + u32 fc_flags; + u32 fc_protocol; + + struct in6_addr fc_dst; + struct in6_addr fc_src; + struct in6_addr fc_gateway; + + unsigned long fc_expires; + struct nlattr *fc_mx; + int fc_mx_len; + + struct nl_info fc_nlinfo; +}; + struct fib6_node { struct fib6_node *parent;
@@ -175,18 +196,13 @@ extern void fib6_clean_all(int (*func)extern int fib6_add (struct fib6_node *root,struct rt6_info *rt, -struct nlmsghdr *nlh, -void *rtattr, -struct netlink_skb_parms *req); +struct nl_info *info);extern int fib6_del (struct rt6_info *rt, -struct nlmsghdr *nlh, -void *rtattr, -struct netlink_skb_parms *req); +struct nl_info *info);extern void inet6_rt_notify (int event,struct rt6_info *rt, -struct nlmsghdr *nlh, -struct netlink_skb_parms *req); +struct nl_info *info);extern void fib6_run_gc (unsigned long dummy);
net/ipv6/addrconf.c +30 -33
89 lines not on this page · raw message
net/ipv6/ip6_fib.c +9 -10
@@ -610,7 +610,7 @@ insert_above:*/ static int fib6_add_rt2node (struct fib6_node *fn,struct rt6_info *rt, -struct nlmsghdr *nlh,struct netlink_skb_parms *req) +struct nl_info *info) {struct rt6_info *iter =NULL ;struct rt6_info **ins;
@@ -665,7 +665,7 @@ out: *ins = rt; rt->rt6i_node = fn;atomic_inc (&rt->rt6i_ref); -inet6_rt_notify (RTM_NEWROUTE , rt, nlh, req); +inet6_rt_notify (RTM_NEWROUTE , rt, info); rt6_stats.fib_rt_entries++;if ((fn->fn_flags &RTN_RTINFO ) ==0 ) {
@@ -695,8 +695,7 @@ void fib6_force_start_gc(void)* with source addr info in sub-trees */ -int fib6_add (struct fib6_node *root,struct rt6_info *rt, -struct nlmsghdr *nlh,void *_rtattr,struct netlink_skb_parms *req) +int fib6_add (struct fib6_node *root,struct rt6_info *rt,struct nl_info *info) {struct fib6_node *fn;int err = -ENOMEM ;
@@ -769,7 +768,7 @@ int fib6_add(struct fib6_node *root, str }#endif - err =fib6_add_rt2node (fn, rt, nlh, req); + err =fib6_add_rt2node (fn, rt, info);if (err ==0 ) {fib6_start_gc (rt);
@@ -1076,7 +1075,7 @@ static struct fib6_node * fib6_repair_tr }static void fib6_del_route (struct fib6_node *fn,struct rt6_info **rtp, -struct nlmsghdr *nlh,void *_rtattr,struct netlink_skb_parms *req) +struct nl_info *info) {struct fib6_walker_t *w;struct rt6_info *rt = *rtp;
@@ -1132,11 +1131,11 @@ static void fib6_del_route(struct fib6_nif (atomic_read (&rt->rt6i_ref) !=1 )BUG (); } -inet6_rt_notify (RTM_DELROUTE , rt, nlh, req); +inet6_rt_notify (RTM_DELROUTE , rt, info);rt6_release (rt); } -int fib6_del (struct rt6_info *rt,struct nlmsghdr *nlh,void *_rtattr,struct netlink_skb_parms *req) +int fib6_del (struct rt6_info *rt,struct nl_info *info) {struct fib6_node *fn = rt->rt6i_node;struct rt6_info **rtp;
@@ -1161,7 +1160,7 @@ int fib6_del(struct rt6_info *rt, structfor (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.next) {if (*rtp == rt) { -fib6_del_route (fn, rtp, nlh, _rtattr, req); +fib6_del_route (fn, rtp, info);return 0 ; } }
@@ -1290,7 +1289,7 @@ static int fib6_clean_node(struct fib6_w res = c->func (rt, c->arg);if (res <0 ) { w->leaf = rt; - res =fib6_del (rt,NULL ,NULL ,NULL ); + res =fib6_del (rt,NULL );if (res) {#if RT6_DEBUG >=2 printk (KERN_DEBUG "fib6_clean_node: del failed: rt=%p@%p err=%d\n" , rt, rt->rt6i_node, res);
net/ipv6/route.c +195 -144
555 lines not on this page · raw message
include/net/ip6_route.h +1 -5
@@ -60,11 +60,7 @@ extern void ip6_route_cleanup(void);extern int ipv6_route_ioctl (unsigned int cmd,void __user *arg); -extern int ip6_route_add (struct in6_rtmsg *rtmsg, -struct nlmsghdr *, -void *rtattr, -struct netlink_skb_parms *req, -u32 table_id); +extern int ip6_route_add (struct fib6_config *cfg);extern int ip6_ins_rt (struct rt6_info *);extern int ip6_del_rt (struct rt6_info *);
PATCH 4/5 route: Convert FIB6 dumping to use new netlink api
In reply to Thomas Grafnet/core/rtnetlink.c +19 -14
@@ -188,22 +188,27 @@ void rtnl_set_sk_err(u32 group, int erroint rtnetlink_put_metrics (struct sk_buff *skb,u32 *metrics) { -struct rtattr *mx = (struct rtattr *)skb->tail; -int i; +struct nlattr *mx; +int i, valid =0 ; -RTA_PUT (skb,RTA_METRICS ,0 ,NULL ); -for (i=0 ; i<RTAX_MAX ; i++) { -if (metrics[i]) -RTA_PUT (skb, i+1 ,sizeof (u32), metrics+i); - } - mx->rta_len = skb->tail - (u8 *)mx; -if (mx->rta_len ==RTA_LENGTH (0 )) -skb_trim (skb, (u8 *)mx - skb->data); -return 0 ; + mx =nla_nest_start (skb,RTA_METRICS ); +if (mx ==NULL ) +return -ENOBUFS ; -rtattr_failure: -skb_trim (skb, (u8 *)mx - skb->data); -return -1 ; +for (i =0 ; i <RTAX_MAX ; i++) { +if (metrics[i]) { + valid++; +NLA_PUT_U32 (skb, i+1 , metrics[i]); + } + } + +if (!valid) + goto nla_put_failure; + +return nla_nest_end (skb, mx); + +nla_put_failure: +return nla_nest_cancel (skb, mx); }
net/ipv6/route.c +29 -25
105 lines not on this page · raw message
PATCH 5/5 route: Convert GETROUTE to use new netlink api
In reply to Thomas GrafFixes various unvalidated netlink attributes causing memory corruptions when left empty by userspace applications.
net/ipv6/route.c +44 -36
@@ -1829,6 +1829,7 @@ void rt6_mtu_change(struct net_device *dstatic struct nla_policy rtm_ipv6_policy[RTA_MAX +1 ]__read_mostly = { [RTA_GATEWAY ] = { .minlen =sizeof (struct in6_addr ) }, [RTA_OIF ] = { .type =NLA_U32 }, + [RTA_IIF ] = { .type =NLA_U32 }, [RTA_PRIORITY ] = { .type =NLA_U32 }, [RTA_METRICS ] = { .type =NLA_NESTED }, };
@@ -2044,68 +2045,75 @@ int rt6_dump_route(struct rt6_info *rt,int inet6_rtm_getroute (struct sk_buff *in_skb,struct nlmsghdr * nlh,void *arg) { -struct rtattr **rta = arg; -int iif =0 ; -int err = -ENOBUFS ; +struct nlattr *tb[RTA_MAX +1 ]; +struct rt6_info *rt;struct sk_buff *skb; +struct rtmsg *rtm;struct flowi fl; -struct rt6_info *rt; +int err, iif =0 ; - skb =alloc_skb (NLMSG_GOODSIZE ,GFP_KERNEL ); -if (skb ==NULL ) - goto out; - -/* Reserve room for dummy headers, this skb can pass -through good chunk of routing engine. -*/ - skb->mac.raw = skb->data; -skb_reserve (skb,MAX_HEADER +sizeof (struct ipv6hdr )); + err =nlmsg_parse (nlh,sizeof (*rtm), tb,RTA_MAX , rtm_ipv6_policy); +if (err <0 ) + goto errout; + err = -EINVAL ;memset (&fl,0 ,sizeof (fl)); -if (rta[RTA_SRC -1 ]) -ipv6_addr_copy (&fl.fl6_src, - (struct in6_addr *)RTA_DATA (rta[RTA_SRC -1 ])); -if (rta[RTA_DST -1 ]) -ipv6_addr_copy (&fl.fl6_dst, - (struct in6_addr *)RTA_DATA (rta[RTA_DST -1 ])); -if (rta[RTA_IIF -1 ]) -memcpy (&iif,RTA_DATA (rta[RTA_IIF -1 ]),sizeof (int )); +if (tb[RTA_SRC ]) { +if (nla_len (tb[RTA_SRC ]) <sizeof (struct in6_addr )) + goto errout; + +ipv6_addr_copy (&fl.fl6_src,nla_data (tb[RTA_SRC ])); + } + +if (tb[RTA_DST ]) { +if (nla_len (tb[RTA_DST ]) <sizeof (struct in6_addr )) + goto errout; + +ipv6_addr_copy (&fl.fl6_dst,nla_data (tb[RTA_DST ])); + } + +if (tb[RTA_IIF ]) + iif =nla_get_u32 (tb[RTA_IIF ]); + +if (tb[RTA_OIF ]) + fl.oif =nla_get_u32 (tb[RTA_OIF ]);if (iif) {struct net_device *dev; dev =__dev_get_by_index (iif);if (!dev) { err = -ENODEV ; - goto out_free; + goto errout; } } - fl.oif =0 ; -if (rta[RTA_OIF -1 ]) -memcpy (&fl.oif,RTA_DATA (rta[RTA_OIF -1 ]),sizeof (int )); + skb =alloc_skb (NLMSG_GOODSIZE ,GFP_KERNEL ); +if (skb ==NULL ) { + err = -ENOBUFS ; + goto errout; + } - rt = (struct rt6_info *)ip6_route_output (NULL , &fl); +/* Reserve room for dummy headers, this skb can pass +through good chunk of routing engine. +*/ + skb->mac.raw = skb->data; +skb_reserve (skb,MAX_HEADER +sizeof (struct ipv6hdr )); + rt = (struct rt6_info *)ip6_route_output (NULL , &fl); skb->dst = &rt->u.dst; -NETLINK_CB (skb).dst_pid =NETLINK_CB (in_skb).pid; - err =rt6_fill_node (skb, rt, - &fl.fl6_dst, &fl.fl6_src, - iif, + err =rt6_fill_node (skb, rt, &fl.fl6_dst, &fl.fl6_src, iif,RTM_NEWROUTE ,NETLINK_CB (in_skb).pid, nlh->nlmsg_seq,0 ,0 );if (err <0 ) { - err = -EMSGSIZE ; - goto out_free; +kfree_skb (skb); + goto errout; } err =rtnl_unicast (skb,NETLINK_CB (in_skb).pid); -out: +errout:return err; -out_free: -kfree_skb (skb); - goto out; }void inet6_rt_notify (int event,struct rt6_info *rt,struct nl_info *info)
From: Thomas Graf <[email protected]>
Date: Thu, 17 Aug 2006 01:40:38 +0200
Quoted 5 lines
Same approach as for IPv4, simplifies the interface and makes it extendable without breaking the ioctl interface.
Same memory corruption fixes in
RTM_GETROUTEas for IPv4.
Applied, thanks a lot Thomas.