Release 4.11 net/ipv4/fib_frontend.c
/*
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
*
* IPv4 Forwarding Information Base: FIB frontend.
*
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/capability.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/errno.h>
#include <linux/in.h>
#include <linux/inet.h>
#include <linux/inetdevice.h>
#include <linux/netdevice.h>
#include <linux/if_addr.h>
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <linux/cache.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <net/ip.h>
#include <net/protocol.h>
#include <net/route.h>
#include <net/tcp.h>
#include <net/sock.h>
#include <net/arp.h>
#include <net/ip_fib.h>
#include <net/rtnetlink.h>
#include <net/xfrm.h>
#include <net/l3mdev.h>
#include <net/lwtunnel.h>
#include <trace/events/fib.h>
#ifndef CONFIG_IP_MULTIPLE_TABLES
static int __net_init fib4_rules_init(struct net *net)
{
struct fib_table *local_table, *main_table;
main_table = fib_trie_table(RT_TABLE_MAIN, NULL);
if (!main_table)
return -ENOMEM;
local_table = fib_trie_table(RT_TABLE_LOCAL, main_table);
if (!local_table)
goto fail;
hlist_add_head_rcu(&local_table->tb_hlist,
&net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX]);
hlist_add_head_rcu(&main_table->tb_hlist,
&net->ipv4.fib_table_hash[TABLE_MAIN_INDEX]);
return 0;
fail:
fib_free_table(main_table);
return -ENOMEM;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Denis V. Lunev | 48 | 45.71% | 4 | 40.00% |
Pavel Emelyanov | 34 | 32.38% | 1 | 10.00% |
Alexander Duyck | 19 | 18.10% | 3 | 30.00% |
David S. Miller | 2 | 1.90% | 1 | 10.00% |
Ian Morris | 2 | 1.90% | 1 | 10.00% |
Total | 105 | 100.00% | 10 | 100.00% |
#else
struct fib_table *fib_new_table(struct net *net, u32 id)
{
struct fib_table *tb, *alias = NULL;
unsigned int h;
if (id == 0)
id = RT_TABLE_MAIN;
tb = fib_get_table(net, id);
if (tb)
return tb;
if (id == RT_TABLE_LOCAL && !net->ipv4.fib_has_custom_rules)
alias = fib_new_table(net, RT_TABLE_MAIN);
tb = fib_trie_table(id, alias);
if (!tb)
return NULL;
switch (id) {
case RT_TABLE_MAIN:
rcu_assign_pointer(net->ipv4.fib_main, tb);
break;
case RT_TABLE_DEFAULT:
rcu_assign_pointer(net->ipv4.fib_default, tb);
break;
default:
break;
}
h = id & (FIB_TABLE_HASHSZ - 1);
hlist_add_head_rcu(&tb->tb_hlist, &net->ipv4.fib_table_hash[h]);
return tb;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 56 | 34.36% | 2 | 20.00% |
Alexander Duyck | 37 | 22.70% | 3 | 30.00% |
David S. Miller | 31 | 19.02% | 2 | 20.00% |
Linus Torvalds (pre-git) | 28 | 17.18% | 1 | 10.00% |
Denis V. Lunev | 11 | 6.75% | 2 | 20.00% |
Total | 163 | 100.00% | 10 | 100.00% |
EXPORT_SYMBOL_GPL(fib_new_table);
/* caller must hold either rtnl or rcu read lock */
struct fib_table *fib_get_table(struct net *net, u32 id)
{
struct fib_table *tb;
struct hlist_head *head;
unsigned int h;
if (id == 0)
id = RT_TABLE_MAIN;
h = id & (FIB_TABLE_HASHSZ - 1);
head = &net->ipv4.fib_table_hash[h];
hlist_for_each_entry_rcu(tb, head, tb_hlist) {
if (tb->tb_id == id)
return tb;
}
return NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 57 | 67.06% | 1 | 25.00% |
Denis V. Lunev | 22 | 25.88% | 2 | 50.00% |
Linus Torvalds (pre-git) | 6 | 7.06% | 1 | 25.00% |
Total | 85 | 100.00% | 4 | 100.00% |
#endif /* CONFIG_IP_MULTIPLE_TABLES */
static void fib_replace_table(struct net *net, struct fib_table *old,
struct fib_table *new)
{
#ifdef CONFIG_IP_MULTIPLE_TABLES
switch (new->tb_id) {
case RT_TABLE_MAIN:
rcu_assign_pointer(net->ipv4.fib_main, new);
break;
case RT_TABLE_DEFAULT:
rcu_assign_pointer(net->ipv4.fib_default, new);
break;
default:
break;
}
#endif
/* replace the old table in the hlist */
hlist_replace_rcu(&old->tb_hlist, &new->tb_hlist);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexander Duyck | 80 | 100.00% | 1 | 100.00% |
Total | 80 | 100.00% | 1 | 100.00% |
int fib_unmerge(struct net *net)
{
struct fib_table *old, *new, *main_table;
/* attempt to fetch local table if it has been allocated */
old = fib_get_table(net, RT_TABLE_LOCAL);
if (!old)
return 0;
new = fib_trie_unmerge(old);
if (!new)
return -ENOMEM;
/* table is already unmerged */
if (new == old)
return 0;
/* replace merged table with clean table */
fib_replace_table(net, old, new);
fib_free_table(old);
/* attempt to fetch main table if it has been allocated */
main_table = fib_get_table(net, RT_TABLE_MAIN);
if (!main_table)
return 0;
/* flush local entries from main table */
fib_table_flush_external(main_table);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexander Duyck | 107 | 100.00% | 3 | 100.00% |
Total | 107 | 100.00% | 3 | 100.00% |
static void fib_flush(struct net *net)
{
int flushed = 0;
unsigned int h;
for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
struct hlist_head *head = &net->ipv4.fib_table_hash[h];
struct hlist_node *tmp;
struct fib_table *tb;
hlist_for_each_entry_safe(tb, tmp, head, tb_hlist)
flushed += fib_table_flush(net, tb);
}
if (flushed)
rt_cache_flush(net);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 36 | 40.91% | 1 | 12.50% |
Alexander Duyck | 18 | 20.45% | 1 | 12.50% |
Denis V. Lunev | 16 | 18.18% | 2 | 25.00% |
Patrick McHardy | 14 | 15.91% | 1 | 12.50% |
Jiri Pirko | 2 | 2.27% | 1 | 12.50% |
Stephen Hemminger | 1 | 1.14% | 1 | 12.50% |
Adrian Bunk | 1 | 1.14% | 1 | 12.50% |
Total | 88 | 100.00% | 8 | 100.00% |
/*
* Find address type as if only "dev" was present in the system. If
* on_dev is NULL then all interfaces are taken into consideration.
*/
static inline unsigned int __inet_dev_addr_type(struct net *net,
const struct net_device *dev,
__be32 addr, u32 tb_id)
{
struct flowi4 fl4 = { .daddr = addr };
struct fib_result res;
unsigned int ret = RTN_BROADCAST;
struct fib_table *table;
if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr))
return RTN_BROADCAST;
if (ipv4_is_multicast(addr))
return RTN_MULTICAST;
rcu_read_lock();
table = fib_get_table(net, tb_id);
if (table) {
ret = RTN_UNICAST;
if (!fib_table_lookup(table, &fl4, &res, FIB_LOOKUP_NOREF)) {
if (!dev || dev == res.fi->fib_dev)
ret = res.type;
}
}
rcu_read_unlock();
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 68 | 48.23% | 2 | 11.11% |
Tóth László Attila | 22 | 15.60% | 1 | 5.56% |
David S. Miller | 10 | 7.09% | 2 | 11.11% |
Pavel Emelyanov | 9 | 6.38% | 1 | 5.56% |
David Ahern | 8 | 5.67% | 2 | 11.11% |
Eric Dumazet | 7 | 4.96% | 2 | 11.11% |
Eric W. Biedermann | 6 | 4.26% | 1 | 5.56% |
Alexander Duyck | 4 | 2.84% | 1 | 5.56% |
Joe Perches | 2 | 1.42% | 1 | 5.56% |
Al Viro | 1 | 0.71% | 1 | 5.56% |
Arnaldo Carvalho de Melo | 1 | 0.71% | 1 | 5.56% |
Stephen Hemminger | 1 | 0.71% | 1 | 5.56% |
Jan Engelhardt | 1 | 0.71% | 1 | 5.56% |
Denis V. Lunev | 1 | 0.71% | 1 | 5.56% |
Total | 141 | 100.00% | 18 | 100.00% |
unsigned int inet_addr_type_table(struct net *net, __be32 addr, u32 tb_id)
{
return __inet_dev_addr_type(net, NULL, addr, tb_id);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David Ahern | 29 | 100.00% | 2 | 100.00% |
Total | 29 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(inet_addr_type_table);
unsigned int inet_addr_type(struct net *net, __be32 addr)
{
return __inet_dev_addr_type(net, NULL, addr, RT_TABLE_LOCAL);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Tóth László Attila | 17 | 65.38% | 1 | 33.33% |
Eric W. Biedermann | 7 | 26.92% | 1 | 33.33% |
David Ahern | 2 | 7.69% | 1 | 33.33% |
Total | 26 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL(inet_addr_type);
unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
__be32 addr)
{
u32 rt_table = l3mdev_fib_table(dev) ? : RT_TABLE_LOCAL;
return __inet_dev_addr_type(net, dev, addr, rt_table);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Tóth László Attila | 23 | 53.49% | 1 | 20.00% |
David Ahern | 13 | 30.23% | 3 | 60.00% |
Eric W. Biedermann | 7 | 16.28% | 1 | 20.00% |
Total | 43 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL(inet_dev_addr_type);
/* inet_addr_type with dev == NULL but using the table from a dev
* if one is associated
*/
unsigned int inet_addr_type_dev_table(struct net *net,
const struct net_device *dev,
__be32 addr)
{
u32 rt_table = l3mdev_fib_table(dev) ? : RT_TABLE_LOCAL;
return __inet_dev_addr_type(net, NULL, addr, rt_table);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David Ahern | 43 | 100.00% | 3 | 100.00% |
Total | 43 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL(inet_addr_type_dev_table);
__be32 fib_compute_spec_dst(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
struct in_device *in_dev;
struct fib_result res;
struct rtable *rt;
struct net *net;
int scope;
rt = skb_rtable(skb);
if ((rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST | RTCF_LOCAL)) ==
RTCF_LOCAL)
return ip_hdr(skb)->daddr;
in_dev = __in_dev_get_rcu(dev);
BUG_ON(!in_dev);
net = dev_net(dev);
scope = RT_SCOPE_UNIVERSE;
if (!ipv4_is_zeronet(ip_hdr(skb)->saddr)) {
struct flowi4 fl4 = {
.flowi4_iif = LOOPBACK_IFINDEX,
.daddr = ip_hdr(skb)->saddr,
.flowi4_tos = RT_TOS(ip_hdr(skb)->tos),
.flowi4_scope = scope,
.flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0,
};
if (!fib_lookup(net, &fl4, &res, 0))
return FIB_RES_PREFSRC(net, res);
} else {
scope = RT_SCOPE_LINK;
}
return inet_select_addr(dev, ip_hdr(skb)->saddr, scope);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 193 | 91.04% | 2 | 33.33% |
Lance Richardson | 12 | 5.66% | 1 | 16.67% |
Julian Anastasov | 4 | 1.89% | 1 | 16.67% |
Andy Gospodarek | 2 | 0.94% | 1 | 16.67% |
Pavel Emelyanov | 1 | 0.47% | 1 | 16.67% |
Total | 212 | 100.00% | 6 | 100.00% |
/* Given (packet source, input interface) and optional (dst, oif, tos):
* - (main) check, that source is valid i.e. not broadcast or our local
* address.
* - figure out what "logical" interface this packet arrived
* and calculate "specific destination" address.
* - check, that packet arrived from expected physical interface.
* called with rcu_read_lock()
*/
static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
u8 tos, int oif, struct net_device *dev,
int rpf, struct in_device *idev, u32 *itag)
{
int ret, no_addr;
struct fib_result res;
struct flowi4 fl4;
struct net *net = dev_net(dev);
bool dev_match;
fl4.flowi4_oif = 0;
fl4.flowi4_iif = l3mdev_master_ifindex_rcu(dev);
if (!fl4.flowi4_iif)
fl4.flowi4_iif = oif ? : LOOPBACK_IFINDEX;
fl4.daddr = src;
fl4.saddr = dst;
fl4.flowi4_tos = tos;
fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
fl4.flowi4_tun_key.tun_id = 0;
fl4.flowi4_flags = 0;
fl4.flowi4_uid = sock_net_uid(net, NULL);
no_addr = idev->ifa_list == NULL;
fl4.flowi4_mark = IN_DEV_SRC_VMARK(idev) ? skb->mark : 0;
trace_fib_validate_source(dev, &fl4);
if (fib_lookup(net, &fl4, &res, 0))
goto last_resort;
if (res.type != RTN_UNICAST &&
(res.type != RTN_LOCAL || !IN_DEV_ACCEPT_LOCAL(idev)))
goto e_inval;
if (!rpf && !fib_num_tclassid_users(net) &&
(dev->ifindex != oif || !IN_DEV_TX_REDIRECTS(idev)))
goto last_resort;
fib_combine_itag(itag, &res);
dev_match = false;
#ifdef CONFIG_IP_ROUTE_MULTIPATH
for (ret = 0; ret < res.fi->fib_nhs; ret++) {
struct fib_nh *nh = &res.fi->fib_nh[ret];
if (nh->nh_dev == dev) {
dev_match = true;
break;
} else if (l3mdev_master_ifindex_rcu(nh->nh_dev) == dev->ifindex) {
dev_match = true;
break;
}
}
#else
if (FIB_RES_DEV(res) == dev)
dev_match = true;
#endif
if (dev_match) {
ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
return ret;
}
if (no_addr)
goto last_resort;
if (rpf == 1)
goto e_rpf;
fl4.flowi4_oif = dev->ifindex;
ret = 0;
if (fib_lookup(net, &fl4, &res, FIB_LOOKUP_IGNORE_LINKSTATE) == 0) {
if (res.type == RTN_UNICAST)
ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
}
return ret;
last_resort:
if (rpf)
goto e_rpf;
*itag = 0;
return 0;
e_inval:
return -EINVAL;
e_rpf:
return -EXDEV;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 177 | 37.82% | 4 | 14.29% |
David S. Miller | 125 | 26.71% | 6 | 21.43% |
David Ahern | 51 | 10.90% | 4 | 14.29% |
Sébastien Barré | 34 | 7.26% | 1 | 3.57% |
Julian Anastasov | 17 | 3.63% | 1 | 3.57% |
Michael Smith | 13 | 2.78% | 1 | 3.57% |
Denis V. Lunev | 11 | 2.35% | 2 | 7.14% |
Eric Dumazet | 9 | 1.92% | 2 | 7.14% |
Thomas Graf | 8 | 1.71% | 1 | 3.57% |
Patrick McHardy | 8 | 1.71% | 1 | 3.57% |
Jamal Hadi Salim | 4 | 0.85% | 1 | 3.57% |
Andy Gospodarek | 4 | 0.85% | 1 | 3.57% |
Cong Wang | 3 | 0.64% | 1 | 3.57% |
Al Viro | 2 | 0.43% | 1 | 3.57% |
Stephen Hemminger | 2 | 0.43% | 1 | 3.57% |
Total | 468 | 100.00% | 28 | 100.00% |
/* Ignore rp_filter for packets protected by IPsec. */
int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
u8 tos, int oif, struct net_device *dev,
struct in_device *idev, u32 *itag)
{
int r = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(idev);
if (!r && !fib_num_tclassid_users(dev_net(dev)) &&
IN_DEV_ACCEPT_LOCAL(idev) &&
(dev->ifindex != oif || !IN_DEV_TX_REDIRECTS(idev))) {
*itag = 0;
return 0;
}
return __fib_validate_source(skb, src, dst, tos, oif, dev, r, idev, itag);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 97 | 83.62% | 2 | 50.00% |
Julian Anastasov | 14 | 12.07% | 1 | 25.00% |
Sébastien Barré | 5 | 4.31% | 1 | 25.00% |
Total | 116 | 100.00% | 4 | 100.00% |
static inline __be32 sk_extract_addr(struct sockaddr *addr)
{
return ((struct sockaddr_in *) addr)->sin_addr.s_addr;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 25 | 96.15% | 1 | 50.00% |
Al Viro | 1 | 3.85% | 1 | 50.00% |
Total | 26 | 100.00% | 2 | 100.00% |
static int put_rtax(struct nlattr *mx, int len, int type, u32 value)
{
struct nlattr *nla;
nla = (struct nlattr *) ((char *) mx + len);
nla->nla_type = type;
nla->nla_len = nla_attr_size(4);
*(u32 *) nla_data(nla) = value;
return len + nla_total_size(4);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 69 | 89.61% | 1 | 50.00% |
Linus Torvalds (pre-git) | 8 | 10.39% | 1 | 50.00% |
Total | 77 | 100.00% | 2 | 100.00% |
static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt,
struct fib_config *cfg)
{
__be32 addr;
int plen;
memset(cfg, 0, sizeof(*cfg));
cfg->fc_nlinfo.nl_net = net;
if (rt->rt_dst.sa_family != AF_INET)
return -EAFNOSUPPORT;
/*
* Check mask for validity:
* a) it must be contiguous.
* b) destination must have all host bits clear.
* c) if application forgot to set correct family (AF_INET),
* reject request unless it is absolutely clear i.e.
* both family and mask are zero.
*/
plen = 32;
addr = sk_extract_addr(&rt->rt_dst);
if (!(rt->rt_flags & RTF_HOST)) {
__be32 mask = sk_extract_addr(&rt->rt_genmask);
if (rt->rt_genmask.sa_family != AF_INET) {
if (mask || rt->rt_genmask.sa_family)
return -EAFNOSUPPORT;
}
if (bad_mask(mask, addr))
return -EINVAL;
plen = inet_mask_len(mask);
}
cfg->fc_dst_len = plen;
cfg->fc_dst = addr;
if (cmd != SIOCDELRT) {
cfg->fc_nlflags = NLM_F_CREATE;
cfg->fc_protocol = RTPROT_BOOT;
}
if (rt->rt_metric)
cfg->fc_priority = rt->rt_metric - 1;
if (rt->rt_flags & RTF_REJECT) {
cfg->fc_scope = RT_SCOPE_HOST;
cfg->fc_type = RTN_UNREACHABLE;
return 0;
}
cfg->fc_scope = RT_SCOPE_NOWHERE;
cfg->fc_type = RTN_UNICAST;
if (rt->rt_dev) {
char *colon;
struct net_device *dev;
char devname[IFNAMSIZ];
if (copy_from_user(devname, rt->rt_dev, IFNAMSIZ-1))
return -EFAULT;
devname[IFNAMSIZ-1] = 0;
colon = strchr(devname, ':');
if (colon)
*colon = 0;
dev = __dev_get_by_name(net, devname);
if (!dev)
return -ENODEV;
cfg->fc_oif = dev->ifindex;
cfg->fc_table = l3mdev_fib_table(dev);
if (colon) {
struct in_ifaddr *ifa;
struct in_device *in_dev = __in_dev_get_rtnl(dev);
if (!in_dev)
return -ENODEV;
*colon = ':';
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next)
if (strcmp(ifa->ifa_label, devname) == 0)
break;
if (!ifa)
return -ENODEV;
cfg->fc_prefsrc = ifa->ifa_local;
}
}
addr = sk_extract_addr(&rt->rt_gateway);
if (rt->rt_gateway.sa_family == AF_INET && addr) {
unsigned int addr_type;
cfg->fc_gw = addr;
addr_type = inet_addr_type_table(net, addr, cfg->fc_table);
if (rt->rt_flags & RTF_GATEWAY &&
addr_type == RTN_UNICAST)
cfg->fc_scope = RT_SCOPE_UNIVERSE;
}
if (cmd == SIOCDELRT)
return 0;
if (rt->rt_flags & RTF_GATEWAY && !cfg->fc_gw)
return -EINVAL;
if (cfg->fc_scope == RT_SCOPE_NOWHERE)
cfg->fc_scope = RT_SCOPE_LINK;
if (rt->rt_flags & (RTF_MTU | RTF_WINDOW | RTF_IRTT)) {
struct nlattr *mx;
int len = 0;
mx = kzalloc(3 * nla_total_size(4), GFP_KERNEL);
if (!mx)
return -ENOMEM;
if (rt->rt_flags & RTF_MTU)
len = put_rtax(mx, len, RTAX_ADVMSS, rt->rt_mtu - 40);
if (rt->rt_flags & RTF_WINDOW)
len = put_rtax(mx, len, RTAX_WINDOW, rt->rt_window);
if (rt->rt_flags & RTF_IRTT)
len = put_rtax(mx, len, RTAX_RTT, rt->rt_irtt << 3);
cfg->fc_mx = mx;
cfg->fc_mx_len = len;
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 558 | 84.16% | 1 | 9.09% |
Linus Torvalds (pre-git) | 59 | 8.90% | 2 | 18.18% |
David Ahern | 18 | 2.71% | 1 | 9.09% |
Denis V. Lunev | 14 | 2.11% | 2 | 18.18% |
Mark Tomlinson | 9 | 1.36% | 1 | 9.09% |
Al Viro | 2 | 0.30% | 2 | 18.18% |
Ian Morris | 2 | 0.30% | 1 | 9.09% |
Eric W. Biedermann | 1 | 0.15% | 1 | 9.09% |
Total | 663 | 100.00% | 11 | 100.00% |
/*
* Handle IP routing ioctl calls.
* These are used to manipulate the routing tables
*/
int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg)
{
struct fib_config cfg;
struct rtentry rt;
int err;
switch (cmd) {
case SIOCADDRT: /* Add a route */
case SIOCDELRT: /* Delete a route */
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM;
if (copy_from_user(&rt, arg, sizeof(rt)))
return -EFAULT;
rtnl_lock();
err = rtentry_to_fib_config(net, cmd, &rt, &cfg);
if (err == 0) {
struct fib_table *tb;
if (cmd == SIOCDELRT) {
tb = fib_get_table(net, cfg.fc_table);
if (tb)
err = fib_table_delete(net, tb, &cfg);
else
err = -ESRCH;
} else {
tb = fib_new_table(net, cfg.fc_table);
if (tb)
err = fib_table_insert(net, tb, &cfg);
else
err = -ENOBUFS;
}
/* allocated by rtentry_to_fib_config() */
kfree(cfg.fc_mx);
}
rtnl_unlock();
return err;
}
return -EINVAL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 183 | 89.27% | 1 | 14.29% |
Denis V. Lunev | 11 | 5.37% | 3 | 42.86% |
Eric W. Biedermann | 5 | 2.44% | 1 | 14.29% |
Jiri Pirko | 4 | 1.95% | 1 | 14.29% |
Stephen Hemminger | 2 | 0.98% | 1 | 14.29% |
Total | 205 | 100.00% | 7 | 100.00% |
const struct nla_policy rtm_ipv4_policy[RTA_MAX + 1] = {
[RTA_DST] = { .type = NLA_U32 },
[RTA_SRC] = { .type = NLA_U32 },
[RTA_IIF] = { .type = NLA_U32 },
[RTA_OIF] = { .type = NLA_U32 },
[RTA_GATEWAY] = { .type = NLA_U32 },
[RTA_PRIORITY] = { .type = NLA_U32 },
[RTA_PREFSRC] = { .type = NLA_U32 },
[RTA_METRICS] = { .type = NLA_NESTED },
[RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
[RTA_FLOW] = { .type = NLA_U32 },
[RTA_ENCAP_TYPE] = { .type = NLA_U16 },
[RTA_ENCAP] = { .type = NLA_NESTED },
[RTA_UID] = { .type = NLA_U32 },
[RTA_MARK] = { .type = NLA_U32 },
};
static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
struct nlmsghdr *nlh, struct fib_config *cfg)
{
struct