| From foo@baz Wed Sep 30 05:25:07 CEST 2015 |
| From: Roopa Prabhu <roopa@cumulusnetworks.com> |
| Date: Tue, 15 Sep 2015 14:44:29 -0700 |
| Subject: rtnetlink: catch -EOPNOTSUPP errors from ndo_bridge_getlink |
| |
| From: Roopa Prabhu <roopa@cumulusnetworks.com> |
| |
| [ Upstream commit d64f69b0373a7d0bcec8b5da7712977518a8f42b ] |
| |
| problem reported: |
| kernel 4.1.3 |
| ------------ |
| # bridge vlan |
| port vlan ids |
| eth0 1 PVID Egress Untagged |
| 90 |
| 91 |
| 92 |
| 93 |
| 94 |
| 95 |
| 96 |
| 97 |
| 98 |
| 99 |
| 100 |
| |
| vmbr0 1 PVID Egress Untagged |
| 94 |
| |
| kernel 4.2 |
| ----------- |
| # bridge vlan |
| port vlan ids |
| |
| ndo_bridge_getlink can return -EOPNOTSUPP when an interfaces |
| ndo_bridge_getlink op is set to switchdev_port_bridge_getlink |
| and CONFIG_SWITCHDEV is not defined. This today can happen to |
| bond, rocker and team devices. This patch adds -EOPNOTSUPP |
| checks after calls to ndo_bridge_getlink. |
| |
| Fixes: 85fdb956726ff2a ("switchdev: cut over to new switchdev_port_bridge_getlink") |
| Reported-by: Alexandre DERUMIER <aderumier@odiso.com> |
| Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/core/rtnetlink.c | 26 ++++++++++++++++---------- |
| 1 file changed, 16 insertions(+), 10 deletions(-) |
| |
| --- a/net/core/rtnetlink.c |
| +++ b/net/core/rtnetlink.c |
| @@ -3021,6 +3021,7 @@ static int rtnl_bridge_getlink(struct sk |
| u32 portid = NETLINK_CB(cb->skb).portid; |
| u32 seq = cb->nlh->nlmsg_seq; |
| u32 filter_mask = 0; |
| + int err; |
| |
| if (nlmsg_len(cb->nlh) > sizeof(struct ifinfomsg)) { |
| struct nlattr *extfilt; |
| @@ -3041,20 +3042,25 @@ static int rtnl_bridge_getlink(struct sk |
| struct net_device *br_dev = netdev_master_upper_dev_get(dev); |
| |
| if (br_dev && br_dev->netdev_ops->ndo_bridge_getlink) { |
| - if (idx >= cb->args[0] && |
| - br_dev->netdev_ops->ndo_bridge_getlink( |
| - skb, portid, seq, dev, filter_mask, |
| - NLM_F_MULTI) < 0) |
| - break; |
| + if (idx >= cb->args[0]) { |
| + err = br_dev->netdev_ops->ndo_bridge_getlink( |
| + skb, portid, seq, dev, |
| + filter_mask, NLM_F_MULTI); |
| + if (err < 0 && err != -EOPNOTSUPP) |
| + break; |
| + } |
| idx++; |
| } |
| |
| if (ops->ndo_bridge_getlink) { |
| - if (idx >= cb->args[0] && |
| - ops->ndo_bridge_getlink(skb, portid, seq, dev, |
| - filter_mask, |
| - NLM_F_MULTI) < 0) |
| - break; |
| + if (idx >= cb->args[0]) { |
| + err = ops->ndo_bridge_getlink(skb, portid, |
| + seq, dev, |
| + filter_mask, |
| + NLM_F_MULTI); |
| + if (err < 0 && err != -EOPNOTSUPP) |
| + break; |
| + } |
| idx++; |
| } |
| } |