Release 4.11 net/core/rtnetlink.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.
*
* Routing netlink socket interface: protocol independent part.
*
* 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.
*
* Fixes:
* Vitaly E. Lavrov RTA_OK arithmetics was wrong.
*/
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/capability.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/security.h>
#include <linux/mutex.h>
#include <linux/if_addr.h>
#include <linux/if_bridge.h>
#include <linux/if_vlan.h>
#include <linux/pci.h>
#include <linux/etherdevice.h>
#include <linux/uaccess.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <net/switchdev.h>
#include <net/ip.h>
#include <net/protocol.h>
#include <net/arp.h>
#include <net/route.h>
#include <net/udp.h>
#include <net/tcp.h>
#include <net/sock.h>
#include <net/pkt_sched.h>
#include <net/fib_rules.h>
#include <net/rtnetlink.h>
#include <net/net_namespace.h>
struct rtnl_link {
rtnl_doit_func doit;
rtnl_dumpit_func dumpit;
rtnl_calcit_func calcit;
};
static DEFINE_MUTEX(rtnl_mutex);
void rtnl_lock(void)
{
mutex_lock(&rtnl_mutex);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 5 | 38.46% | 1 | 33.33% |
Stephen Hemminger | 5 | 38.46% | 1 | 33.33% |
Linus Torvalds | 3 | 23.08% | 1 | 33.33% |
Total | 13 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL(rtnl_lock);
static struct sk_buff *defer_kfree_skb_list;
void rtnl_kfree_skbs(struct sk_buff *head, struct sk_buff *tail)
{
if (head && tail) {
tail->next = defer_kfree_skb_list;
defer_kfree_skb_list = head;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Eric Dumazet | 33 | 100.00% | 1 | 100.00% |
Total | 33 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL(rtnl_kfree_skbs);
void __rtnl_unlock(void)
{
struct sk_buff *head = defer_kfree_skb_list;
defer_kfree_skb_list = NULL;
mutex_unlock(&rtnl_mutex);
while (head) {
struct sk_buff *next = head->next;
kfree_skb(head);
cond_resched();
head = next;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Eric Dumazet | 38 | 74.51% | 1 | 33.33% |
Christoph Hellwig | 8 | 15.69% | 1 | 33.33% |
Stephen Hemminger | 5 | 9.80% | 1 | 33.33% |
Total | 51 | 100.00% | 3 | 100.00% |
void rtnl_unlock(void)
{
/* This fellow will unlock it for us. */
netdev_run_todo();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 7 | 63.64% | 2 | 40.00% |
David S. Miller | 3 | 27.27% | 2 | 40.00% |
Herbert Xu | 1 | 9.09% | 1 | 20.00% |
Total | 11 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL(rtnl_unlock);
int rtnl_trylock(void)
{
return mutex_trylock(&rtnl_mutex);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Stephen Hemminger | 14 | 100.00% | 1 | 100.00% |
Total | 14 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL(rtnl_trylock);
int rtnl_is_locked(void)
{
return mutex_is_locked(&rtnl_mutex);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 14 | 100.00% | 1 | 100.00% |
Total | 14 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL(rtnl_is_locked);
#ifdef CONFIG_PROVE_LOCKING
bool lockdep_rtnl_is_held(void)
{
return lockdep_is_held(&rtnl_mutex);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Paul E. McKenney | 13 | 92.86% | 1 | 50.00% |
Yaowei Bai | 1 | 7.14% | 1 | 50.00% |
Total | 14 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(lockdep_rtnl_is_held);
#endif /* #ifdef CONFIG_PROVE_LOCKING */
static struct rtnl_link *rtnl_msg_handlers[RTNL_FAMILY_MAX + 1];
static inline int rtm_msgindex(int msgtype)
{
int msgindex = msgtype - RTM_BASE;
/*
* msgindex < 0 implies someone tried to register a netlink
* control code. msgindex >= RTM_NR_MSGTYPES may indicate that
* the message type has not been added to linux/rtnetlink.h
*/
BUG_ON(msgindex < 0 || msgindex >= RTM_NR_MSGTYPES);
return msgindex;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 32 | 100.00% | 1 | 100.00% |
Total | 32 | 100.00% | 1 | 100.00% |
static rtnl_doit_func rtnl_get_doit(int protocol, int msgindex)
{
struct rtnl_link *tab;
if (protocol <= RTNL_FAMILY_MAX)
tab = rtnl_msg_handlers[protocol];
else
tab = NULL;
if (tab == NULL || tab[msgindex].doit == NULL)
tab = rtnl_msg_handlers[PF_UNSPEC];
return tab[msgindex].doit;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 54 | 83.08% | 2 | 50.00% |
Patrick McHardy | 11 | 16.92% | 2 | 50.00% |
Total | 65 | 100.00% | 4 | 100.00% |
static rtnl_dumpit_func rtnl_get_dumpit(int protocol, int msgindex)
{
struct rtnl_link *tab;
if (protocol <= RTNL_FAMILY_MAX)
tab = rtnl_msg_handlers[protocol];
else
tab = NULL;
if (tab == NULL || tab[msgindex].dumpit == NULL)
tab = rtnl_msg_handlers[PF_UNSPEC];
return tab[msgindex].dumpit;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 54 | 83.08% | 2 | 50.00% |
Patrick McHardy | 11 | 16.92% | 2 | 50.00% |
Total | 65 | 100.00% | 4 | 100.00% |
static rtnl_calcit_func rtnl_get_calcit(int protocol, int msgindex)
{
struct rtnl_link *tab;
if (protocol <= RTNL_FAMILY_MAX)
tab = rtnl_msg_handlers[protocol];
else
tab = NULL;
if (tab == NULL || tab[msgindex].calcit == NULL)
tab = rtnl_msg_handlers[PF_UNSPEC];
return tab[msgindex].calcit;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Greg Rose | 65 | 100.00% | 1 | 100.00% |
Total | 65 | 100.00% | 1 | 100.00% |
/**
* __rtnl_register - Register a rtnetlink message type
* @protocol: Protocol family or PF_UNSPEC
* @msgtype: rtnetlink message type
* @doit: Function pointer called for each request message
* @dumpit: Function pointer called for each dump request (NLM_F_DUMP) message
* @calcit: Function pointer to calc size of dump message
*
* Registers the specified function pointers (at least one of them has
* to be non-NULL) to be called whenever a request message for the
* specified protocol family and message type is received.
*
* The special protocol family PF_UNSPEC may be used to define fallback
* function pointers for the case when no entry for the specific protocol
* family exists.
*
* Returns 0 on success or a negative error code.
*/
int __rtnl_register(int protocol, int msgtype,
rtnl_doit_func doit, rtnl_dumpit_func dumpit,
rtnl_calcit_func calcit)
{
struct rtnl_link *tab;
int msgindex;
BUG_ON(protocol < 0 || protocol > RTNL_FAMILY_MAX);
msgindex = rtm_msgindex(msgtype);
tab = rtnl_msg_handlers[protocol];
if (tab == NULL) {
tab = kcalloc(RTM_NR_MSGTYPES, sizeof(*tab), GFP_KERNEL);
if (tab == NULL)
return -ENOBUFS;
rtnl_msg_handlers[protocol] = tab;
}
if (doit)
tab[msgindex].doit = doit;
if (dumpit)
tab[msgindex].dumpit = dumpit;
if (calcit)
tab[msgindex].calcit = calcit;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 117 | 86.67% | 1 | 33.33% |
Greg Rose | 16 | 11.85% | 1 | 33.33% |
Patrick McHardy | 2 | 1.48% | 1 | 33.33% |
Total | 135 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL_GPL(__rtnl_register);
/**
* rtnl_register - Register a rtnetlink message type
*
* Identical to __rtnl_register() but panics on failure. This is useful
* as failure of this function is very unlikely, it can only happen due
* to lack of memory when allocating the chain to store all message
* handlers for a protocol. Meant for use in init functions where lack
* of memory implies no sense in continuing.
*/
void rtnl_register(int protocol, int msgtype,
rtnl_doit_func doit, rtnl_dumpit_func dumpit,
rtnl_calcit_func calcit)
{
if (__rtnl_register(protocol, msgtype, doit, dumpit, calcit) < 0)
panic("Unable to register rtnetlink message handler, "
"protocol = %d, message type = %d\n",
protocol, msgtype);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 42 | 89.36% | 1 | 50.00% |
Greg Rose | 5 | 10.64% | 1 | 50.00% |
Total | 47 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL_GPL(rtnl_register);
/**
* rtnl_unregister - Unregister a rtnetlink message type
* @protocol: Protocol family or PF_UNSPEC
* @msgtype: rtnetlink message type
*
* Returns 0 on success or a negative error code.
*/
int rtnl_unregister(int protocol, int msgtype)
{
int msgindex;
BUG_ON(protocol < 0 || protocol > RTNL_FAMILY_MAX);
msgindex = rtm_msgindex(msgtype);
if (rtnl_msg_handlers[protocol] == NULL)
return -ENOENT;
rtnl_msg_handlers[protocol][msgindex].doit = NULL;
rtnl_msg_handlers[protocol][msgindex].dumpit = NULL;
rtnl_msg_handlers[protocol][msgindex].calcit = NULL;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 70 | 83.33% | 1 | 33.33% |
Mathias Krause | 12 | 14.29% | 1 | 33.33% |
Patrick McHardy | 2 | 2.38% | 1 | 33.33% |
Total | 84 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL_GPL(rtnl_unregister);
/**
* rtnl_unregister_all - Unregister all rtnetlink message type of a protocol
* @protocol : Protocol family or PF_UNSPEC
*
* Identical to calling rtnl_unregster() for all registered message types
* of a certain protocol family.
*/
void rtnl_unregister_all(int protocol)
{
BUG_ON(protocol < 0 || protocol > RTNL_FAMILY_MAX);
kfree(rtnl_msg_handlers[protocol]);
rtnl_msg_handlers[protocol] = NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 32 | 94.12% | 1 | 50.00% |
Patrick McHardy | 2 | 5.88% | 1 | 50.00% |
Total | 34 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL_GPL(rtnl_unregister_all);
static LIST_HEAD(link_ops);
static const struct rtnl_link_ops *rtnl_link_ops_get(const char *kind)
{
const struct rtnl_link_ops *ops;
list_for_each_entry(ops, &link_ops, list) {
if (!strcmp(ops->kind, kind))
return ops;
}
return NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Eric Dumazet | 48 | 100.00% | 1 | 100.00% |
Total | 48 | 100.00% | 1 | 100.00% |
/**
* __rtnl_link_register - Register rtnl_link_ops with rtnetlink.
* @ops: struct rtnl_link_ops * to register
*
* The caller must hold the rtnl_mutex. This function should be used
* by drivers that create devices during module initialization. It
* must be called before registering the devices.
*
* Returns 0 on success or a negative error code.
*/
int __rtnl_link_register(struct rtnl_link_ops *ops)
{
if (rtnl_link_ops_get(ops->kind))
return -EEXIST;
/* The check for setup is here because if ops
* does not have that filled up, it is not possible
* to use the ops for creating device. So do not
* fill up dellink as well. That disables rtnl_dellink.
*/
if (ops->setup && !ops->dellink)
ops->dellink = unregister_netdevice_queue;
list_add_tail(&ops->list, &link_ops);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 34 | 61.82% | 2 | 33.33% |
Eric Dumazet | 14 | 25.45% | 2 | 33.33% |
Jiri Pirko | 5 | 9.09% | 1 | 16.67% |
Linus Torvalds (pre-git) | 2 | 3.64% | 1 | 16.67% |
Total | 55 | 100.00% | 6 | 100.00% |
EXPORT_SYMBOL_GPL(__rtnl_link_register);
/**
* rtnl_link_register - Register rtnl_link_ops with rtnetlink.
* @ops: struct rtnl_link_ops * to register
*
* Returns 0 on success or a negative error code.
*/
int rtnl_link_register(struct rtnl_link_ops *ops)
{
int err;
rtnl_lock();
err = __rtnl_link_register(ops);
rtnl_unlock();
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 27 | 93.10% | 1 | 33.33% |
Thomas Graf | 1 | 3.45% | 1 | 33.33% |
Linus Torvalds (pre-git) | 1 | 3.45% | 1 | 33.33% |
Total | 29 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL_GPL(rtnl_link_register);
static void __rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops)
{
struct net_device *dev;
LIST_HEAD(list_kill);
for_each_netdev(net, dev) {
if (dev->rtnl_link_ops == ops)
ops->dellink(dev, &list_kill);
}
unregister_netdevice_many(&list_kill);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 33 | 56.90% | 2 | 33.33% |
Eric Dumazet | 14 | 24.14% | 1 | 16.67% |
Pavel Emelyanov | 8 | 13.79% | 2 | 33.33% |
Eric W. Biedermann | 3 | 5.17% | 1 | 16.67% |
Total | 58 | 100.00% | 6 | 100.00% |
/**
* __rtnl_link_unregister - Unregister rtnl_link_ops from rtnetlink.
* @ops: struct rtnl_link_ops * to unregister
*
* The caller must hold the rtnl_mutex.
*/
void __rtnl_link_unregister(struct rtnl_link_ops *ops)
{
struct net *net;
for_each_net(net) {
__rtnl_kill_links(net, ops);
}
list_del(&ops->list);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Pavel Emelyanov | 27 | 75.00% | 1 | 33.33% |
Patrick McHardy | 8 | 22.22% | 1 | 33.33% |
Linus Torvalds (pre-git) | 1 | 2.78% | 1 | 33.33% |
Total | 36 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL_GPL(__rtnl_link_unregister);
/* Return with the rtnl_lock held when there are no network
* devices unregistering in any network namespace.
*/
static void rtnl_lock_unregistering_all(void)
{
struct net *net;
bool unregistering;
DEFINE_WAIT_FUNC(wait, woken_wake_function);
add_wait_queue(&netdev_unregistering_wq, &wait);
for (;;) {
unregistering = false;
rtnl_lock();
for_each_net(net) {
if (net->dev_unreg_count > 0) {
unregistering = true;
break;
}
}
if (!unregistering)
break;
__rtnl_unlock();
wait_woken(&wait, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
remove_wait_queue(&netdev_unregistering_wq, &wait);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Cong Wang | 75 | 78.95% | 1 | 50.00% |
Peter Zijlstra | 20 | 21.05% | 1 | 50.00% |
Total | 95 | 100.00% | 2 | 100.00% |
/**
* rtnl_link_unregister - Unregister rtnl_link_ops from rtnetlink.
* @ops: struct rtnl_link_ops * to unregister
*/
void rtnl_link_unregister(struct rtnl_link_ops *ops)
{
/* Close the race with cleanup_net() */
mutex_lock(&net_mutex);
rtnl_lock_unregistering_all();
__rtnl_link_unregister(ops);
rtnl_unlock();
mutex_unlock(&net_mutex);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 19 | 55.88% | 1 | 33.33% |
Cong Wang | 14 | 41.18% | 1 | 33.33% |
Linus Torvalds (pre-git) | 1 | 2.94% | 1 | 33.33% |
Total | 34 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL_GPL(rtnl_link_unregister);
static size_t rtnl_link_get_slave_info_data_size(const struct net_device *dev)
{
struct net_device *master_dev;
const struct rtnl_link_ops *ops;
master_dev = netdev_master_upper_dev_get((struct net_device *) dev);
if (!master_dev)
return 0;
ops = master_dev->rtnl_link_ops;
if (!ops || !ops->get_slave_size)
return 0;
/* IFLA_INFO_SLAVE_DATA + nested data */
return nla_total_size(sizeof(struct nlattr)) +
ops->get_slave_size(master_dev, dev);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jiri Pirko | 79 | 96.34% | 1 | 50.00% |
Fernando Luis Vázquez Cao | 3 | 3.66% | 1 | 50.00% |
Total | 82 | 100.00% | 2 | 100.00% |
static size_t rtnl_link_get_size(const struct net_device *dev)
{
const struct rtnl_link_ops *ops = dev->rtnl_link_ops;
size_t size;
if (!ops)
return 0;
size = nla_total_size(sizeof(struct nlattr)) + /* IFLA_LINKINFO */
nla_total_size(strlen(ops->kind) + 1); /* IFLA_INFO_KIND */
if (ops->get_size)
/* IFLA_INFO_DATA + nested data */
size += nla_total_size(sizeof(struct nlattr)) +
ops->get_size(dev);
if (ops->get_xstats_size)
/* IFLA_INFO_XSTATS */
size += nla_total_size(ops->get_xstats_size(dev));
size += rtnl_link_get_slave_info_data_size(dev);
return size;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 81 | 72.32% | 1 | 20.00% |
Thomas Graf | 12 | 10.71% | 2 | 40.00% |
Linus Torvalds (pre-git) | 12 | 10.71% | 1 | 20.00% |
Jiri Pirko | 7 | 6.25% | 1 | 20.00% |
Total | 112 | 100.00% | 5 | 100.00% |
static LIST_HEAD(rtnl_af_ops);
static const struct rtnl_af_ops *rtnl_af_lookup(const int family)
{
const struct rtnl_af_ops *ops;
list_for_each_entry(ops, &rtnl_af_ops, list) {
if (ops->family == family)
return ops;
}
return NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 43 | 100.00% | 1 | 100.00% |
Total | 43 | 100.00% | 1 | 100.00% |
/**
* rtnl_af_register - Register rtnl_af_ops with rtnetlink.
* @ops: struct rtnl_af_ops * to register
*
* Returns 0 on success or a negative error code.
*/
void rtnl_af_register(struct rtnl_af_ops *ops)
{
rtnl_lock();
list_add_tail(&ops->list, &rtnl_af_ops);
rtnl_unlock();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 22 | 81.48% | 1 | 50.00% |
Stephen Hemminger | 5 | 18.52% | 1 | 50.00% |
Total | 27 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL_GPL(rtnl_af_register);
/**
* __rtnl_af_unregister - Unregister rtnl_af_ops from rtnetlink.
* @ops: struct rtnl_af_ops * to unregister
*
* The caller must hold the rtnl_mutex.
*/
void __rtnl_af_unregister(struct rtnl_af_ops *ops)
{
list_del(&ops->list);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 18 | 100.00% | 1 | 100.00% |
Total | 18 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL_GPL(__rtnl_af_unregister);
/**
* rtnl_af_unregister - Unregister rtnl_af_ops from rtnetlink.
* @ops: struct rtnl_af_ops * to unregister
*/
void rtnl_af_unregister(struct rtnl_af_ops *ops)
{
rtnl_lock();
__rtnl_af_unregister(ops);
rtnl_unlock();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 21 | 100.00% | 1 | 100.00% |
Total | 21 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL_GPL(rtnl_af_unregister);
static size_t rtnl_link_get_af_size(const struct net_device *dev,
u32 ext_filter_mask)
{
struct rtnl_af_ops *af_ops;
size_t size;
/* IFLA_AF_SPEC */
size = nla_total_size(sizeof(struct nlattr));
list_for_each_entry(af_ops, &rtnl_af_ops, list) {
if (af_ops->get_link_af_size) {
/* AF_* + nested data */
size += nla_total_size(sizeof(struct nlattr)) +
af_ops->get_link_af_size(dev, ext_filter_mask);
}
}
return size;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 72 | 93.51% | 1 | 50.00% |
Arad, Ronen | 5 | 6.49% | 1 | 50.00% |
Total | 77 | 100.00% | 2 | 100.00% |
static bool rtnl_have_link_slave_info(const struct net_device *dev)
{
struct net_device *master_dev;
master_dev = netdev_master_upper_dev_get((struct net_device *) dev);
if (master_dev && master_dev->rtnl_link_ops)
return true;
return false;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jiri Pirko | 43 | 100.00% | 1 | 100.00% |
Total | 43 | 100.00% | 1 | 100.00% |
static int rtnl_link_slave_info_fill(struct sk_buff *skb,
const struct net_device *dev)
{
struct net_device *master_dev;
const struct rtnl_link_ops *ops;
struct nlattr *slave_data;
int err;
master_dev = netdev_master_upper_dev_get((struct net_device *) dev);
if (!master_dev)
return 0;
ops = master_dev->rtnl_link_ops;
if (!ops)
return 0;
if (nla_put_string(skb, IFLA_INFO_SLAVE_KIND, ops->kind) < 0)
return -EMSGSIZE;
if (ops->fill_slave_info) {
slave_data = nla_nest_start(skb, IFLA_INFO_SLAVE_DATA);
if (!slave_data)
return -EMSGSIZE;
err = ops->fill_slave_info(skb, master_dev, dev);
if (err < 0)
goto err_cancel_slave_data;
nla_nest_end(skb, slave_data);
}
return 0;
err_cancel_slave_data:
nla_nest_cancel(skb, slave_data);
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jiri Pirko | 118 | 74.21% | 1 | 25.00% |
Patrick McHardy | 39 | 24.53% | 1 | 25.00% |
Linus Torvalds (pre-git) | 1 | 0.63% | 1 | 25.00% |
Thomas Graf | 1 | 0.63% | 1 | 25.00% |
Total | 159 | 100.00% | 4 | 100.00% |
static int rtnl_link_info_fill(struct sk_buff *skb,
const struct net_device *dev)
{
const struct rtnl_link_ops *ops = dev->rtnl_link_ops;
struct nlattr *data;
int err;
if (!ops)
return 0;
if (nla_put_string(skb, IFLA_INFO_KIND, ops->kind) < 0)
return -EMSGSIZE;
if (ops->fill_xstats) {
err = ops->fill_xstats(skb, dev);
if (err < 0)
return err;
}
if (ops->fill_info) {
data = nla_nest_start(skb, IFLA_INFO_DATA);
if (data == NULL)
return -EMSGSIZE;
err = ops->fill_info(skb, dev);
if (err < 0)
goto err_cancel_data;
nla_nest_end(skb, data);
}
return 0;
err_cancel_data:
nla_nest_cancel(skb, data);
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jiri Pirko | 129 | 81.13% | 1 | 33.33% |
Patrick McHardy | 29 | 18.24% | 1 | 33.33% |
Linus Torvalds (pre-git) | 1 | 0.63% | 1 | 33.33% |
Total | 159 | 100.00% | 3 | 100.00% |
static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev)
{
struct nlattr *linkinfo;
int err = -EMSGSIZE;
linkinfo = nla_nest_start(skb, IFLA_LINKINFO);
if (linkinfo == NULL)
goto out;
err = rtnl_link_info_fill(skb, dev);
if (err < 0)
goto err_cancel_link;
err = rtnl_link_slave_info_fill(skb, dev);
if (err < 0)
goto err_cancel_link;
nla_nest_end(skb, linkinfo);
return 0;
err_cancel_link:
nla_nest_cancel(skb, linkinfo);
out:
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 57 | 53.77% | 1 | 25.00% |
Jiri Pirko | 46 | 43.40% | 1 | 25.00% |
Linus Torvalds (pre-git) | 2 | 1.89% | 1 | 25.00% |
Wei Yongjun | 1 | 0.94% | 1 | 25.00% |
Total | 106 | 100.00% | 4 | 100.00% |
int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned int group, int echo)
{
struct sock *rtnl = net->rtnl;
int err = 0;
NETLINK_CB(skb).dst_group = group;
if (echo)
atomic_inc(&skb->users);
netlink_broadcast(rtnl, skb, pid, group, GFP_KERNEL);
if (echo)
err = netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT);
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 77 | 82.80% | 1 | 25.00% |
Denis V. Lunev | 14 | 15.05% | 1 | 25.00% |
Patrick McHardy | 1 | 1.08% | 1 | 25.00% |
Eric Dumazet | 1 | 1.08% | 1 | 25.00% |
Total | 93 | 100.00% | 4 | 100.00% |
int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid)
{
struct sock *rtnl = net->rtnl;
return nlmsg_unicast(rtnl, skb, pid);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 23 | 62.16% | 1 | 50.00% |
Denis V. Lunev | 14 | 37.84% | 1 | 50.00% |
Total | 37 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(rtnl_unicast);
void rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
struct nlmsghdr *nlh, gfp_t flags)
{
struct sock *rtnl = net->rtnl;
int report = 0;
if (nlh)
report = nlmsg_report(nlh);
nlmsg_notify(rtnl, skb, pid, group, report, flags);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 53 | 76.81% | 1 | 33.33% |
Denis V. Lunev | 14 | 20.29% | 1 | 33.33% |
Pablo Neira Ayuso | 2 | 2.90% | 1 | 33.33% |
Total | 69 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL(rtnl_notify);
void rtnl_set_sk_err(struct net *net, u32 group, int error)
{
struct sock *rtnl = net->rtnl;
netlink_set_err(rtnl, 0, group, error);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 22 | 61.11% | 1 | 50.00% |
Denis V. Lunev | 14 | 38.89% | 1 | 50.00% |
Total | 36 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(rtnl_set_sk_err);
int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics)
{
struct nlattr *mx;
int i, valid = 0;
mx = nla_nest_start(skb, RTA_METRICS);
if (mx == NULL)
return -ENOBUFS;
for (i = 0; i < RTAX_MAX; i++) {
if (metrics[i]) {
if (i == RTAX_CC_ALGO - 1) {
char tmp[TCP_CA_NAME_MAX], *name;
name = tcp_ca_get_name_by_key(metrics[i], tmp);
if (!name)
continue;
if (nla_put_string(skb, i + 1, name))
goto nla_put_failure;
} else if (i == RTAX_FEATURES - 1) {
u32 user_features = metrics[i] & RTAX_FEATURE_MASK;
if (!user_features)
continue;
BUILD_BUG_ON(RTAX_FEATURE_MASK & DST_FEATURE_MASK);
if (nla_put_u32(skb, i + 1, user_features))
goto nla_put_failure;
} else {
if (nla_put_u32(skb, i + 1, metrics[i]))
goto nla_put_failure;
}
valid++;
}
}
if (!valid) {
nla_nest_cancel(skb, mx);
return 0;
}
return nla_nest_end(skb, mx);
nla_put_failure:
nla_nest_cancel(skb, mx);
return -EMSGSIZE;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Daniel Borkmann | 102 | 43.40% | 2 | 22.22% |
Linus Torvalds (pre-git) | 74 | 31.49% | 1 | 11.11% |
Thomas Graf | 33 | 14.04% | 2 | 22.22% |
David S. Miller | 19 | 8.09% | 2 | 22.22% |
Phil Sutter | 6 | 2.55% | 1 | 11.11% |
Alexey Kuznetsov | 1 | 0.43% | 1 | 11.11% |
Total | 235 | 100.00% | 9 | 100.00% |
EXPORT_SYMBOL(rtnetlink_put_metrics);
int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, u32 id,
long expires, u32 error)
{
struct rta_cacheinfo ci = {
.rta_lastuse = jiffies_delta_to_clock_t(jiffies - dst->lastuse),
.rta_used = dst->__use,
.rta_clntref = atomic_read(&(dst->__refcnt)),
.rta_error = error,
.rta_id = id,
};
if (expires) {
unsigned long clock;
clock = jiffies_to_clock_t(abs(expires));
clock = min_t(unsigned long, clock, INT_MAX);
ci.rta_expires = (expires > 0) ? clock : -clock;
}
return nla_put(skb, RTA_CACHEINFO, sizeof(ci), &ci);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Graf | 97 | 72.39% | 1 | 33.33% |
Li Wei | 36 | 26.87% | 1 | 33.33% |
Eric Dumazet | 1 | 0.75% | 1 | 33.33% |
Total | 134 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL_GPL(rtnl_put_cacheinfo);
static void set_operstate(struct net_device *dev, unsigned char transition)
{
unsigned char operstate = dev->operstate;
switch (transition) {
case IF_OPER_UP:
if ((operstate == IF_OPER_DORMANT ||
operstate == IF_OPER_UNKNOWN) &&
!netif_dormant(dev))
operstate = IF_OPER_UP;
break;
case IF_OPER_DORMANT:
if (operstate == IF_OPER_UP ||
operstate == IF_OPER_UNKNOWN)
operstate = IF_OPER_DORMANT;
break;
}
if (dev->operstate != operstate) {
write_lock_bh(&dev_base_lock);
dev->operstate = operstate;
write_unlock_bh(&dev_base_lock);
netdev_state_change(dev);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Stefan Rompf | 105 | 99.06% | 1 | 50.00% |
David S. Miller | 1 | 0.94% | 1 | 50.00% |
Total | 106 | 100.00% | 2 | 100.00% |
static unsigned int rtnl_dev_get_flags(const struct net_device *dev)
{
return (dev->flags & ~(IFF_PROMISC | IFF_ALLMULTI)) |
(dev->gflags & (IFF_PROMISC | IFF_ALLMULTI));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jiri Benc | 39 | 100.00% | 1 | 100.00% |
Total | 39 | 100.00% | 1 | 100.00% |
static unsigned int rtnl_dev_combine_flags(const struct net_device *dev,
const struct ifinfomsg *ifm)
{
unsigned int flags = ifm->ifi_flags;
/* bugwards compatibility: ifi_change == 0 is treated as ~0 */