diff options
Diffstat (limited to 'net/core/rtnetlink.c')
-rw-r--r-- | net/core/rtnetlink.c | 110 |
1 files changed, 83 insertions, 27 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 1063996f8317..f0493e3b7471 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -299,7 +299,12 @@ int __rtnl_link_register(struct rtnl_link_ops *ops) | |||
299 | if (rtnl_link_ops_get(ops->kind)) | 299 | if (rtnl_link_ops_get(ops->kind)) |
300 | return -EEXIST; | 300 | return -EEXIST; |
301 | 301 | ||
302 | if (!ops->dellink) | 302 | /* The check for setup is here because if ops |
303 | * does not have that filled up, it is not possible | ||
304 | * to use the ops for creating device. So do not | ||
305 | * fill up dellink as well. That disables rtnl_dellink. | ||
306 | */ | ||
307 | if (ops->setup && !ops->dellink) | ||
303 | ops->dellink = unregister_netdevice_queue; | 308 | ops->dellink = unregister_netdevice_queue; |
304 | 309 | ||
305 | list_add_tail(&ops->list, &link_ops); | 310 | list_add_tail(&ops->list, &link_ops); |
@@ -799,7 +804,8 @@ static inline int rtnl_vfinfo_size(const struct net_device *dev, | |||
799 | (nla_total_size(sizeof(struct ifla_vf_mac)) + | 804 | (nla_total_size(sizeof(struct ifla_vf_mac)) + |
800 | nla_total_size(sizeof(struct ifla_vf_vlan)) + | 805 | nla_total_size(sizeof(struct ifla_vf_vlan)) + |
801 | nla_total_size(sizeof(struct ifla_vf_spoofchk)) + | 806 | nla_total_size(sizeof(struct ifla_vf_spoofchk)) + |
802 | nla_total_size(sizeof(struct ifla_vf_rate))); | 807 | nla_total_size(sizeof(struct ifla_vf_rate)) + |
808 | nla_total_size(sizeof(struct ifla_vf_link_state))); | ||
803 | return size; | 809 | return size; |
804 | } else | 810 | } else |
805 | return 0; | 811 | return 0; |
@@ -1777,7 +1783,7 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1777 | return -ENODEV; | 1783 | return -ENODEV; |
1778 | 1784 | ||
1779 | ops = dev->rtnl_link_ops; | 1785 | ops = dev->rtnl_link_ops; |
1780 | if (!ops) | 1786 | if (!ops || !ops->dellink) |
1781 | return -EOPNOTSUPP; | 1787 | return -EOPNOTSUPP; |
1782 | 1788 | ||
1783 | ops->dellink(dev, &list_kill); | 1789 | ops->dellink(dev, &list_kill); |
@@ -1805,7 +1811,8 @@ int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm) | |||
1805 | EXPORT_SYMBOL(rtnl_configure_link); | 1811 | EXPORT_SYMBOL(rtnl_configure_link); |
1806 | 1812 | ||
1807 | struct net_device *rtnl_create_link(struct net *net, | 1813 | struct net_device *rtnl_create_link(struct net *net, |
1808 | char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[]) | 1814 | char *ifname, unsigned char name_assign_type, |
1815 | const struct rtnl_link_ops *ops, struct nlattr *tb[]) | ||
1809 | { | 1816 | { |
1810 | int err; | 1817 | int err; |
1811 | struct net_device *dev; | 1818 | struct net_device *dev; |
@@ -1823,8 +1830,8 @@ struct net_device *rtnl_create_link(struct net *net, | |||
1823 | num_rx_queues = ops->get_num_rx_queues(); | 1830 | num_rx_queues = ops->get_num_rx_queues(); |
1824 | 1831 | ||
1825 | err = -ENOMEM; | 1832 | err = -ENOMEM; |
1826 | dev = alloc_netdev_mqs(ops->priv_size, ifname, ops->setup, | 1833 | dev = alloc_netdev_mqs(ops->priv_size, ifname, name_assign_type, |
1827 | num_tx_queues, num_rx_queues); | 1834 | ops->setup, num_tx_queues, num_rx_queues); |
1828 | if (!dev) | 1835 | if (!dev) |
1829 | goto err; | 1836 | goto err; |
1830 | 1837 | ||
@@ -1889,6 +1896,7 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1889 | char ifname[IFNAMSIZ]; | 1896 | char ifname[IFNAMSIZ]; |
1890 | struct nlattr *tb[IFLA_MAX+1]; | 1897 | struct nlattr *tb[IFLA_MAX+1]; |
1891 | struct nlattr *linkinfo[IFLA_INFO_MAX+1]; | 1898 | struct nlattr *linkinfo[IFLA_INFO_MAX+1]; |
1899 | unsigned char name_assign_type = NET_NAME_USER; | ||
1892 | int err; | 1900 | int err; |
1893 | 1901 | ||
1894 | #ifdef CONFIG_MODULES | 1902 | #ifdef CONFIG_MODULES |
@@ -2038,14 +2046,19 @@ replay: | |||
2038 | return -EOPNOTSUPP; | 2046 | return -EOPNOTSUPP; |
2039 | } | 2047 | } |
2040 | 2048 | ||
2041 | if (!ifname[0]) | 2049 | if (!ops->setup) |
2050 | return -EOPNOTSUPP; | ||
2051 | |||
2052 | if (!ifname[0]) { | ||
2042 | snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); | 2053 | snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); |
2054 | name_assign_type = NET_NAME_ENUM; | ||
2055 | } | ||
2043 | 2056 | ||
2044 | dest_net = rtnl_link_get_net(net, tb); | 2057 | dest_net = rtnl_link_get_net(net, tb); |
2045 | if (IS_ERR(dest_net)) | 2058 | if (IS_ERR(dest_net)) |
2046 | return PTR_ERR(dest_net); | 2059 | return PTR_ERR(dest_net); |
2047 | 2060 | ||
2048 | dev = rtnl_create_link(dest_net, ifname, ops, tb); | 2061 | dev = rtnl_create_link(dest_net, ifname, name_assign_type, ops, tb); |
2049 | if (IS_ERR(dev)) { | 2062 | if (IS_ERR(dev)) { |
2050 | err = PTR_ERR(dev); | 2063 | err = PTR_ERR(dev); |
2051 | goto out; | 2064 | goto out; |
@@ -2380,22 +2393,20 @@ int ndo_dflt_fdb_del(struct ndmsg *ndm, | |||
2380 | struct net_device *dev, | 2393 | struct net_device *dev, |
2381 | const unsigned char *addr) | 2394 | const unsigned char *addr) |
2382 | { | 2395 | { |
2383 | int err = -EOPNOTSUPP; | 2396 | int err = -EINVAL; |
2384 | 2397 | ||
2385 | /* If aging addresses are supported device will need to | 2398 | /* If aging addresses are supported device will need to |
2386 | * implement its own handler for this. | 2399 | * implement its own handler for this. |
2387 | */ | 2400 | */ |
2388 | if (!(ndm->ndm_state & NUD_PERMANENT)) { | 2401 | if (!(ndm->ndm_state & NUD_PERMANENT)) { |
2389 | pr_info("%s: FDB only supports static addresses\n", dev->name); | 2402 | pr_info("%s: FDB only supports static addresses\n", dev->name); |
2390 | return -EINVAL; | 2403 | return err; |
2391 | } | 2404 | } |
2392 | 2405 | ||
2393 | if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) | 2406 | if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) |
2394 | err = dev_uc_del(dev, addr); | 2407 | err = dev_uc_del(dev, addr); |
2395 | else if (is_multicast_ether_addr(addr)) | 2408 | else if (is_multicast_ether_addr(addr)) |
2396 | err = dev_mc_del(dev, addr); | 2409 | err = dev_mc_del(dev, addr); |
2397 | else | ||
2398 | err = -EINVAL; | ||
2399 | 2410 | ||
2400 | return err; | 2411 | return err; |
2401 | } | 2412 | } |
@@ -2509,6 +2520,7 @@ skip: | |||
2509 | int ndo_dflt_fdb_dump(struct sk_buff *skb, | 2520 | int ndo_dflt_fdb_dump(struct sk_buff *skb, |
2510 | struct netlink_callback *cb, | 2521 | struct netlink_callback *cb, |
2511 | struct net_device *dev, | 2522 | struct net_device *dev, |
2523 | struct net_device *filter_dev, | ||
2512 | int idx) | 2524 | int idx) |
2513 | { | 2525 | { |
2514 | int err; | 2526 | int err; |
@@ -2526,28 +2538,72 @@ EXPORT_SYMBOL(ndo_dflt_fdb_dump); | |||
2526 | 2538 | ||
2527 | static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) | 2539 | static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) |
2528 | { | 2540 | { |
2529 | int idx = 0; | ||
2530 | struct net *net = sock_net(skb->sk); | ||
2531 | struct net_device *dev; | 2541 | struct net_device *dev; |
2542 | struct nlattr *tb[IFLA_MAX+1]; | ||
2543 | struct net_device *bdev = NULL; | ||
2544 | struct net_device *br_dev = NULL; | ||
2545 | const struct net_device_ops *ops = NULL; | ||
2546 | const struct net_device_ops *cops = NULL; | ||
2547 | struct ifinfomsg *ifm = nlmsg_data(cb->nlh); | ||
2548 | struct net *net = sock_net(skb->sk); | ||
2549 | int brport_idx = 0; | ||
2550 | int br_idx = 0; | ||
2551 | int idx = 0; | ||
2532 | 2552 | ||
2533 | rcu_read_lock(); | 2553 | if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX, |
2534 | for_each_netdev_rcu(net, dev) { | 2554 | ifla_policy) == 0) { |
2535 | if (dev->priv_flags & IFF_BRIDGE_PORT) { | 2555 | if (tb[IFLA_MASTER]) |
2536 | struct net_device *br_dev; | 2556 | br_idx = nla_get_u32(tb[IFLA_MASTER]); |
2537 | const struct net_device_ops *ops; | 2557 | } |
2558 | |||
2559 | brport_idx = ifm->ifi_index; | ||
2538 | 2560 | ||
2539 | br_dev = netdev_master_upper_dev_get(dev); | 2561 | if (br_idx) { |
2540 | ops = br_dev->netdev_ops; | 2562 | br_dev = __dev_get_by_index(net, br_idx); |
2541 | if (ops->ndo_fdb_dump) | 2563 | if (!br_dev) |
2542 | idx = ops->ndo_fdb_dump(skb, cb, dev, idx); | 2564 | return -ENODEV; |
2565 | |||
2566 | ops = br_dev->netdev_ops; | ||
2567 | bdev = br_dev; | ||
2568 | } | ||
2569 | |||
2570 | for_each_netdev(net, dev) { | ||
2571 | if (brport_idx && (dev->ifindex != brport_idx)) | ||
2572 | continue; | ||
2573 | |||
2574 | if (!br_idx) { /* user did not specify a specific bridge */ | ||
2575 | if (dev->priv_flags & IFF_BRIDGE_PORT) { | ||
2576 | br_dev = netdev_master_upper_dev_get(dev); | ||
2577 | cops = br_dev->netdev_ops; | ||
2578 | } | ||
2579 | |||
2580 | bdev = dev; | ||
2581 | } else { | ||
2582 | if (dev != br_dev && | ||
2583 | !(dev->priv_flags & IFF_BRIDGE_PORT)) | ||
2584 | continue; | ||
2585 | |||
2586 | if (br_dev != netdev_master_upper_dev_get(dev) && | ||
2587 | !(dev->priv_flags & IFF_EBRIDGE)) | ||
2588 | continue; | ||
2589 | |||
2590 | bdev = br_dev; | ||
2591 | cops = ops; | ||
2592 | } | ||
2593 | |||
2594 | if (dev->priv_flags & IFF_BRIDGE_PORT) { | ||
2595 | if (cops && cops->ndo_fdb_dump) | ||
2596 | idx = cops->ndo_fdb_dump(skb, cb, br_dev, dev, | ||
2597 | idx); | ||
2543 | } | 2598 | } |
2544 | 2599 | ||
2600 | idx = ndo_dflt_fdb_dump(skb, cb, dev, NULL, idx); | ||
2545 | if (dev->netdev_ops->ndo_fdb_dump) | 2601 | if (dev->netdev_ops->ndo_fdb_dump) |
2546 | idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, dev, idx); | 2602 | idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, bdev, dev, |
2547 | else | 2603 | idx); |
2548 | idx = ndo_dflt_fdb_dump(skb, cb, dev, idx); | 2604 | |
2605 | cops = NULL; | ||
2549 | } | 2606 | } |
2550 | rcu_read_unlock(); | ||
2551 | 2607 | ||
2552 | cb->args[0] = idx; | 2608 | cb->args[0] = idx; |
2553 | return skb->len; | 2609 | return skb->len; |