IPv6 routing, NLM_F_* flag support: REPLACE and EXCL flags support, warn about missing CREATE flag
The support for NLM_F_* flags at IPv6 routing requests. If NLM_F_CREATE flag is not defined for RTM_NEWROUTE request, warning is printed, but no error is returned. Instead new route is added. Later NLM_F_CREATE may be required for new route creation. 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. Patch created against linux-3.2-rc1 Signed-off-by: Matti Vaittinen <Mazziesaccount@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
d71314b4ac
Коммит
4a287eba2d
|
@ -425,7 +425,8 @@ out:
|
||||||
|
|
||||||
static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,
|
static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,
|
||||||
int addrlen, int plen,
|
int addrlen, int plen,
|
||||||
int offset)
|
int offset, int allow_create,
|
||||||
|
int replace_required)
|
||||||
{
|
{
|
||||||
struct fib6_node *fn, *in, *ln;
|
struct fib6_node *fn, *in, *ln;
|
||||||
struct fib6_node *pn = NULL;
|
struct fib6_node *pn = NULL;
|
||||||
|
@ -447,8 +448,12 @@ static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,
|
||||||
* Prefix match
|
* Prefix match
|
||||||
*/
|
*/
|
||||||
if (plen < fn->fn_bit ||
|
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
|
||||||
|
"IPv6: NLM_F_CREATE should be set when creating new route\n");
|
||||||
goto insert_above;
|
goto insert_above;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Exact match ?
|
* Exact match ?
|
||||||
|
@ -477,10 +482,26 @@ static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,
|
||||||
fn = dir ? fn->right: fn->left;
|
fn = dir ? fn->right: fn->left;
|
||||||
} while (fn);
|
} 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
|
||||||
|
"IPv6: NLM_F_CREATE should be set when creating new route - ignoring request\n");
|
||||||
|
return ERR_PTR(-ENOENT);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* We walked to the bottom of tree.
|
* We walked to the bottom of tree.
|
||||||
* Create new leaf node without children.
|
* Create new leaf node without children.
|
||||||
*/
|
*/
|
||||||
|
if (!allow_create)
|
||||||
|
printk(KERN_WARNING "IPv6: NLM_F_CREATE should be set when creating new route\n");
|
||||||
|
|
||||||
ln = node_alloc();
|
ln = node_alloc();
|
||||||
|
|
||||||
|
@ -614,6 +635,12 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
|
||||||
{
|
{
|
||||||
struct rt6_info *iter = NULL;
|
struct rt6_info *iter = NULL;
|
||||||
struct rt6_info **ins;
|
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;
|
ins = &fn->leaf;
|
||||||
|
|
||||||
|
@ -626,6 +653,13 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
|
||||||
/*
|
/*
|
||||||
* Same priority level
|
* 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 &&
|
if (iter->rt6i_dev == rt->rt6i_dev &&
|
||||||
iter->rt6i_idev == rt->rt6i_idev &&
|
iter->rt6i_idev == rt->rt6i_idev &&
|
||||||
|
@ -655,17 +689,40 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
|
||||||
/*
|
/*
|
||||||
* insert node
|
* insert node
|
||||||
*/
|
*/
|
||||||
|
if (!replace) {
|
||||||
|
if (!add)
|
||||||
|
printk(KERN_WARNING "IPv6: NLM_F_CREATE should be set when creating new route\n");
|
||||||
|
|
||||||
rt->dst.rt6_next = iter;
|
add:
|
||||||
*ins = rt;
|
rt->dst.rt6_next = iter;
|
||||||
rt->rt6i_node = fn;
|
*ins = rt;
|
||||||
atomic_inc(&rt->rt6i_ref);
|
rt->rt6i_node = fn;
|
||||||
inet6_rt_notify(RTM_NEWROUTE, rt, info);
|
atomic_inc(&rt->rt6i_ref);
|
||||||
info->nl_net->ipv6.rt6_stats->fib_rt_entries++;
|
inet6_rt_notify(RTM_NEWROUTE, rt, info);
|
||||||
|
info->nl_net->ipv6.rt6_stats->fib_rt_entries++;
|
||||||
|
|
||||||
if ((fn->fn_flags & RTN_RTINFO) == 0) {
|
if ((fn->fn_flags & RTN_RTINFO) == 0) {
|
||||||
info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
|
info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
|
||||||
fn->fn_flags |= RTN_RTINFO;
|
fn->fn_flags |= RTN_RTINFO;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (!found) {
|
||||||
|
if (add)
|
||||||
|
goto add;
|
||||||
|
printk(KERN_WARNING "IPv6: NLM_F_REPLACE set, but no existing node found!\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;
|
return 0;
|
||||||
|
@ -696,9 +753,25 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
|
||||||
{
|
{
|
||||||
struct fib6_node *fn, *pn = NULL;
|
struct fib6_node *fn, *pn = NULL;
|
||||||
int err = -ENOMEM;
|
int err = -ENOMEM;
|
||||||
|
int allow_create = 1;
|
||||||
|
int replace_required = 0;
|
||||||
|
if (NULL != info && NULL != info->nlh) {
|
||||||
|
if (!(info->nlh->nlmsg_flags&NLM_F_CREATE))
|
||||||
|
allow_create = 0;
|
||||||
|
if ((info->nlh->nlmsg_flags&NLM_F_REPLACE))
|
||||||
|
replace_required = 1;
|
||||||
|
}
|
||||||
|
if (!allow_create && !replace_required)
|
||||||
|
printk(KERN_WARNING "IPv6: 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),
|
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),
|
||||||
|
allow_create, replace_required);
|
||||||
|
|
||||||
|
if (IS_ERR(fn)) {
|
||||||
|
err = PTR_ERR(fn);
|
||||||
|
fn = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (fn == NULL)
|
if (fn == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -736,7 +809,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
|
||||||
|
|
||||||
sn = fib6_add_1(sfn, &rt->rt6i_src.addr,
|
sn = fib6_add_1(sfn, &rt->rt6i_src.addr,
|
||||||
sizeof(struct in6_addr), rt->rt6i_src.plen,
|
sizeof(struct in6_addr), rt->rt6i_src.plen,
|
||||||
offsetof(struct rt6_info, rt6i_src));
|
offsetof(struct rt6_info, rt6i_src),
|
||||||
|
allow_create, replace_required);
|
||||||
|
|
||||||
if (sn == NULL) {
|
if (sn == NULL) {
|
||||||
/* If it is failed, discard just allocated
|
/* If it is failed, discard just allocated
|
||||||
|
@ -753,8 +827,13 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
|
||||||
} else {
|
} else {
|
||||||
sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr,
|
sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr,
|
||||||
sizeof(struct in6_addr), rt->rt6i_src.plen,
|
sizeof(struct in6_addr), rt->rt6i_src.plen,
|
||||||
offsetof(struct rt6_info, rt6i_src));
|
offsetof(struct rt6_info, rt6i_src),
|
||||||
|
allow_create, replace_required);
|
||||||
|
|
||||||
|
if (IS_ERR(sn)) {
|
||||||
|
err = PTR_ERR(sn);
|
||||||
|
sn = NULL;
|
||||||
|
}
|
||||||
if (sn == NULL)
|
if (sn == NULL)
|
||||||
goto st_failure;
|
goto st_failure;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче