aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/rtnetlink.h14
-rw-r--r--include/uapi/linux/if_link.h2
-rw-r--r--net/core/rtnetlink.c158
3 files changed, 154 insertions, 20 deletions
diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h
index 8fb42070a2c1..661e45d38051 100644
--- a/include/net/rtnetlink.h
+++ b/include/net/rtnetlink.h
@@ -79,6 +79,20 @@ struct rtnl_link_ops {
79 const struct net_device *dev); 79 const struct net_device *dev);
80 unsigned int (*get_num_tx_queues)(void); 80 unsigned int (*get_num_tx_queues)(void);
81 unsigned int (*get_num_rx_queues)(void); 81 unsigned int (*get_num_rx_queues)(void);
82
83 int slave_maxtype;
84 const struct nla_policy *slave_policy;
85 int (*slave_validate)(struct nlattr *tb[],
86 struct nlattr *data[]);
87 int (*slave_changelink)(struct net_device *dev,
88 struct net_device *slave_dev,
89 struct nlattr *tb[],
90 struct nlattr *data[]);
91 size_t (*get_slave_size)(const struct net_device *dev,
92 const struct net_device *slave_dev);
93 int (*fill_slave_info)(struct sk_buff *skb,
94 const struct net_device *dev,
95 const struct net_device *slave_dev);
82}; 96};
83 97
84int __rtnl_link_register(struct rtnl_link_ops *ops); 98int __rtnl_link_register(struct rtnl_link_ops *ops);
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 1f30b85ebf9d..b8fb352b58f6 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -241,6 +241,8 @@ enum {
241 IFLA_INFO_KIND, 241 IFLA_INFO_KIND,
242 IFLA_INFO_DATA, 242 IFLA_INFO_DATA,
243 IFLA_INFO_XSTATS, 243 IFLA_INFO_XSTATS,
244 IFLA_INFO_SLAVE_KIND,
245 IFLA_INFO_SLAVE_DATA,
244 __IFLA_INFO_MAX, 246 __IFLA_INFO_MAX,
245}; 247};
246 248
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index cace14962234..a56bccf6629e 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -365,6 +365,22 @@ void rtnl_link_unregister(struct rtnl_link_ops *ops)
365} 365}
366EXPORT_SYMBOL_GPL(rtnl_link_unregister); 366EXPORT_SYMBOL_GPL(rtnl_link_unregister);
367 367
368static size_t rtnl_link_get_slave_info_data_size(const struct net_device *dev)
369{
370 struct net_device *master_dev;
371 const struct rtnl_link_ops *ops;
372
373 master_dev = netdev_master_upper_dev_get((struct net_device *) dev);
374 if (!master_dev)
375 return 0;
376 ops = master_dev->rtnl_link_ops;
377 if (!ops->get_slave_size)
378 return 0;
379 /* IFLA_INFO_SLAVE_DATA + nested data */
380 return nla_total_size(sizeof(struct nlattr)) +
381 ops->get_slave_size(master_dev, dev);
382}
383
368static size_t rtnl_link_get_size(const struct net_device *dev) 384static size_t rtnl_link_get_size(const struct net_device *dev)
369{ 385{
370 const struct rtnl_link_ops *ops = dev->rtnl_link_ops; 386 const struct rtnl_link_ops *ops = dev->rtnl_link_ops;
@@ -385,6 +401,8 @@ static size_t rtnl_link_get_size(const struct net_device *dev)
385 /* IFLA_INFO_XSTATS */ 401 /* IFLA_INFO_XSTATS */
386 size += nla_total_size(ops->get_xstats_size(dev)); 402 size += nla_total_size(ops->get_xstats_size(dev));
387 403
404 size += rtnl_link_get_slave_info_data_size(dev);
405
388 return size; 406 return size;
389} 407}
390 408
@@ -459,40 +477,101 @@ static size_t rtnl_link_get_af_size(const struct net_device *dev)
459 return size; 477 return size;
460} 478}
461 479
462static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev) 480static bool rtnl_have_link_slave_info(const struct net_device *dev)
463{ 481{
464 const struct rtnl_link_ops *ops = dev->rtnl_link_ops; 482 struct net_device *master_dev;
465 struct nlattr *linkinfo, *data;
466 int err = -EMSGSIZE;
467 483
468 linkinfo = nla_nest_start(skb, IFLA_LINKINFO); 484 master_dev = netdev_master_upper_dev_get((struct net_device *) dev);
469 if (linkinfo == NULL) 485 if (master_dev && master_dev->rtnl_link_ops &&
470 goto out; 486 master_dev->rtnl_link_ops->fill_slave_info)
487 return true;
488 return false;
489}
490
491static int rtnl_link_slave_info_fill(struct sk_buff *skb,
492 const struct net_device *dev)
493{
494 struct net_device *master_dev;
495 const struct rtnl_link_ops *ops;
496 struct nlattr *slave_data;
497 int err;
471 498
499 master_dev = netdev_master_upper_dev_get((struct net_device *) dev);
500 if (!master_dev)
501 return 0;
502 ops = master_dev->rtnl_link_ops;
503 if (!ops)
504 return 0;
505 if (nla_put_string(skb, IFLA_INFO_SLAVE_KIND, ops->kind) < 0)
506 return -EMSGSIZE;
507 if (ops->fill_slave_info) {
508 slave_data = nla_nest_start(skb, IFLA_INFO_SLAVE_DATA);
509 if (!slave_data)
510 return -EMSGSIZE;
511 err = ops->fill_slave_info(skb, master_dev, dev);
512 if (err < 0)
513 goto err_cancel_slave_data;
514 nla_nest_end(skb, slave_data);
515 }
516 return 0;
517
518err_cancel_slave_data:
519 nla_nest_cancel(skb, slave_data);
520 return err;
521}
522
523static int rtnl_link_info_fill(struct sk_buff *skb,
524 const struct net_device *dev)
525{
526 const struct rtnl_link_ops *ops = dev->rtnl_link_ops;
527 struct nlattr *data;
528 int err;
529
530 if (!ops)
531 return 0;
472 if (nla_put_string(skb, IFLA_INFO_KIND, ops->kind) < 0) 532 if (nla_put_string(skb, IFLA_INFO_KIND, ops->kind) < 0)
473 goto err_cancel_link; 533 return -EMSGSIZE;
474 if (ops->fill_xstats) { 534 if (ops->fill_xstats) {
475 err = ops->fill_xstats(skb, dev); 535 err = ops->fill_xstats(skb, dev);
476 if (err < 0) 536 if (err < 0)
477 goto err_cancel_link; 537 return err;
478 } 538 }
479 if (ops->fill_info) { 539 if (ops->fill_info) {
480 data = nla_nest_start(skb, IFLA_INFO_DATA); 540 data = nla_nest_start(skb, IFLA_INFO_DATA);
481 if (data == NULL) { 541 if (data == NULL)
482 err = -EMSGSIZE; 542 return -EMSGSIZE;
483 goto err_cancel_link;
484 }
485 err = ops->fill_info(skb, dev); 543 err = ops->fill_info(skb, dev);
486 if (err < 0) 544 if (err < 0)
487 goto err_cancel_data; 545 goto err_cancel_data;
488 nla_nest_end(skb, data); 546 nla_nest_end(skb, data);
489 } 547 }
490
491 nla_nest_end(skb, linkinfo);
492 return 0; 548 return 0;
493 549
494err_cancel_data: 550err_cancel_data:
495 nla_nest_cancel(skb, data); 551 nla_nest_cancel(skb, data);
552 return err;
553}
554
555static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev)
556{
557 struct nlattr *linkinfo;
558 int err = -EMSGSIZE;
559
560 linkinfo = nla_nest_start(skb, IFLA_LINKINFO);
561 if (linkinfo == NULL)
562 goto out;
563
564 err = rtnl_link_info_fill(skb, dev);
565 if (err < 0)
566 goto err_cancel_link;
567
568 err = rtnl_link_slave_info_fill(skb, dev);
569 if (err < 0)
570 goto err_cancel_link;
571
572 nla_nest_end(skb, linkinfo);
573 return 0;
574
496err_cancel_link: 575err_cancel_link:
497 nla_nest_cancel(skb, linkinfo); 576 nla_nest_cancel(skb, linkinfo);
498out: 577out:
@@ -1052,10 +1131,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
1052 if (rtnl_port_fill(skb, dev)) 1131 if (rtnl_port_fill(skb, dev))
1053 goto nla_put_failure; 1132 goto nla_put_failure;
1054 1133
1055 if (rtnl_bond_slave_fill(skb, dev)) 1134 if (dev->rtnl_link_ops || rtnl_have_link_slave_info(dev)) {
1056 goto nla_put_failure;
1057
1058 if (dev->rtnl_link_ops) {
1059 if (rtnl_link_fill(skb, dev) < 0) 1135 if (rtnl_link_fill(skb, dev) < 0)
1060 goto nla_put_failure; 1136 goto nla_put_failure;
1061 } 1137 }
@@ -1178,6 +1254,8 @@ EXPORT_SYMBOL(ifla_policy);
1178static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { 1254static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
1179 [IFLA_INFO_KIND] = { .type = NLA_STRING }, 1255 [IFLA_INFO_KIND] = { .type = NLA_STRING },
1180 [IFLA_INFO_DATA] = { .type = NLA_NESTED }, 1256 [IFLA_INFO_DATA] = { .type = NLA_NESTED },
1257 [IFLA_INFO_SLAVE_KIND] = { .type = NLA_STRING },
1258 [IFLA_INFO_SLAVE_DATA] = { .type = NLA_NESTED },
1181}; 1259};
1182 1260
1183static const struct nla_policy ifla_vfinfo_policy[IFLA_VF_INFO_MAX+1] = { 1261static const struct nla_policy ifla_vfinfo_policy[IFLA_VF_INFO_MAX+1] = {
@@ -1765,7 +1843,9 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh)
1765{ 1843{
1766 struct net *net = sock_net(skb->sk); 1844 struct net *net = sock_net(skb->sk);
1767 const struct rtnl_link_ops *ops; 1845 const struct rtnl_link_ops *ops;
1846 const struct rtnl_link_ops *m_ops = NULL;
1768 struct net_device *dev; 1847 struct net_device *dev;
1848 struct net_device *master_dev = NULL;
1769 struct ifinfomsg *ifm; 1849 struct ifinfomsg *ifm;
1770 char kind[MODULE_NAME_LEN]; 1850 char kind[MODULE_NAME_LEN];
1771 char ifname[IFNAMSIZ]; 1851 char ifname[IFNAMSIZ];
@@ -1795,6 +1875,12 @@ replay:
1795 dev = NULL; 1875 dev = NULL;
1796 } 1876 }
1797 1877
1878 if (dev) {
1879 master_dev = netdev_master_upper_dev_get(dev);
1880 if (master_dev)
1881 m_ops = master_dev->rtnl_link_ops;
1882 }
1883
1798 err = validate_linkmsg(dev, tb); 1884 err = validate_linkmsg(dev, tb);
1799 if (err < 0) 1885 if (err < 0)
1800 return err; 1886 return err;
@@ -1816,7 +1902,10 @@ replay:
1816 } 1902 }
1817 1903
1818 if (1) { 1904 if (1) {
1819 struct nlattr *attr[ops ? ops->maxtype + 1 : 0], **data = NULL; 1905 struct nlattr *attr[ops ? ops->maxtype + 1 : 0];
1906 struct nlattr *slave_attr[m_ops ? m_ops->slave_maxtype + 1 : 0];
1907 struct nlattr **data = NULL;
1908 struct nlattr **slave_data = NULL;
1820 struct net *dest_net; 1909 struct net *dest_net;
1821 1910
1822 if (ops) { 1911 if (ops) {
@@ -1835,6 +1924,24 @@ replay:
1835 } 1924 }
1836 } 1925 }
1837 1926
1927 if (m_ops) {
1928 if (m_ops->slave_maxtype &&
1929 linkinfo[IFLA_INFO_SLAVE_DATA]) {
1930 err = nla_parse_nested(slave_attr,
1931 m_ops->slave_maxtype,
1932 linkinfo[IFLA_INFO_SLAVE_DATA],
1933 m_ops->slave_policy);
1934 if (err < 0)
1935 return err;
1936 slave_data = slave_attr;
1937 }
1938 if (m_ops->slave_validate) {
1939 err = m_ops->slave_validate(tb, slave_data);
1940 if (err < 0)
1941 return err;
1942 }
1943 }
1944
1838 if (dev) { 1945 if (dev) {
1839 int modified = 0; 1946 int modified = 0;
1840 1947
@@ -1854,6 +1961,17 @@ replay:
1854 modified = 1; 1961 modified = 1;
1855 } 1962 }
1856 1963
1964 if (linkinfo[IFLA_INFO_SLAVE_DATA]) {
1965 if (!m_ops || !m_ops->slave_changelink)
1966 return -EOPNOTSUPP;
1967
1968 err = m_ops->slave_changelink(master_dev, dev,
1969 tb, slave_data);
1970 if (err < 0)
1971 return err;
1972 modified = 1;
1973 }
1974
1857 return do_setlink(dev, ifm, tb, ifname, modified); 1975 return do_setlink(dev, ifm, tb, ifname, modified);
1858 } 1976 }
1859 1977