diff options
Diffstat (limited to 'net/switchdev/switchdev.c')
| -rw-r--r-- | net/switchdev/switchdev.c | 519 | 
1 files changed, 0 insertions, 519 deletions
| diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 25dc67ef9d37..0531b41d1f2d 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -343,8 +343,6 @@ static size_t switchdev_obj_size(const struct switchdev_obj *obj)  	switch (obj->id) {  	case SWITCHDEV_OBJ_ID_PORT_VLAN:  		return sizeof(struct switchdev_obj_port_vlan); -	case SWITCHDEV_OBJ_ID_PORT_FDB: -		return sizeof(struct switchdev_obj_port_fdb);  	case SWITCHDEV_OBJ_ID_PORT_MDB:  		return sizeof(struct switchdev_obj_port_mdb);  	default: @@ -534,43 +532,6 @@ int switchdev_port_obj_del(struct net_device *dev,  }  EXPORT_SYMBOL_GPL(switchdev_port_obj_del); -/** - *	switchdev_port_obj_dump - Dump port objects - * - *	@dev: port device - *	@id: object ID - *	@obj: object to dump - *	@cb: function to call with a filled object - * - *	rtnl_lock must be held. - */ -int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj, -			    switchdev_obj_dump_cb_t *cb) -{ -	const struct switchdev_ops *ops = dev->switchdev_ops; -	struct net_device *lower_dev; -	struct list_head *iter; -	int err = -EOPNOTSUPP; - -	ASSERT_RTNL(); - -	if (ops && ops->switchdev_port_obj_dump) -		return ops->switchdev_port_obj_dump(dev, obj, cb); - -	/* Switch device port(s) may be stacked under -	 * bond/team/vlan dev, so recurse down to dump objects on -	 * first port at bottom of stack. -	 */ - -	netdev_for_each_lower_dev(dev, lower_dev, iter) { -		err = switchdev_port_obj_dump(lower_dev, obj, cb); -		break; -	} - -	return err; -} -EXPORT_SYMBOL_GPL(switchdev_port_obj_dump); -  static ATOMIC_NOTIFIER_HEAD(switchdev_notif_chain);  /** @@ -613,486 +574,6 @@ int call_switchdev_notifiers(unsigned long val, struct net_device *dev,  }  EXPORT_SYMBOL_GPL(call_switchdev_notifiers); -struct switchdev_vlan_dump { -	struct switchdev_obj_port_vlan vlan; -	struct sk_buff *skb; -	u32 filter_mask; -	u16 flags; -	u16 begin; -	u16 end; -}; - -static int switchdev_port_vlan_dump_put(struct switchdev_vlan_dump *dump) -{ -	struct bridge_vlan_info vinfo; - -	vinfo.flags = dump->flags; - -	if (dump->begin == 0 && dump->end == 0) { -		return 0; -	} else if (dump->begin == dump->end) { -		vinfo.vid = dump->begin; -		if (nla_put(dump->skb, IFLA_BRIDGE_VLAN_INFO, -			    sizeof(vinfo), &vinfo)) -			return -EMSGSIZE; -	} else { -		vinfo.vid = dump->begin; -		vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN; -		if (nla_put(dump->skb, IFLA_BRIDGE_VLAN_INFO, -			    sizeof(vinfo), &vinfo)) -			return -EMSGSIZE; -		vinfo.vid = dump->end; -		vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN; -		vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_END; -		if (nla_put(dump->skb, IFLA_BRIDGE_VLAN_INFO, -			    sizeof(vinfo), &vinfo)) -			return -EMSGSIZE; -	} - -	return 0; -} - -static int switchdev_port_vlan_dump_cb(struct switchdev_obj *obj) -{ -	struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); -	struct switchdev_vlan_dump *dump = -		container_of(vlan, struct switchdev_vlan_dump, vlan); -	int err = 0; - -	if (vlan->vid_begin > vlan->vid_end) -		return -EINVAL; - -	if (dump->filter_mask & RTEXT_FILTER_BRVLAN) { -		dump->flags = vlan->flags; -		for (dump->begin = dump->end = vlan->vid_begin; -		     dump->begin <= vlan->vid_end; -		     dump->begin++, dump->end++) { -			err = switchdev_port_vlan_dump_put(dump); -			if (err) -				return err; -		} -	} else if (dump->filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED) { -		if (dump->begin > vlan->vid_begin && -		    dump->begin >= vlan->vid_end) { -			if ((dump->begin - 1) == vlan->vid_end && -			    dump->flags == vlan->flags) { -				/* prepend */ -				dump->begin = vlan->vid_begin; -			} else { -				err = switchdev_port_vlan_dump_put(dump); -				dump->flags = vlan->flags; -				dump->begin = vlan->vid_begin; -				dump->end = vlan->vid_end; -			} -		} else if (dump->end <= vlan->vid_begin && -		           dump->end < vlan->vid_end) { -			if ((dump->end  + 1) == vlan->vid_begin && -			    dump->flags == vlan->flags) { -				/* append */ -				dump->end = vlan->vid_end; -			} else { -				err = switchdev_port_vlan_dump_put(dump); -				dump->flags = vlan->flags; -				dump->begin = vlan->vid_begin; -				dump->end = vlan->vid_end; -			} -		} else { -			err = -EINVAL; -		} -	} - -	return err; -} - -static int switchdev_port_vlan_fill(struct sk_buff *skb, struct net_device *dev, -				    u32 filter_mask) -{ -	struct switchdev_vlan_dump dump = { -		.vlan.obj.orig_dev = dev, -		.vlan.obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, -		.skb = skb, -		.filter_mask = filter_mask, -	}; -	int err = 0; - -	if ((filter_mask & RTEXT_FILTER_BRVLAN) || -	    (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) { -		err = switchdev_port_obj_dump(dev, &dump.vlan.obj, -					      switchdev_port_vlan_dump_cb); -		if (err) -			goto err_out; -		if (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED) -			/* last one */ -			err = switchdev_port_vlan_dump_put(&dump); -	} - -err_out: -	return err == -EOPNOTSUPP ? 0 : err; -} - -/** - *	switchdev_port_bridge_getlink - Get bridge port attributes - * - *	@dev: port device - * - *	Called for SELF on rtnl_bridge_getlink to get bridge port - *	attributes. - */ -int switchdev_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, -				  struct net_device *dev, u32 filter_mask, -				  int nlflags) -{ -	struct switchdev_attr attr = { -		.orig_dev = dev, -		.id = SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS, -	}; -	u16 mode = BRIDGE_MODE_UNDEF; -	u32 mask = BR_LEARNING | BR_LEARNING_SYNC | BR_FLOOD; -	int err; - -	if (!netif_is_bridge_port(dev)) -		return -EOPNOTSUPP; - -	err = switchdev_port_attr_get(dev, &attr); -	if (err && err != -EOPNOTSUPP) -		return err; - -	return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode, -				       attr.u.brport_flags, mask, nlflags, -				       filter_mask, switchdev_port_vlan_fill); -} -EXPORT_SYMBOL_GPL(switchdev_port_bridge_getlink); - -static int switchdev_port_br_setflag(struct net_device *dev, -				     struct nlattr *nlattr, -				     unsigned long brport_flag) -{ -	struct switchdev_attr attr = { -		.orig_dev = dev, -		.id = SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS, -	}; -	u8 flag = nla_get_u8(nlattr); -	int err; - -	err = switchdev_port_attr_get(dev, &attr); -	if (err) -		return err; - -	if (flag) -		attr.u.brport_flags |= brport_flag; -	else -		attr.u.brport_flags &= ~brport_flag; - -	return switchdev_port_attr_set(dev, &attr); -} - -static const struct nla_policy -switchdev_port_bridge_policy[IFLA_BRPORT_MAX + 1] = { -	[IFLA_BRPORT_STATE]		= { .type = NLA_U8 }, -	[IFLA_BRPORT_COST]		= { .type = NLA_U32 }, -	[IFLA_BRPORT_PRIORITY]		= { .type = NLA_U16 }, -	[IFLA_BRPORT_MODE]		= { .type = NLA_U8 }, -	[IFLA_BRPORT_GUARD]		= { .type = NLA_U8 }, -	[IFLA_BRPORT_PROTECT]		= { .type = NLA_U8 }, -	[IFLA_BRPORT_FAST_LEAVE]	= { .type = NLA_U8 }, -	[IFLA_BRPORT_LEARNING]		= { .type = NLA_U8 }, -	[IFLA_BRPORT_LEARNING_SYNC]	= { .type = NLA_U8 }, -	[IFLA_BRPORT_UNICAST_FLOOD]	= { .type = NLA_U8 }, -}; - -static int switchdev_port_br_setlink_protinfo(struct net_device *dev, -					      struct nlattr *protinfo) -{ -	struct nlattr *attr; -	int rem; -	int err; - -	err = nla_validate_nested(protinfo, IFLA_BRPORT_MAX, -				  switchdev_port_bridge_policy, NULL); -	if (err) -		return err; - -	nla_for_each_nested(attr, protinfo, rem) { -		switch (nla_type(attr)) { -		case IFLA_BRPORT_LEARNING: -			err = switchdev_port_br_setflag(dev, attr, -							BR_LEARNING); -			break; -		case IFLA_BRPORT_LEARNING_SYNC: -			err = switchdev_port_br_setflag(dev, attr, -							BR_LEARNING_SYNC); -			break; -		case IFLA_BRPORT_UNICAST_FLOOD: -			err = switchdev_port_br_setflag(dev, attr, BR_FLOOD); -			break; -		default: -			err = -EOPNOTSUPP; -			break; -		} -		if (err) -			return err; -	} - -	return 0; -} - -static int switchdev_port_br_afspec(struct net_device *dev, -				    struct nlattr *afspec, -				    int (*f)(struct net_device *dev, -					     const struct switchdev_obj *obj)) -{ -	struct nlattr *attr; -	struct bridge_vlan_info *vinfo; -	struct switchdev_obj_port_vlan vlan = { -		.obj.orig_dev = dev, -		.obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, -	}; -	int rem; -	int err; - -	nla_for_each_nested(attr, afspec, rem) { -		if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO) -			continue; -		if (nla_len(attr) != sizeof(struct bridge_vlan_info)) -			return -EINVAL; -		vinfo = nla_data(attr); -		if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK) -			return -EINVAL; -		vlan.flags = vinfo->flags; -		if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) { -			if (vlan.vid_begin) -				return -EINVAL; -			vlan.vid_begin = vinfo->vid; -			/* don't allow range of pvids */ -			if (vlan.flags & BRIDGE_VLAN_INFO_PVID) -				return -EINVAL; -		} else if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END) { -			if (!vlan.vid_begin) -				return -EINVAL; -			vlan.vid_end = vinfo->vid; -			if (vlan.vid_end <= vlan.vid_begin) -				return -EINVAL; -			err = f(dev, &vlan.obj); -			if (err) -				return err; -			vlan.vid_begin = 0; -		} else { -			if (vlan.vid_begin) -				return -EINVAL; -			vlan.vid_begin = vinfo->vid; -			vlan.vid_end = vinfo->vid; -			err = f(dev, &vlan.obj); -			if (err) -				return err; -			vlan.vid_begin = 0; -		} -	} - -	return 0; -} - -/** - *	switchdev_port_bridge_setlink - Set bridge port attributes - * - *	@dev: port device - *	@nlh: netlink header - *	@flags: netlink flags - * - *	Called for SELF on rtnl_bridge_setlink to set bridge port - *	attributes. - */ -int switchdev_port_bridge_setlink(struct net_device *dev, -				  struct nlmsghdr *nlh, u16 flags) -{ -	struct nlattr *protinfo; -	struct nlattr *afspec; -	int err = 0; - -	if (!netif_is_bridge_port(dev)) -		return -EOPNOTSUPP; - -	protinfo = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), -				   IFLA_PROTINFO); -	if (protinfo) { -		err = switchdev_port_br_setlink_protinfo(dev, protinfo); -		if (err) -			return err; -	} - -	afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), -				 IFLA_AF_SPEC); -	if (afspec) -		err = switchdev_port_br_afspec(dev, afspec, -					       switchdev_port_obj_add); - -	return err; -} -EXPORT_SYMBOL_GPL(switchdev_port_bridge_setlink); - -/** - *	switchdev_port_bridge_dellink - Set bridge port attributes - * - *	@dev: port device - *	@nlh: netlink header - *	@flags: netlink flags - * - *	Called for SELF on rtnl_bridge_dellink to set bridge port - *	attributes. - */ -int switchdev_port_bridge_dellink(struct net_device *dev, -				  struct nlmsghdr *nlh, u16 flags) -{ -	struct nlattr *afspec; - -	if (!netif_is_bridge_port(dev)) -		return -EOPNOTSUPP; - -	afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), -				 IFLA_AF_SPEC); -	if (afspec) -		return switchdev_port_br_afspec(dev, afspec, -						switchdev_port_obj_del); - -	return 0; -} -EXPORT_SYMBOL_GPL(switchdev_port_bridge_dellink); - -/** - *	switchdev_port_fdb_add - Add FDB (MAC/VLAN) entry to port - * - *	@ndmsg: netlink hdr - *	@nlattr: netlink attributes - *	@dev: port device - *	@addr: MAC address to add - *	@vid: VLAN to add - * - *	Add FDB entry to switch device. - */ -int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], -			   struct net_device *dev, const unsigned char *addr, -			   u16 vid, u16 nlm_flags) -{ -	struct switchdev_obj_port_fdb fdb = { -		.obj.orig_dev = dev, -		.obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, -		.vid = vid, -	}; - -	ether_addr_copy(fdb.addr, addr); -	return switchdev_port_obj_add(dev, &fdb.obj); -} -EXPORT_SYMBOL_GPL(switchdev_port_fdb_add); - -/** - *	switchdev_port_fdb_del - Delete FDB (MAC/VLAN) entry from port - * - *	@ndmsg: netlink hdr - *	@nlattr: netlink attributes - *	@dev: port device - *	@addr: MAC address to delete - *	@vid: VLAN to delete - * - *	Delete FDB entry from switch device. - */ -int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], -			   struct net_device *dev, const unsigned char *addr, -			   u16 vid) -{ -	struct switchdev_obj_port_fdb fdb = { -		.obj.orig_dev = dev, -		.obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, -		.vid = vid, -	}; - -	ether_addr_copy(fdb.addr, addr); -	return switchdev_port_obj_del(dev, &fdb.obj); -} -EXPORT_SYMBOL_GPL(switchdev_port_fdb_del); - -struct switchdev_fdb_dump { -	struct switchdev_obj_port_fdb fdb; -	struct net_device *dev; -	struct sk_buff *skb; -	struct netlink_callback *cb; -	int idx; -}; - -static int switchdev_port_fdb_dump_cb(struct switchdev_obj *obj) -{ -	struct switchdev_obj_port_fdb *fdb = SWITCHDEV_OBJ_PORT_FDB(obj); -	struct switchdev_fdb_dump *dump = -		container_of(fdb, struct switchdev_fdb_dump, fdb); -	u32 portid = NETLINK_CB(dump->cb->skb).portid; -	u32 seq = dump->cb->nlh->nlmsg_seq; -	struct nlmsghdr *nlh; -	struct ndmsg *ndm; - -	if (dump->idx < dump->cb->args[2]) -		goto skip; - -	nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH, -			sizeof(*ndm), NLM_F_MULTI); -	if (!nlh) -		return -EMSGSIZE; - -	ndm = nlmsg_data(nlh); -	ndm->ndm_family  = AF_BRIDGE; -	ndm->ndm_pad1    = 0; -	ndm->ndm_pad2    = 0; -	ndm->ndm_flags   = NTF_SELF; -	ndm->ndm_type    = 0; -	ndm->ndm_ifindex = dump->dev->ifindex; -	ndm->ndm_state   = fdb->ndm_state; - -	if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, fdb->addr)) -		goto nla_put_failure; - -	if (fdb->vid && nla_put_u16(dump->skb, NDA_VLAN, fdb->vid)) -		goto nla_put_failure; - -	nlmsg_end(dump->skb, nlh); - -skip: -	dump->idx++; -	return 0; - -nla_put_failure: -	nlmsg_cancel(dump->skb, nlh); -	return -EMSGSIZE; -} - -/** - *	switchdev_port_fdb_dump - Dump port FDB (MAC/VLAN) entries - * - *	@skb: netlink skb - *	@cb: netlink callback - *	@dev: port device - *	@filter_dev: filter device - *	@idx: - * - *	Dump FDB entries from switch device. - */ -int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, -			    struct net_device *dev, -			    struct net_device *filter_dev, int *idx) -{ -	struct switchdev_fdb_dump dump = { -		.fdb.obj.orig_dev = dev, -		.fdb.obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, -		.dev = dev, -		.skb = skb, -		.cb = cb, -		.idx = *idx, -	}; -	int err; - -	err = switchdev_port_obj_dump(dev, &dump.fdb.obj, -				      switchdev_port_fdb_dump_cb); -	*idx = dump.idx; -	return err; -} -EXPORT_SYMBOL_GPL(switchdev_port_fdb_dump); -  bool switchdev_port_same_parent_id(struct net_device *a,  				   struct net_device *b)  { | 
