hyperv/vmbus: Cleanup channel packet receiving.

MFC after:	1 week
Sponsored by:	Microsoft OSTC
Differential Revision:	https://reviews.freebsd.org/D7204
This commit is contained in:
Sepherosa Ziehau 2016-07-15 07:53:45 +00:00
parent 7c55724859
commit 43bbe6b27f
5 changed files with 96 additions and 132 deletions

View File

@ -90,28 +90,6 @@ struct hyperv_guid {
int hyperv_guid2str(const struct hyperv_guid *, char *, size_t);
typedef struct {
uint16_t type;
uint16_t data_offset8;
uint16_t length8;
uint16_t flags;
uint64_t transaction_id;
} __packed hv_vm_packet_descriptor;
typedef struct {
uint32_t byte_count;
uint32_t byte_offset;
} __packed hv_vm_transfer_page;
typedef struct {
hv_vm_packet_descriptor d;
uint16_t transfer_page_set_id;
hv_bool_uint8_t sender_owns_set;
uint8_t reserved;
uint32_t range_count;
hv_vm_transfer_page ranges[1];
} __packed hv_vm_transfer_page_packet_header;
#define HW_MACADDR_LEN 6
/*
@ -298,13 +276,6 @@ hv_set_channel_read_state(hv_vmbus_channel* channel, boolean_t on)
channel->ch_flags |= VMBUS_CHAN_FLAG_BATCHREAD;
}
int hv_vmbus_channel_recv_packet_raw(
hv_vmbus_channel* channel,
void* buffer,
uint32_t buffer_len,
uint32_t* buffer_actual_len,
uint64_t* request_id);
int hv_vmbus_channel_open(
hv_vmbus_channel* channel,
uint32_t send_ring_buffer_size,

View File

@ -47,6 +47,19 @@ struct vmbus_gpa {
uint64_t gpa_page;
} __packed;
#define VMBUS_CHANPKT_SIZE_SHIFT 3
#define VMBUS_CHANPKT_GETLEN(pktlen) \
(((int)(pktlen)) << VMBUS_CHANPKT_SIZE_SHIFT)
struct vmbus_chanpkt_hdr {
uint16_t cph_type; /* VMBUS_CHANPKT_TYPE_ */
uint16_t cph_hlen; /* header len, in 8 bytes */
uint16_t cph_tlen; /* total len, in 8 bytes */
uint16_t cph_flags; /* VMBUS_CHANPKT_FLAG_ */
uint64_t cph_xactid;
} __packed;
#define VMBUS_CHANPKT_TYPE_INBAND 0x0006
#define VMBUS_CHANPKT_TYPE_RXBUF 0x0007
#define VMBUS_CHANPKT_TYPE_GPA 0x0009
@ -54,6 +67,23 @@ struct vmbus_gpa {
#define VMBUS_CHANPKT_FLAG_RC 0x0001 /* report completion */
#define VMBUS_CHANPKT_CONST_DATA(pkt) \
(const void *)((const uint8_t *)(pkt) + \
VMBUS_CHANPKT_GETLEN((pkt)->cph_hlen))
struct vmbus_rxbuf_desc {
uint32_t rb_len;
uint32_t rb_ofs;
} __packed;
struct vmbus_chanpkt_rxbuf {
struct vmbus_chanpkt_hdr cp_hdr;
uint16_t cp_rxbuf_id;
uint16_t cp_rsvd;
uint32_t cp_rxbuf_cnt;
struct vmbus_rxbuf_desc cp_rxbuf[];
} __packed;
#define VMBUS_CHAN_SGLIST_MAX 32
#define VMBUS_CHAN_PRPLIST_MAX 32
@ -61,6 +91,8 @@ struct hv_vmbus_channel;
int vmbus_chan_recv(struct hv_vmbus_channel *chan, void *data, int *dlen,
uint64_t *xactid);
int vmbus_chan_recv_pkt(struct hv_vmbus_channel *chan,
struct vmbus_chanpkt_hdr *pkt, int *pktlen);
int vmbus_chan_send(struct hv_vmbus_channel *chan, uint16_t type,
uint16_t flags, void *data, int dlen, uint64_t xactid);

View File

@ -64,12 +64,12 @@ static int hv_nv_destroy_send_buffer(netvsc_dev *net_dev);
static int hv_nv_destroy_rx_buffer(netvsc_dev *net_dev);
static int hv_nv_connect_to_vsp(struct hn_softc *sc);
static void hv_nv_on_send_completion(netvsc_dev *net_dev,
struct hv_vmbus_channel *, hv_vm_packet_descriptor *pkt);
struct hv_vmbus_channel *, const struct vmbus_chanpkt_hdr *pkt);
static void hv_nv_on_receive_completion(struct hv_vmbus_channel *chan,
uint64_t tid, uint32_t status);
static void hv_nv_on_receive(netvsc_dev *net_dev,
struct hn_softc *sc, struct hv_vmbus_channel *chan,
hv_vm_packet_descriptor *pkt);
const struct vmbus_chanpkt_hdr *pkt);
/*
*
@ -726,13 +726,12 @@ hv_nv_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel)
*/
static void
hv_nv_on_send_completion(netvsc_dev *net_dev, struct hv_vmbus_channel *chan,
hv_vm_packet_descriptor *pkt)
const struct vmbus_chanpkt_hdr *pkt)
{
nvsp_msg *nvsp_msg_pkt;
const nvsp_msg *nvsp_msg_pkt;
netvsc_packet *net_vsc_pkt;
nvsp_msg_pkt =
(nvsp_msg *)((unsigned long)pkt + (pkt->data_offset8 << 3));
nvsp_msg_pkt = VMBUS_CHANPKT_CONST_DATA(pkt);
if (nvsp_msg_pkt->hdr.msg_type == nvsp_msg_type_init_complete
|| nvsp_msg_pkt->hdr.msg_type
@ -749,7 +748,7 @@ hv_nv_on_send_completion(netvsc_dev *net_dev, struct hv_vmbus_channel *chan,
nvsp_msg_1_type_send_rndis_pkt_complete) {
/* Get the send context */
net_vsc_pkt =
(netvsc_packet *)(unsigned long)pkt->transaction_id;
(netvsc_packet *)(unsigned long)pkt->cph_xactid;
if (NULL != net_vsc_pkt) {
if (net_vsc_pkt->send_buf_section_idx !=
NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX) {
@ -829,10 +828,10 @@ hv_nv_on_send(struct hv_vmbus_channel *chan, netvsc_packet *pkt)
*/
static void
hv_nv_on_receive(netvsc_dev *net_dev, struct hn_softc *sc,
struct hv_vmbus_channel *chan, hv_vm_packet_descriptor *pkt)
struct hv_vmbus_channel *chan, const struct vmbus_chanpkt_hdr *pkthdr)
{
hv_vm_transfer_page_packet_header *vm_xfer_page_pkt;
nvsp_msg *nvsp_msg_pkt;
const struct vmbus_chanpkt_rxbuf *pkt;
const nvsp_msg *nvsp_msg_pkt;
netvsc_packet vsc_pkt;
netvsc_packet *net_vsc_pkt = &vsc_pkt;
device_t dev = sc->hn_dev;
@ -840,43 +839,31 @@ hv_nv_on_receive(netvsc_dev *net_dev, struct hn_softc *sc,
int i = 0;
int status = nvsp_status_success;
/*
* All inbound packets other than send completion should be
* xfer page packet.
*/
if (pkt->type != VMBUS_CHANPKT_TYPE_RXBUF) {
device_printf(dev, "packet type %d is invalid!\n", pkt->type);
return;
}
nvsp_msg_pkt = (nvsp_msg *)((unsigned long)pkt
+ (pkt->data_offset8 << 3));
nvsp_msg_pkt = VMBUS_CHANPKT_CONST_DATA(pkthdr);
/* Make sure this is a valid nvsp packet */
if (nvsp_msg_pkt->hdr.msg_type != nvsp_msg_1_type_send_rndis_pkt) {
device_printf(dev, "packet hdr type %d is invalid!\n",
pkt->type);
device_printf(dev, "packet hdr type %u is invalid!\n",
nvsp_msg_pkt->hdr.msg_type);
return;
}
vm_xfer_page_pkt = (hv_vm_transfer_page_packet_header *)pkt;
pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
if (vm_xfer_page_pkt->transfer_page_set_id !=
NETVSC_RECEIVE_BUFFER_ID) {
device_printf(dev, "transfer_page_set_id %d is invalid!\n",
vm_xfer_page_pkt->transfer_page_set_id);
if (pkt->cp_rxbuf_id != NETVSC_RECEIVE_BUFFER_ID) {
device_printf(dev, "rxbuf_id %d is invalid!\n",
pkt->cp_rxbuf_id);
return;
}
count = vm_xfer_page_pkt->range_count;
count = pkt->cp_rxbuf_cnt;
/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
for (i = 0; i < count; i++) {
net_vsc_pkt->status = nvsp_status_success;
net_vsc_pkt->data = (void *)((unsigned long)net_dev->rx_buf +
vm_xfer_page_pkt->ranges[i].byte_offset);
net_vsc_pkt->tot_data_buf_len =
vm_xfer_page_pkt->ranges[i].byte_count;
net_vsc_pkt->data = ((uint8_t *)net_dev->rx_buf +
pkt->cp_rxbuf[i].rb_ofs);
net_vsc_pkt->tot_data_buf_len = pkt->cp_rxbuf[i].rb_len;
hv_rf_on_receive(net_dev, chan, net_vsc_pkt);
if (net_vsc_pkt->status != nvsp_status_success) {
@ -889,8 +876,7 @@ hv_nv_on_receive(netvsc_dev *net_dev, struct hn_softc *sc,
* messages (not just data messages) will trigger a response
* message back to the host.
*/
hv_nv_on_receive_completion(chan, vm_xfer_page_pkt->d.transaction_id,
status);
hv_nv_on_receive_completion(chan, pkt->cp_hdr.cph_xactid, status);
}
/*
@ -934,19 +920,19 @@ hv_nv_on_receive_completion(struct hv_vmbus_channel *chan, uint64_t tid,
* Net VSC receiving vRSS send table from VSP
*/
static void
hv_nv_send_table(struct hn_softc *sc, hv_vm_packet_descriptor *pkt)
hv_nv_send_table(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
{
netvsc_dev *net_dev;
nvsp_msg *nvsp_msg_pkt;
const nvsp_msg *nvsp_msg_pkt;
int i;
uint32_t count, *table;
uint32_t count;
const uint32_t *table;
net_dev = hv_nv_get_inbound_net_device(sc);
if (!net_dev)
return;
nvsp_msg_pkt =
(nvsp_msg *)((unsigned long)pkt + (pkt->data_offset8 << 3));
nvsp_msg_pkt = VMBUS_CHANPKT_CONST_DATA(pkt);
if (nvsp_msg_pkt->hdr.msg_type !=
nvsp_msg5_type_send_indirection_table) {
@ -962,8 +948,8 @@ hv_nv_send_table(struct hn_softc *sc, hv_vm_packet_descriptor *pkt)
return;
}
table = (uint32_t *)
((unsigned long)&nvsp_msg_pkt->msgs.vers_5_msgs.send_table +
table = (const uint32_t *)
((const uint8_t *)&nvsp_msg_pkt->msgs.vers_5_msgs.send_table +
nvsp_msg_pkt->msgs.vers_5_msgs.send_table.offset);
for (i = 0; i < count; i++)
@ -980,44 +966,40 @@ hv_nv_on_channel_callback(void *xchan)
device_t dev = chan->ch_dev;
struct hn_softc *sc = device_get_softc(dev);
netvsc_dev *net_dev;
uint32_t bytes_rxed;
uint64_t request_id;
hv_vm_packet_descriptor *desc;
uint8_t *buffer;
void *buffer;
int bufferlen = NETVSC_PACKET_SIZE;
int ret = 0;
net_dev = hv_nv_get_inbound_net_device(sc);
if (net_dev == NULL)
return;
buffer = chan->hv_chan_rdbuf;
do {
ret = hv_vmbus_channel_recv_packet_raw(chan,
buffer, bufferlen, &bytes_rxed, &request_id);
struct vmbus_chanpkt_hdr *pkt = buffer;
uint32_t bytes_rxed;
int ret;
bytes_rxed = bufferlen;
ret = vmbus_chan_recv_pkt(chan, pkt, &bytes_rxed);
if (ret == 0) {
if (bytes_rxed > 0) {
desc = (hv_vm_packet_descriptor *)buffer;
switch (desc->type) {
switch (pkt->cph_type) {
case VMBUS_CHANPKT_TYPE_COMP:
hv_nv_on_send_completion(net_dev, chan,
desc);
pkt);
break;
case VMBUS_CHANPKT_TYPE_RXBUF:
hv_nv_on_receive(net_dev, sc, chan, desc);
hv_nv_on_receive(net_dev, sc, chan, pkt);
break;
case VMBUS_CHANPKT_TYPE_INBAND:
hv_nv_send_table(sc, desc);
hv_nv_send_table(sc, pkt);
break;
default:
device_printf(dev,
"hv_cb recv unknow type %d "
" packet\n", desc->type);
"unknown chan pkt %u\n",
pkt->cph_type);
break;
}
} else {
break;
}
} else if (ret == ENOBUFS) {
/* Handle large packet */
@ -1036,6 +1018,9 @@ hv_nv_on_channel_callback(void *xchan)
break;
}
bufferlen = bytes_rxed;
} else {
/* No more packets */
break;
}
} while (1);

View File

@ -751,7 +751,7 @@ vmbus_chan_recv(struct hv_vmbus_channel *chan, void *data, int *dlen0,
dlen = VMBUS_CHANPKT_GETLEN(pkt.cph_tlen) - hlen;
if (*dlen0 < dlen) {
/* Return the size of this packet. */
/* Return the size of this packet's data. */
*dlen0 = dlen;
return ENOBUFS;
}
@ -759,49 +759,37 @@ vmbus_chan_recv(struct hv_vmbus_channel *chan, void *data, int *dlen0,
*xactid = pkt.cph_xactid;
*dlen0 = dlen;
/* Skip packet header */
error = hv_ring_buffer_read(&chan->inbound, data, dlen, hlen);
KASSERT(!error, ("hv_ring_buffer_read failed"));
return 0;
}
/**
* @brief Retrieve the raw packet on the specified channel
*/
int
hv_vmbus_channel_recv_packet_raw(
hv_vmbus_channel* channel,
void* buffer,
uint32_t buffer_len,
uint32_t* buffer_actual_len,
uint64_t* request_id)
vmbus_chan_recv_pkt(struct hv_vmbus_channel *chan,
struct vmbus_chanpkt_hdr *pkt0, int *pktlen0)
{
int ret;
uint32_t packetLen;
hv_vm_packet_descriptor desc;
struct vmbus_chanpkt_hdr pkt;
int error, pktlen;
*buffer_actual_len = 0;
*request_id = 0;
error = hv_ring_buffer_peek(&chan->inbound, &pkt, sizeof(pkt));
if (error)
return error;
ret = hv_ring_buffer_peek(
&channel->inbound, &desc,
sizeof(hv_vm_packet_descriptor));
pktlen = VMBUS_CHANPKT_GETLEN(pkt.cph_tlen);
if (*pktlen0 < pktlen) {
/* Return the size of this packet. */
*pktlen0 = pktlen;
return ENOBUFS;
}
*pktlen0 = pktlen;
if (ret != 0)
return (0);
/* Include packet header */
error = hv_ring_buffer_read(&chan->inbound, pkt0, pktlen, 0);
KASSERT(!error, ("hv_ring_buffer_read failed"));
packetLen = desc.length8 << 3;
*buffer_actual_len = packetLen;
if (packetLen > buffer_len)
return (ENOBUFS);
*request_id = desc.transaction_id;
/* Copy over the entire packet to the user buffer */
ret = hv_ring_buffer_read(&channel->inbound, buffer, packetLen, 0);
return (0);
return 0;
}
static void

View File

@ -112,7 +112,6 @@ CTASSERT(sizeof(struct vmbus_mnf) == PAGE_SIZE);
* Channel packets
*/
#define VMBUS_CHANPKT_SIZE_SHIFT 3
#define VMBUS_CHANPKT_SIZE_ALIGN (1 << VMBUS_CHANPKT_SIZE_SHIFT)
#define VMBUS_CHANPKT_SETLEN(pktlen, len) \
@ -120,20 +119,9 @@ do { \
(pktlen) = (len) >> VMBUS_CHANPKT_SIZE_SHIFT; \
} while (0)
#define VMBUS_CHANPKT_GETLEN(pktlen) \
(((int)(pktlen)) << VMBUS_CHANPKT_SIZE_SHIFT)
#define VMBUS_CHANPKT_TOTLEN(tlen) \
roundup2((tlen), VMBUS_CHANPKT_SIZE_ALIGN)
struct vmbus_chanpkt_hdr {
uint16_t cph_type;
uint16_t cph_hlen; /* header len, in 8 bytes */
uint16_t cph_tlen; /* total len, in 8 bytes */
uint16_t cph_flags;
uint64_t cph_xactid;
} __packed;
struct vmbus_chanpkt {
struct vmbus_chanpkt_hdr cp_hdr;
} __packed;