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

Commit 08f382eb authored by Scott Feldman's avatar Scott Feldman Committed by David S. Miller
Browse files

enic: bug fix: make the set/get netlink VF_PORT support symmetrical



To make get/set netlink VF_PORT truly symmetrical, we need to keep track
of what items are set and only return those items on get.  Previously, the
driver wasn't differentiating between a set of attr with a NULL string,
for example, and not setting the attr at all.  We only want to return
the NULL string if the attr was actually set with a NULL string.  Otherwise,
don't return the attr.

Signed-off-by: default avatarScott Feldman <scofeldm@cisco.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f048fa9c
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -74,7 +74,14 @@ struct enic_msix_entry {
	void *devid;
	void *devid;
};
};


#define ENIC_SET_APPLIED		(1 << 0)
#define ENIC_SET_REQUEST		(1 << 1)
#define ENIC_SET_NAME			(1 << 2)
#define ENIC_SET_INSTANCE		(1 << 3)
#define ENIC_SET_HOST			(1 << 4)

struct enic_port_profile {
struct enic_port_profile {
	u32 set;
	u8 request;
	u8 request;
	char name[PORT_PROFILE_MAX];
	char name[PORT_PROFILE_MAX];
	u8 instance_uuid[PORT_UUID_MAX];
	u8 instance_uuid[PORT_UUID_MAX];
+97 −103
Original line number Original line Diff line number Diff line
@@ -1029,8 +1029,7 @@ static int enic_dev_init_done(struct enic *enic, int *done, int *error)
	return err;
	return err;
}
}


