Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d64f69b0 authored by Roopa Prabhu's avatar Roopa Prabhu Committed by David S. Miller
Browse files

rtnetlink: catch -EOPNOTSUPP errors from ndo_bridge_getlink



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: 85fdb956 ("switchdev: cut over to new switchdev_port_bridge_getlink")
Reported-by: default avatarAlexandre DERUMIER <aderumier@odiso.com>
Signed-off-by: default avatarRoopa Prabhu <roopa@cumulusnetworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent daf158d0
Loading
Loading
Loading
Loading
+16 −10
Original line number Original line Diff line number Diff line
@@ -3047,6 +3047,7 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
	u32 portid = NETLINK_CB(cb->skb).portid;
	u32 portid = NETLINK_CB(cb->skb).portid;
	u32 seq = cb->nlh->nlmsg_seq;
	u32 seq = cb->nlh->nlmsg_seq;
	u32 filter_mask = 0;
	u32 filter_mask = 0;
	int err;


	if (nlmsg_len(cb->nlh) > sizeof(struct ifinfomsg)) {
	if (nlmsg_len(cb->nlh) > sizeof(struct ifinfomsg)) {
		struct nlattr *extfilt;
		struct nlattr *extfilt;
@@ -3067,20 +3068,25 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
		struct net_device *br_dev = netdev_master_upper_dev_get(dev);
		struct net_device *br_dev = netdev_master_upper_dev_get(dev);


		if (br_dev && br_dev->netdev_ops->ndo_bridge_getlink) {
		if (br_dev && br_dev->netdev_ops->ndo_bridge_getlink) {
			if (idx >= cb->args[0] &&
			if (idx >= cb->args[0]) {
			    br_dev->netdev_ops->ndo_bridge_getlink(
				err = br_dev->netdev_ops->ndo_bridge_getlink(
				    skb, portid, seq, dev, filter_mask,
						skb, portid, seq, dev,
				    NLM_F_MULTI) < 0)
						filter_mask, NLM_F_MULTI);
				if (err < 0 && err != -EOPNOTSUPP)
					break;
					break;
			}
			idx++;
			idx++;
		}
		}


		if (ops->ndo_bridge_getlink) {
		if (ops->ndo_bridge_getlink) {
			if (idx >= cb->args[0] &&
			if (idx >= cb->args[0]) {
			    ops->ndo_bridge_getlink(skb, portid, seq, dev,
				err = ops->ndo_bridge_getlink(skb, portid,
							      seq, dev,
							      filter_mask,
							      filter_mask,
						    NLM_F_MULTI) < 0)
							      NLM_F_MULTI);
				if (err < 0 && err != -EOPNOTSUPP)
					break;
					break;
			}
			idx++;
			idx++;
		}
		}
	}
	}