IPv6 - support for NLM_F_* flags at routing requests
Subsystems (3)
PATCH v3 1/1 IPv6 - support for NLM_F_* flags at routing requests
Once more.. Changed returnvalue -EINVAL to -ENOENT for case where NLM_F_REPLACE is specified without NLM_F_CREATE, and no matching route is found.
The support for NLM_F_* flags at IPv6 routing requests.
If no NLM_F_CREATE flag is not defined for RTM_NEWROUTE request, warning is printed, but no error is returned. Instead new route is added.
Exception is when NLM_F_REPLACE flag is given without NLM_F_CREATE, and no matching route is found. In this case it should be safe to assume that the request issuer is familiar with NLM_F_* flags, and does really not want route to be created.
Specifying NLM_F_REPLACE flag will now make the kernel to search for matching route, and replace it with new one. If no route is found and NLM_F_CREATE is specified as well, then new route is created.
Also, specifying NLM_F_EXCL will yield returning of error if matching route is found.
---
net/ipv6/ip6_fib.c +117 -17
@@ -429,17 +429,34 @@static struct fib6_node *fib6_add_1 (struct fib6_node *root,void *addr,int addrlen,int plen, -int offset) +int offset,struct nl_info *info) {struct fib6_node *fn, *in, *ln;struct fib6_node *pn =NULL ;struct rt6key *key;int bit; + + +int allow_create =1 ; +int replace_required =0 ; + +__be32 dir =0 ;__u32 sernum =fib6_new_sernum ();RT6_TRACE ("fib6_add_1\n" ); +if (NULL != info && +NULL != info->nlh && + (info->nlh->nlmsg_flags&NLM_F_REPLACE )) { + replace_required =1 ; + } +if (NULL != info && +NULL != info->nlh && + !(info->nlh->nlmsg_flags&NLM_F_CREATE )) { + allow_create =0 ; + } +/* insert node in tree */ fn = root;
@@ -451,8 +468,12 @@* Prefix match */ if (plen < fn->fn_bit || - !ipv6_prefix_equal (&key->addr, addr, fn->fn_bit)) + !ipv6_prefix_equal (&key->addr, addr, fn->fn_bit)) { +if (!allow_create) +printk (KERN_WARNING +"NLM_F_CREATE should be specified when creating new rt\n" ); goto insert_above; + }/* * Exact match ?
@@ -481,10 +502,27 @@ fn = dir ? fn->right: fn->left; }while (fn); + +if (replace_required && !allow_create) { +/* We should not create new node because +* NLM_F_REPLACE was specified without NLM_F_CREATE +* I assume it is safe to require NLM_F_CREATE when +* REPLACE flag is used! Later we may want to remove the +* check for replace_required, because according +* to netlink specification, NLM_F_CREATE +* MUST be specified if new route is created. +* That would keep IPv6 consistent with IPv4 +*/ +printk (KERN_WARNING +"NLM_F_CREATE should be specified when creating new rt - ignoring request\n" ); +return ERR_PTR (-ENOENT ); + }/* * We walked to the bottom of tree. * Create new leaf node without children. */ +if (!allow_create) +printk (KERN_WARNING "NLM_F_CREATE should be specified when creating new rt\n" ); ln =node_alloc ();
@@ -567,7 +605,6 @@ fn->parent = in; ln->fn_sernum = sernum; -if (addr_bit_set (addr, bit)) { in->right = ln; in->left = fn;
@@ -585,6 +622,7 @@ ln =node_alloc (); +if (ln ==NULL )return NULL ;
@@ -618,6 +656,12 @@ {struct rt6_info *iter =NULL ;struct rt6_info **ins; +int replace = (NULL != info && +NULL != info->nlh && + (info->nlh->nlmsg_flags&NLM_F_REPLACE )); +int add = ((NULL == info ||NULL == info->nlh) || + (info->nlh->nlmsg_flags&NLM_F_CREATE )); +int found =0 ; ins = &fn->leaf;
@@ -630,6 +674,13 @@/* * Same priority level */ +if (NULL != info->nlh && + (info->nlh->nlmsg_flags&NLM_F_EXCL )) +return -EEXIST ; +if (replace) { + found++; +break ; + } if (iter->rt6i_dev == rt->rt6i_dev && iter->rt6i_idev == rt->rt6i_idev &&
@@ -659,19 +710,41 @@/* * insert node */ +if (!replace) { +if (!add) +printk (KERN_WARNING "NLM_F_CREATE should be specified when creating new rt\n" ); + +add: + rt->dst.rt6_next = iter; + *ins = rt; + rt->rt6i_node = fn; +atomic_inc (&rt->rt6i_ref); +inet6_rt_notify (RTM_NEWROUTE , rt, info); + info->nl_net->ipv6.rt6_stats->fib_rt_entries++; + +if ((fn->fn_flags &RTN_RTINFO ) ==0 ) { + info->nl_net->ipv6.rt6_stats->fib_route_nodes++; + fn->fn_flags |=RTN_RTINFO ; + } - rt->dst.rt6_next = iter; - *ins = rt; - rt->rt6i_node = fn; -atomic_inc (&rt->rt6i_ref); -inet6_rt_notify (RTM_NEWROUTE , rt, info); - info->nl_net->ipv6.rt6_stats->fib_rt_entries++; - -if ((fn->fn_flags &RTN_RTINFO ) ==0 ) { - info->nl_net->ipv6.rt6_stats->fib_route_nodes++; - fn->fn_flags |=RTN_RTINFO ; + }else { +if (!found) { +if (add) + goto add; +printk (KERN_WARNING "add rtinfo to node - NLM_F_REPLACE specified, but no existing node found! bailing out\n" ); +return -ENOENT ; + } + *ins = rt; + rt->rt6i_node = fn; + rt->dst.rt6_next = iter->dst.rt6_next; +atomic_inc (&rt->rt6i_ref); +inet6_rt_notify (RTM_NEWROUTE , rt, info); +rt6_release (iter); +if ((fn->fn_flags &RTN_RTINFO ) ==0 ) { + info->nl_net->ipv6.rt6_stats->fib_route_nodes++; + fn->fn_flags |=RTN_RTINFO ; + } } -return 0 ; }
@@ -700,10 +773,29 @@ {struct fib6_node *fn, *pn =NULL ;int err = -ENOMEM ; +int allow_create =1 ; +int allow_replace =1 ; +if (NULL != info && +NULL != info->nlh && + !(info->nlh->nlmsg_flags&NLM_F_REPLACE )) { + allow_replace =0 ; + } +if (NULL != info && +NULL != info->nlh && + !(info->nlh->nlmsg_flags&NLM_F_CREATE )) { + allow_create =0 ; + } +if (!allow_create && !allow_replace) +printk (KERN_WARNING "RTM_NEWROUTE with no NLM_F_CREATE or NLM_F_REPLACE\n" ); fn =fib6_add_1 (root, &rt->rt6i_dst.addr,sizeof (struct in6_addr ), - rt->rt6i_dst.plen, offsetof(struct rt6_info , rt6i_dst)); + rt->rt6i_dst.plen, offsetof(struct rt6_info , rt6i_dst), + info); +if (-ENOENT ==PTR_ERR (fn)) { + err = -ENOENT ; + fn =NULL ; + }if (fn ==NULL ) goto out;
@@ -716,6 +808,8 @@if (fn->subtree ==NULL ) {struct fib6_node *sfn; +if (!allow_create) +printk (KERN_WARNING "NLM_F_CREATE should be specified when creating new rt\n" );/* * Create subtree. *
@@ -740,7 +834,8 @@ sn =fib6_add_1 (sfn, &rt->rt6i_src.addr,sizeof (struct in6_addr ), rt->rt6i_src.plen, - offsetof(struct rt6_info , rt6i_src)); + offsetof(struct rt6_info , rt6i_src), + info);if (sn ==NULL ) {/* If it is failed, discard just allocated
@@ -757,8 +852,13 @@ }else { sn =fib6_add_1 (fn->subtree, &rt->rt6i_src.addr,sizeof (struct in6_addr ), rt->rt6i_src.plen, - offsetof(struct rt6_info , rt6i_src)); + offsetof(struct rt6_info , rt6i_src), + info); +if (-ENOENT ==PTR_ERR (sn)) { + err = -ENOENT ; + sn =NULL ; + }if (sn ==NULL ) goto st_failure; }
net/ipv6/route.c +11 -2
@@ -1223,9 +1223,18 @@if (cfg->fc_metric ==0 ) cfg->fc_metric =IP6_RT_PRIO_USER ; - table =fib6_new_table (net, cfg->fc_table); + err = -ENOBUFS ; +if (NULL != cfg->fc_nlinfo.nlh && + !(cfg->fc_nlinfo.nlh->nlmsg_flags&NLM_F_CREATE )) { + table =fib6_get_table (net, cfg->fc_table); +if (table ==NULL ) { +printk (KERN_WARNING "NLM_F_CREATE should be specified when creating new rt\n" ); + table =fib6_new_table (net, cfg->fc_table); + } + }else { + table =fib6_new_table (net, cfg->fc_table); + }if (table ==NULL ) { - err = -ENOBUFS ; goto out; }