Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add set mtu device operation to netvsc #68

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
4 changes: 3 additions & 1 deletion drivers/bus/vmbus/vmbus_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ vmbus_map_resource(void *requested_addr, int fd, off_t offset, size_t size,
"mmap(%d, %p, %zu, %ld) failed: %s",
fd, requested_addr, size, (long)offset,
strerror(errno));
}
} else
VMBUS_LOG(DEBUG, " VMBUS memory mapped at %p",
mapaddr);
return mapaddr;
}

Expand Down
173 changes: 141 additions & 32 deletions drivers/net/netvsc/hn_ethdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -1059,37 +1059,6 @@ hn_dev_close(struct rte_eth_dev *dev)
return ret;
}

static const struct eth_dev_ops hn_eth_dev_ops = {
.dev_configure = hn_dev_configure,
.dev_start = hn_dev_start,
.dev_stop = hn_dev_stop,
.dev_close = hn_dev_close,
.dev_infos_get = hn_dev_info_get,
.txq_info_get = hn_dev_tx_queue_info,
.rxq_info_get = hn_dev_rx_queue_info,
.dev_supported_ptypes_get = hn_vf_supported_ptypes,
.promiscuous_enable = hn_dev_promiscuous_enable,
.promiscuous_disable = hn_dev_promiscuous_disable,
.allmulticast_enable = hn_dev_allmulticast_enable,
.allmulticast_disable = hn_dev_allmulticast_disable,
.set_mc_addr_list = hn_dev_mc_addr_list,
.reta_update = hn_rss_reta_update,
.reta_query = hn_rss_reta_query,
.rss_hash_update = hn_rss_hash_update,
.rss_hash_conf_get = hn_rss_hash_conf_get,
.tx_queue_setup = hn_dev_tx_queue_setup,
.tx_queue_release = hn_dev_tx_queue_release,
.tx_done_cleanup = hn_dev_tx_done_cleanup,
.rx_queue_setup = hn_dev_rx_queue_setup,
.rx_queue_release = hn_dev_rx_queue_release,
.link_update = hn_dev_link_update,
.stats_get = hn_dev_stats_get,
.stats_reset = hn_dev_stats_reset,
.xstats_get = hn_dev_xstats_get,
.xstats_get_names = hn_dev_xstats_get_names,
.xstats_reset = hn_dev_xstats_reset,
};

/*
* Setup connection between PMD and kernel.
*/
Expand Down Expand Up @@ -1129,12 +1098,146 @@ hn_detach(struct hn_data *hv)
hn_rndis_detach(hv);
}