static int enic_set_port_profile(struct enic *enic, u8 request, u8 *mac,
static int enic_set_port_profile(struct enic *enic, u8 *mac)
	char *name, u8 *instance_uuid, u8 *host_uuid)
{
{
	struct vic_provinfo *vp;
	struct vic_provinfo *vp;
	u8 oui[3] = VIC_PROVINFO_CISCO_OUI;
	u8 oui[3] = VIC_PROVINFO_CISCO_OUI;
@@ -1040,26 +1039,35 @@ static int enic_set_port_profile(struct enic *enic, u8 request, u8 *mac,
		"%02X%02X-%02X%02X%02X%02X%0X%02X";
		"%02X%02X-%02X%02X%02X%02X%0X%02X";
	int err;
	int err;


	if (!name)
	err = enic_vnic_dev_deinit(enic);
	if (err)
		return err;

	switch (enic->pp.request) {

	case PORT_REQUEST_ASSOCIATE:

		if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name))
			return -EINVAL;
			return -EINVAL;


		if (!is_valid_ether_addr(mac))
		if (!is_valid_ether_addr(mac))
			return -EADDRNOTAVAIL;
			return -EADDRNOTAVAIL;


	vp = vic_provinfo_alloc(GFP_KERNEL, oui, VIC_PROVINFO_LINUX_TYPE);
		vp = vic_provinfo_alloc(GFP_KERNEL, oui,
			VIC_PROVINFO_LINUX_TYPE);
		if (!vp)
		if (!vp)
			return -ENOMEM;
			return -ENOMEM;


		vic_provinfo_add_tlv(vp,
		vic_provinfo_add_tlv(vp,
			VIC_LINUX_PROV_TLV_PORT_PROFILE_NAME_STR,
			VIC_LINUX_PROV_TLV_PORT_PROFILE_NAME_STR,
		strlen(name) + 1, name);
			strlen(enic->pp.name) + 1, enic->pp.name);


		vic_provinfo_add_tlv(vp,
		vic_provinfo_add_tlv(vp,
			VIC_LINUX_PROV_TLV_CLIENT_MAC_ADDR,
			VIC_LINUX_PROV_TLV_CLIENT_MAC_ADDR,
			ETH_ALEN, mac);
			ETH_ALEN, mac);


	if (instance_uuid) {
		if (enic->pp.set & ENIC_SET_INSTANCE) {
		uuid = instance_uuid;
			uuid = enic->pp.instance_uuid;
			sprintf(uuid_str, uuid_fmt,
			sprintf(uuid_str, uuid_fmt,
				uuid[0],  uuid[1],  uuid[2],  uuid[3],
				uuid[0],  uuid[1],  uuid[2],  uuid[3],
				uuid[4],  uuid[5],  uuid[6],  uuid[7],
				uuid[4],  uuid[5],  uuid[6],  uuid[7],
@@ -1070,8 +1078,8 @@ static int enic_set_port_profile(struct enic *enic, u8 request, u8 *mac,
				sizeof(uuid_str), uuid_str);
				sizeof(uuid_str), uuid_str);
		}
		}


	if (host_uuid) {
		if (enic->pp.set & ENIC_SET_HOST) {
		uuid = host_uuid;
			uuid = enic->pp.host_uuid;
			sprintf(uuid_str, uuid_fmt,
			sprintf(uuid_str, uuid_fmt,
				uuid[0],  uuid[1],  uuid[2],  uuid[3],
				uuid[0],  uuid[1],  uuid[2],  uuid[3],
				uuid[4],  uuid[5],  uuid[6],  uuid[7],
				uuid[4],  uuid[5],  uuid[6],  uuid[7],
@@ -1082,55 +1090,61 @@ static int enic_set_port_profile(struct enic *enic, u8 request, u8 *mac,
				sizeof(uuid_str), uuid_str);
				sizeof(uuid_str), uuid_str);
		}
		}


	err = enic_vnic_dev_deinit(enic);
	if (err)
		goto err_out;

	memset(&enic->pp, 0, sizeof(enic->pp));

		err = enic_dev_init_prov(enic, vp);
		err = enic_dev_init_prov(enic, vp);
		vic_provinfo_free(vp);
		if (err)
		if (err)
		goto err_out;
			return err;

		break;
	enic->pp.request = request;
	memcpy(enic->pp.name, name, PORT_PROFILE_MAX);
	if (instance_uuid)
		memcpy(enic->pp.instance_uuid,
			instance_uuid, PORT_UUID_MAX);
	if (host_uuid)
		memcpy(enic->pp.host_uuid,
			host_uuid, PORT_UUID_MAX);


err_out:
	case PORT_REQUEST_DISASSOCIATE:
	vic_provinfo_free(vp);
		break;


	return err;
	default:
		return -EINVAL;
	}
	}


static int enic_unset_port_profile(struct enic *enic)
	enic->pp.set |= ENIC_SET_APPLIED;
{
	return 0;
	memset(&enic->pp, 0, sizeof(enic->pp));
	return enic_vnic_dev_deinit(enic);
}
}


static int enic_set_vf_port(struct net_device *netdev, int vf,
static int enic_set_vf_port(struct net_device *netdev, int vf,
	struct nlattr *port[])
	struct nlattr *port[])
{
{
	struct enic *enic = netdev_priv(netdev);
	struct enic *enic = netdev_priv(netdev);
	char *name = NULL;

	u8 *instance_uuid = NULL;
	memset(&enic->pp, 0, sizeof(enic->pp));
	u8 *host_uuid = NULL;

	u8 request = PORT_REQUEST_DISASSOCIATE;
	if (port[IFLA_PORT_REQUEST]) {
		enic->pp.set |= ENIC_SET_REQUEST;
		enic->pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]);
	}

	if (port[IFLA_PORT_PROFILE]) {
		enic->pp.set |= ENIC_SET_NAME;
		memcpy(enic->pp.name, nla_data(port[IFLA_PORT_PROFILE]),
			PORT_PROFILE_MAX);
	}

	if (port[IFLA_PORT_INSTANCE_UUID]) {
		enic->pp.set |= ENIC_SET_INSTANCE;
		memcpy(enic->pp.instance_uuid,
			nla_data(port[IFLA_PORT_INSTANCE_UUID]), PORT_UUID_MAX);
	}

	if (port[IFLA_PORT_HOST_UUID]) {
		enic->pp.set |= ENIC_SET_HOST;
		memcpy(enic->pp.host_uuid,
			nla_data(port[IFLA_PORT_HOST_UUID]), PORT_UUID_MAX);
	}


	/* don't support VFs, yet */
	/* don't support VFs, yet */
	if (vf != PORT_SELF_VF)
	if (vf != PORT_SELF_VF)
		return -EOPNOTSUPP;
		return -EOPNOTSUPP;


	if (port[IFLA_PORT_REQUEST])
	if (!(enic->pp.set & ENIC_SET_REQUEST))
		request = nla_get_u8(port[IFLA_PORT_REQUEST]);
		return -EOPNOTSUPP;


	switch (request) {
	if (enic->pp.request == PORT_REQUEST_ASSOCIATE) {
	case PORT_REQUEST_ASSOCIATE:


		/* If the interface mac addr hasn't been assigned,
		/* If the interface mac addr hasn't been assigned,
		 * assign a random mac addr before setting port-
		 * assign a random mac addr before setting port-
@@ -1139,30 +1153,9 @@ static int enic_set_vf_port(struct net_device *netdev, int vf,


		if (is_zero_ether_addr(netdev->dev_addr))
		if (is_zero_ether_addr(netdev->dev_addr))
			random_ether_addr(netdev->dev_addr);
			random_ether_addr(netdev->dev_addr);

		if (port[IFLA_PORT_PROFILE])
			name = nla_data(port[IFLA_PORT_PROFILE]);

		if (port[IFLA_PORT_INSTANCE_UUID])
			instance_uuid =
				nla_data(port[IFLA_PORT_INSTANCE_UUID]);

		if (port[IFLA_PORT_HOST_UUID])
			host_uuid = nla_data(port[IFLA_PORT_HOST_UUID]);

		return enic_set_port_profile(enic, request,
			netdev->dev_addr, name,
			instance_uuid, host_uuid);

	case PORT_REQUEST_DISASSOCIATE:

		return enic_unset_port_profile(enic);

	default:
		break;
	}
	}


	return -EOPNOTSUPP;
	return enic_set_port_profile(enic, netdev->dev_addr);
}
}


static int enic_get_vf_port(struct net_device *netdev, int vf,
static int enic_get_vf_port(struct net_device *netdev, int vf,
@@ -1172,14 +1165,12 @@ static int enic_get_vf_port(struct net_device *netdev, int vf,
	int err, error, done;
	int err, error, done;
	u16 response = PORT_PROFILE_RESPONSE_SUCCESS;
	u16 response = PORT_PROFILE_RESPONSE_SUCCESS;


	/* don't support VFs, yet */
	if (!(enic->pp.set & ENIC_SET_APPLIED))
	if (vf != PORT_SELF_VF)
		return -ENODATA;
		return -EOPNOTSUPP;


	err = enic_dev_init_done(enic, &done, &error);
	err = enic_dev_init_done(enic, &done, &error);

	if (err)
	if (err)
		return err;
		error = err;


	switch (error) {
	switch (error) {
	case ERR_SUCCESS:
	case ERR_SUCCESS:
@@ -1202,10 +1193,13 @@ static int enic_get_vf_port(struct net_device *netdev, int vf,


	NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request);
	NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request);
	NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response);
	NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response);
	if (enic->pp.set & ENIC_SET_NAME)
		NLA_PUT(skb, IFLA_PORT_PROFILE, PORT_PROFILE_MAX,
		NLA_PUT(skb, IFLA_PORT_PROFILE, PORT_PROFILE_MAX,
			enic->pp.name);
			enic->pp.name);
	if (enic->pp.set & ENIC_SET_INSTANCE)
		NLA_PUT(skb, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX,
		NLA_PUT(skb, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX,
			enic->pp.instance_uuid);
			enic->pp.instance_uuid);
	if (enic->pp.set & ENIC_SET_HOST)
		NLA_PUT(skb, IFLA_PORT_HOST_UUID, PORT_UUID_MAX,
		NLA_PUT(skb, IFLA_PORT_HOST_UUID, PORT_UUID_MAX,
			enic->pp.host_uuid);
			enic->pp.host_uuid);