static int
hn_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
{
struct hn_data *hv = dev->data->dev_private;
struct hn_rx_queue **rxqs = (struct hn_rx_queue **)dev->data->rx_queues;
struct hn_tx_queue **txqs = (struct hn_tx_queue **)dev->data->tx_queues;
struct rte_eth_dev *vf_dev;
unsigned int orig_mtu = dev->data->mtu;
uint32_t rndis_mtu;
int ret = 0;
int i;

if (dev->data->dev_started) {
PMD_DRV_LOG(ERR, "Device must be stopped before changing MTU");
return -EIO;
}

/* Change MTU of underlying VF netdev first, if it exists */
rte_rwlock_read_lock(&hv->vf_lock);
vf_dev = hn_get_vf_dev(hv);
if (hv->vf_ctx.vf_vsc_switched && vf_dev) {
ret = vf_dev->dev_ops->mtu_set(vf_dev, mtu);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A VF device can be hot added or removed. Look at hn_vf_add() on setting the mtu if VF is hot added

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added code to set the VF MTU on a hot add.

if (ret) {
rte_rwlock_read_unlock(&hv->vf_lock);
goto out;
}
}
rte_rwlock_read_unlock(&hv->vf_lock);

/* Release channel resources */
hn_detach(hv);

/* Close vmbus channels */
for (i = 0; i < hv->num_queues; i++)
rte_vmbus_chan_close(hv->channels[i]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to deal separately with the primary channel, as rte_vmbus_chan_close() doesn't delete it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is currently used in 3 other places: in 2 of those 3, it is directly passed the primary channel. That makes it a no-op in those cases as well as the 0 index case here, as you point out. I could either (1) just call rte_free for the primary channel here, or (2) modify rte_vmbus_chan_close to handle closing the primary channel as well. Which do you prefer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ended up just calling rte_free for the primary channel here.


/* Unmap and re-map vmbus device */
rte_vmbus_unmap_device(hv->vmbus);
ret = rte_vmbus_map_device(hv->vmbus);
if (ret) {
/* This is a catastrophic error - the device is unusable */
PMD_DRV_LOG(ERR, "Could not re-map vmbus device!");
return ret;
}

/* Update pointers to re-mapped UIO resources */
hv->rxbuf_res = hv->vmbus->resource[HV_RECV_BUF_MAP];
hv->chim_res = hv->vmbus->resource[HV_SEND_BUF_MAP];

/* Re-open the vmbus channel */
ret = rte_vmbus_chan_open(hv->vmbus, &hv->channels[0]);
if (ret) {
/* This is a catastrophic error - the device is unusable */
PMD_DRV_LOG(ERR, "Could not re-open vmbus channel!");
}

rte_vmbus_set_latency(hv->vmbus, hv->channels[0], hv->latency);

/* Point primary queues at new primary channel */
rxqs[0]->chan = hv->channels[0];
txqs[0]->chan = hv->channels[0];

ret = hn_attach(hv, mtu);
if (ret)
goto error;

/* Create vmbus subchannels, additional RNDIS configuration */
ret = hn_dev_configure(dev);
if (ret)
goto error;

/* Point any additional queues at new subchannels */
for (i = 1; i < dev->data->nb_rx_queues; i++)
rxqs[i]->chan = hv->channels[i];
for (i = 1; i < dev->data->nb_tx_queues; i++)
txqs[i]->chan = hv->channels[i];

out:
if (hn_rndis_get_mtu(hv, &rndis_mtu))
PMD_DRV_LOG(ERR, "Could not get MTU via RNDIS");
else {
dev->data->mtu = (uint16_t)rndis_mtu;
PMD_DRV_LOG(DEBUG, "RNDIS MTU is %u", dev->data->mtu);
}

return ret;

error:
/* In case of error, attempt to restore original MTU */
if (hn_attach(hv, orig_mtu))
PMD_DRV_LOG(ERR, "Restoring original MTU failed");

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case of error, need to restore all subchannels on original mtu

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've refactored this so all subchannels would be restored if we are attempting to rollback to the original MTU.

rte_rwlock_read_lock(&hv->vf_lock);
vf_dev = hn_get_vf_dev(hv);
if (hv->vf_ctx.vf_vsc_switched && vf_dev)
vf_dev->dev_ops->mtu_set(vf_dev, orig_mtu);
rte_rwlock_read_unlock(&hv->vf_lock);

return ret;
}

static const struct eth_dev_ops hn_eth_dev_ops = {
.dev_configure = hn_dev_configure,
.dev_start = hn_dev_start,
.dev_stop = hn_dev_stop,
.dev_close = hn_dev_close,
.dev_infos_get = hn_dev_info_get,
.txq_info_get = hn_dev_tx_queue_info,
.rxq_info_get = hn_dev_rx_queue_info,
.dev_supported_ptypes_get = hn_vf_supported_ptypes,
.promiscuous_enable = hn_dev_promiscuous_enable,
.promiscuous_disable = hn_dev_promiscuous_disable,
.allmulticast_enable = hn_dev_allmulticast_enable,
.allmulticast_disable = hn_dev_allmulticast_disable,
.set_mc_addr_list = hn_dev_mc_addr_list,
.mtu_set = hn_dev_mtu_set,
.reta_update = hn_rss_reta_update,
.reta_query = hn_rss_reta_query,
.rss_hash_update = hn_rss_hash_update,
.rss_hash_conf_get = hn_rss_hash_conf_get,
.tx_queue_setup = hn_dev_tx_queue_setup,
.tx_queue_release = hn_dev_tx_queue_release,
.tx_done_cleanup = hn_dev_tx_done_cleanup,
.rx_queue_setup = hn_dev_rx_queue_setup,
.rx_queue_release = hn_dev_rx_queue_release,
.link_update = hn_dev_link_update,
.stats_get = hn_dev_stats_get,
.stats_reset = hn_dev_stats_reset,
.xstats_get = hn_dev_xstats_get,
.xstats_get_names = hn_dev_xstats_get_names,
.xstats_reset = hn_dev_xstats_reset,
};

static int
eth_hn_dev_init(struct rte_eth_dev *eth_dev)
{
struct hn_data *hv = eth_dev->data->dev_private;
struct rte_device *device = eth_dev->device;
struct rte_vmbus_device *vmbus;
uint32_t mtu;
unsigned int rxr_cnt;
int err, max_chan;

Expand Down Expand Up @@ -1218,6 +1321,12 @@ eth_hn_dev_init(struct rte_eth_dev *eth_dev)
if (err)
goto failed;

err = hn_rndis_get_mtu(hv, &mtu);
if (err)
goto failed;
eth_dev->data->mtu = (uint16_t)mtu;
PMD_INIT_LOG(DEBUG, "RNDIS MTU is %u", eth_dev->data->mtu);

err = hn_rndis_get_eaddr(hv, eth_dev->data->mac_addrs->addr_bytes);
if (err)
goto failed;
Expand Down Expand Up @@ -1272,7 +1381,7 @@ eth_hn_dev_uninit(struct rte_eth_dev *eth_dev)

hn_detach(hv);
hn_chim_uninit(eth_dev);
rte_vmbus_chan_close(hv->primary->chan);
rte_vmbus_chan_close(hv->channels[0]);
rte_free(hv->primary);
ret = rte_eth_dev_owner_delete(hv->owner.id);
if (ret != 0)
Expand Down
7 changes: 7 additions & 0 deletions drivers/net/netvsc/hn_rndis.c
Original file line number Diff line number Diff line change
Expand Up @@ -1111,6 +1111,13 @@ hn_rndis_get_eaddr(struct hn_data *hv, uint8_t *eaddr)
return 0;
}

int
hn_rndis_get_mtu(struct hn_data *hv, uint32_t *mtu)
{
return hn_rndis_query(hv, OID_GEN_MAXIMUM_FRAME_SIZE, NULL, 0,
mtu, sizeof(uint32_t));
}

int
hn_rndis_get_linkstatus(struct hn_data *hv)
{
Expand Down
1 change: 1 addition & 0 deletions drivers/net/netvsc/hn_rndis.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ void hn_rndis_link_status(struct rte_eth_dev *dev, const void *msg);
int hn_rndis_attach(struct hn_data *hv);
void hn_rndis_detach(struct hn_data *hv);
int hn_rndis_get_eaddr(struct hn_data *hv, uint8_t *eaddr);
int hn_rndis_get_mtu(struct hn_data *hv, uint32_t *mtu);
int hn_rndis_get_linkstatus(struct hn_data *hv);
int hn_rndis_get_linkspeed(struct hn_data *hv);
int hn_rndis_set_rxfilter(struct hn_data *hv, uint32_t filter);
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/netvsc/hn_var.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* Tunable ethdev params
*/
#define HN_MIN_RX_BUF_SIZE 1024
#define HN_MAX_XFER_LEN 2048
#define HN_MAX_XFER_LEN RTE_ETHER_MAX_JUMBO_FRAME_LEN
#define HN_MAX_MAC_ADDRS 1
#define HN_MAX_CHANNELS 64

Expand Down