FreeBSD Bugzilla – Attachment 162011 Details for
Bug 203630
[Hyper-V] [nat] [tcp] 10.2 NAT bug in TCP stack or hyperv netsvc driver
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Revert TSO and checksum offloading patch r285236 in Netvsc driver
revert-r285236.patch (text/plain), 65.88 KB, created by
Wei Hu
on 2015-10-14 04:37:40 UTC
(
hide
)
Description:
Revert TSO and checksum offloading patch r285236 in Netvsc driver
Filename:
MIME Type:
Creator:
Wei Hu
Created:
2015-10-14 04:37:40 UTC
Size:
65.88 KB
patch
obsolete
>Index: sys/dev/hyperv/netvsc/hv_net_vsc.c >=================================================================== >--- sys/dev/hyperv/netvsc/hv_net_vsc.c (revision 285236) >+++ sys/dev/hyperv/netvsc/hv_net_vsc.c (revision 285224) >@@ -48,7 +48,6 @@ > #include "hv_rndis.h" > #include "hv_rndis_filter.h" > >-MALLOC_DEFINE(M_NETVSC, "netvsc", "Hyper-V netvsc driver"); > > /* > * Forward declarations >@@ -59,11 +58,14 @@ > 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 hv_device *device); >-static void hv_nv_on_send_completion(netvsc_dev *net_dev, >- struct hv_device *device, hv_vm_packet_descriptor *pkt); >-static void hv_nv_on_receive(netvsc_dev *net_dev, >- struct hv_device *device, hv_vm_packet_descriptor *pkt); >+static void hv_nv_on_send_completion(struct hv_device *device, >+ hv_vm_packet_descriptor *pkt); >+static void hv_nv_on_receive(struct hv_device *device, >+ hv_vm_packet_descriptor *pkt); >+static void hv_nv_send_receive_completion(struct hv_device *device, >+ uint64_t tid); > >+ > /* > * > */ >@@ -73,7 +75,7 @@ > netvsc_dev *net_dev; > hn_softc_t *sc = device_get_softc(device->device); > >- net_dev = malloc(sizeof(netvsc_dev), M_NETVSC, M_NOWAIT | M_ZERO); >+ net_dev = malloc(sizeof(netvsc_dev), M_DEVBUF, M_NOWAIT | M_ZERO); > if (net_dev == NULL) { > return (NULL); > } >@@ -125,34 +127,6 @@ > return (net_dev); > } > >-int >-hv_nv_get_next_send_section(netvsc_dev *net_dev) >-{ >- unsigned long bitsmap_words = net_dev->bitsmap_words; >- unsigned long *bitsmap = net_dev->send_section_bitsmap; >- unsigned long idx; >- int ret = NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX; >- int i; >- >- for (i = 0; i < bitsmap_words; i++) { >- idx = ffs(~bitsmap[i]); >- if (0 == idx) >- continue; >- >- idx--; >- if (i * BITS_PER_LONG + idx >= net_dev->send_section_count) >- return (ret); >- >- if (synch_test_and_set_bit(idx, &bitsmap[i])) >- continue; >- >- ret = i * BITS_PER_LONG + idx; >- break; >- } >- >- return (ret); >-} >- > /* > * Net VSC initialize receive buffer with net VSP > * >@@ -171,8 +145,12 @@ > return (ENODEV); > } > >- net_dev->rx_buf = contigmalloc(net_dev->rx_buf_size, M_NETVSC, >+ net_dev->rx_buf = contigmalloc(net_dev->rx_buf_size, M_DEVBUF, > M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0); >+ if (net_dev->rx_buf == NULL) { >+ ret = ENOMEM; >+ goto cleanup; >+ } > > /* > * Establish the GPADL handle for this buffer on this channel. >@@ -223,7 +201,7 @@ > init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.num_sections; > > net_dev->rx_sections = malloc(net_dev->rx_section_count * >- sizeof(nvsp_1_rx_buf_section), M_NETVSC, M_NOWAIT); >+ sizeof(nvsp_1_rx_buf_section), M_DEVBUF, M_NOWAIT); > if (net_dev->rx_sections == NULL) { > ret = EINVAL; > goto cleanup; >@@ -267,7 +245,7 @@ > return (ENODEV); > } > >- net_dev->send_buf = contigmalloc(net_dev->send_buf_size, M_NETVSC, >+ net_dev->send_buf = contigmalloc(net_dev->send_buf_size, M_DEVBUF, > M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0); > if (net_dev->send_buf == NULL) { > ret = ENOMEM; >@@ -280,7 +258,7 @@ > * channel to establish the gpadl handle. > */ > ret = hv_vmbus_channel_establish_gpadl(device->channel, >- net_dev->send_buf, net_dev->send_buf_size, >+ net_dev->send_buf, net_dev->send_buf_size, > &net_dev->send_buf_gpadl_handle); > if (ret != 0) { > goto cleanup; >@@ -301,7 +279,7 @@ > /* Send the gpadl notification request */ > > ret = hv_vmbus_channel_send_packet(device->channel, init_pkt, >- sizeof(nvsp_msg), (uint64_t)init_pkt, >+ sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt, > HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, > HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); > if (ret != 0) { >@@ -319,17 +297,6 @@ > > net_dev->send_section_size = > init_pkt->msgs.vers_1_msgs.send_send_buf_complete.section_size; >- net_dev->send_section_count = >- net_dev->send_buf_size / net_dev->send_section_size; >- net_dev->bitsmap_words = howmany(net_dev->send_section_count, >- BITS_PER_LONG); >- net_dev->send_section_bitsmap = >- malloc(net_dev->bitsmap_words * sizeof(long), M_NETVSC, >- M_NOWAIT | M_ZERO); >- if (NULL == net_dev->send_section_bitsmap) { >- ret = ENOMEM; >- goto cleanup; >- } > > goto exit; > >@@ -394,12 +361,12 @@ > > if (net_dev->rx_buf) { > /* Free up the receive buffer */ >- contigfree(net_dev->rx_buf, net_dev->rx_buf_size, M_NETVSC); >+ contigfree(net_dev->rx_buf, net_dev->rx_buf_size, M_DEVBUF); > net_dev->rx_buf = NULL; > } > > if (net_dev->rx_sections) { >- free(net_dev->rx_sections, M_NETVSC); >+ free(net_dev->rx_sections, M_DEVBUF); > net_dev->rx_sections = NULL; > net_dev->rx_section_count = 0; > } >@@ -462,14 +429,10 @@ > > if (net_dev->send_buf) { > /* Free up the receive buffer */ >- contigfree(net_dev->send_buf, net_dev->send_buf_size, M_NETVSC); >+ contigfree(net_dev->send_buf, net_dev->send_buf_size, M_DEVBUF); > net_dev->send_buf = NULL; > } > >- if (net_dev->send_section_bitsmap) { >- free(net_dev->send_section_bitsmap, M_NETVSC); >- } >- > return (ret); > } > >@@ -483,7 +446,7 @@ > */ > static int > hv_nv_negotiate_nvsp_protocol(struct hv_device *device, netvsc_dev *net_dev, >- uint32_t nvsp_ver) >+ uint32_t nvsp_ver) > { > nvsp_msg *init_pkt; > int ret; >@@ -560,13 +523,8 @@ > { > netvsc_dev *net_dev; > nvsp_msg *init_pkt; >+ uint32_t nvsp_vers; > uint32_t ndis_version; >- uint32_t protocol_list[] = { NVSP_PROTOCOL_VERSION_1, >- NVSP_PROTOCOL_VERSION_2, >- NVSP_PROTOCOL_VERSION_4, >- NVSP_PROTOCOL_VERSION_5 }; >- int i; >- int protocol_number = nitems(protocol_list); > int ret = 0; > device_t dev = device->device; > hn_softc_t *sc = device_get_softc(dev); >@@ -578,31 +536,26 @@ > } > > /* >- * Negotiate the NVSP version. Try the latest NVSP first. >+ * Negotiate the NVSP version. Try NVSP v2 first. > */ >- for (i = protocol_number - 1; i >= 0; i--) { >- if (hv_nv_negotiate_nvsp_protocol(device, net_dev, >- protocol_list[i]) == 0) { >- net_dev->nvsp_version = protocol_list[i]; >- if (bootverbose) >- device_printf(dev, "Netvsc: got version 0x%x\n", >- net_dev->nvsp_version); >- break; >+ nvsp_vers = NVSP_PROTOCOL_VERSION_2; >+ ret = hv_nv_negotiate_nvsp_protocol(device, net_dev, nvsp_vers); >+ if (ret != 0) { >+ /* NVSP v2 failed, try NVSP v1 */ >+ nvsp_vers = NVSP_PROTOCOL_VERSION_1; >+ ret = hv_nv_negotiate_nvsp_protocol(device, net_dev, nvsp_vers); >+ if (ret != 0) { >+ /* NVSP v1 failed, return bad status */ >+ return (ret); > } > } >+ net_dev->nvsp_version = nvsp_vers; > >- if (i < 0) { >- if (bootverbose) >- device_printf(dev, "failed to negotiate a valid " >- "protocol.\n"); >- return (EPROTO); >- } >- > /* > * Set the MTU if supported by this NVSP protocol version > * This needs to be right after the NVSP init message per Haiyang > */ >- if (net_dev->nvsp_version >= NVSP_PROTOCOL_VERSION_2) >+ if (nvsp_vers >= NVSP_PROTOCOL_VERSION_2) > ret = hv_nv_send_ndis_config(device, ifp->if_mtu); > > /* >@@ -612,11 +565,10 @@ > > memset(init_pkt, 0, sizeof(nvsp_msg)); > >- if (net_dev->nvsp_version <= NVSP_PROTOCOL_VERSION_4) { >- ndis_version = NDIS_VERSION_6_1; >- } else { >- ndis_version = NDIS_VERSION_6_30; >- } >+ /* >+ * Updated to version 5.1, minimum, for VLAN per Haiyang >+ */ >+ ndis_version = NDIS_VERSION; > > init_pkt->hdr.msg_type = nvsp_msg_1_type_send_ndis_vers; > init_pkt->msgs.vers_1_msgs.send_ndis_vers.ndis_major_vers = >@@ -668,7 +620,9 @@ > hv_nv_on_device_add(struct hv_device *device, void *additional_info) > { > netvsc_dev *net_dev; >- int ret = 0; >+ netvsc_packet *packet; >+ netvsc_packet *next_packet; >+ int i, ret = 0; > > net_dev = hv_nv_alloc_net_device(device); > if (!net_dev) >@@ -676,9 +630,29 @@ > > /* Initialize the NetVSC channel extension */ > net_dev->rx_buf_size = NETVSC_RECEIVE_BUFFER_SIZE; >+ mtx_init(&net_dev->rx_pkt_list_lock, "HV-RPL", NULL, >+ MTX_SPIN | MTX_RECURSE); > > net_dev->send_buf_size = NETVSC_SEND_BUFFER_SIZE; > >+ /* Same effect as STAILQ_HEAD_INITIALIZER() static initializer */ >+ STAILQ_INIT(&net_dev->myrx_packet_list); >+ >+ /* >+ * malloc a sufficient number of netvsc_packet buffers to hold >+ * a packet list. Add them to the netvsc device packet queue. >+ */ >+ for (i=0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) { >+ packet = malloc(sizeof(netvsc_packet) + >+ (NETVSC_RECEIVE_SG_COUNT * sizeof(hv_vmbus_page_buffer)), >+ M_DEVBUF, M_NOWAIT | M_ZERO); >+ if (!packet) { >+ break; >+ } >+ STAILQ_INSERT_TAIL(&net_dev->myrx_packet_list, packet, >+ mylist_entry); >+ } >+ > sema_init(&net_dev->channel_init_sema, 0, "netdev_sema"); > > /* >@@ -711,7 +685,19 @@ > */ > if (net_dev) { > sema_destroy(&net_dev->channel_init_sema); >- free(net_dev, M_NETVSC); >+ >+ packet = STAILQ_FIRST(&net_dev->myrx_packet_list); >+ while (packet != NULL) { >+ next_packet = STAILQ_NEXT(packet, mylist_entry); >+ free(packet, M_DEVBUF); >+ packet = next_packet; >+ } >+ /* Reset the list to initial state */ >+ STAILQ_INIT(&net_dev->myrx_packet_list); >+ >+ mtx_destroy(&net_dev->rx_pkt_list_lock); >+ >+ free(net_dev, M_DEVBUF); > } > > return (NULL); >@@ -723,6 +709,8 @@ > int > hv_nv_on_device_remove(struct hv_device *device, boolean_t destroy_channel) > { >+ netvsc_packet *net_vsc_pkt; >+ netvsc_packet *next_net_vsc_pkt; > hn_softc_t *sc = device_get_softc(device->device); > netvsc_dev *net_dev = sc->net_dev;; > >@@ -749,8 +737,20 @@ > > hv_vmbus_channel_close(device->channel); > >+ /* Release all resources */ >+ net_vsc_pkt = STAILQ_FIRST(&net_dev->myrx_packet_list); >+ while (net_vsc_pkt != NULL) { >+ next_net_vsc_pkt = STAILQ_NEXT(net_vsc_pkt, mylist_entry); >+ free(net_vsc_pkt, M_DEVBUF); >+ net_vsc_pkt = next_net_vsc_pkt; >+ } >+ >+ /* Reset the list to initial state */ >+ STAILQ_INIT(&net_dev->myrx_packet_list); >+ >+ mtx_destroy(&net_dev->rx_pkt_list_lock); > sema_destroy(&net_dev->channel_init_sema); >- free(net_dev, M_NETVSC); >+ free(net_dev, M_DEVBUF); > > return (0); > } >@@ -758,13 +758,18 @@ > /* > * Net VSC on send completion > */ >-static void >-hv_nv_on_send_completion(netvsc_dev *net_dev, >- struct hv_device *device, hv_vm_packet_descriptor *pkt) >+static void >+hv_nv_on_send_completion(struct hv_device *device, hv_vm_packet_descriptor *pkt) > { >+ netvsc_dev *net_dev; > nvsp_msg *nvsp_msg_pkt; > netvsc_packet *net_vsc_pkt; > >+ net_dev = hv_nv_get_inbound_net_device(device); >+ if (!net_dev) { >+ return; >+ } >+ > nvsp_msg_pkt = > (nvsp_msg *)((unsigned long)pkt + (pkt->data_offset8 << 3)); > >@@ -775,25 +780,17 @@ > == nvsp_msg_1_type_send_send_buf_complete) { > /* Copy the response back */ > memcpy(&net_dev->channel_init_packet, nvsp_msg_pkt, >- sizeof(nvsp_msg)); >+ sizeof(nvsp_msg)); > sema_post(&net_dev->channel_init_sema); > } else if (nvsp_msg_pkt->hdr.msg_type == >- nvsp_msg_1_type_send_rndis_pkt_complete) { >+ nvsp_msg_1_type_send_rndis_pkt_complete) { > /* Get the send context */ > net_vsc_pkt = > (netvsc_packet *)(unsigned long)pkt->transaction_id; >- if (NULL != net_vsc_pkt) { >- if (net_vsc_pkt->send_buf_section_idx != >- NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX) { >- synch_change_bit(net_vsc_pkt->send_buf_section_idx, >- net_dev->send_section_bitsmap); >- } >- >- /* Notify the layer above us */ >- net_vsc_pkt->compl.send.on_send_completion( >- net_vsc_pkt->compl.send.send_completion_context); > >- } >+ /* Notify the layer above us */ >+ net_vsc_pkt->compl.send.on_send_completion( >+ net_vsc_pkt->compl.send.send_completion_context); > > atomic_subtract_int(&net_dev->num_outstanding_sends, 1); > } >@@ -824,10 +821,10 @@ > send_msg.msgs.vers_1_msgs.send_rndis_pkt.chan_type = 1; > } > >+ /* Not using send buffer section */ > send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_idx = >- pkt->send_buf_section_idx; >- send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_size = >- pkt->send_buf_section_size; >+ 0xFFFFFFFF; >+ send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_size = 0; > > if (pkt->page_buf_count) { > ret = hv_vmbus_channel_send_packet_pagebuffer(device->channel, >@@ -853,81 +850,157 @@ > * In the FreeBSD Hyper-V virtual world, this function deals exclusively > * with virtual addresses. > */ >-static void >-hv_nv_on_receive(netvsc_dev *net_dev, struct hv_device *device, >- hv_vm_packet_descriptor *pkt) >+static void >+hv_nv_on_receive(struct hv_device *device, hv_vm_packet_descriptor *pkt) > { >+ netvsc_dev *net_dev; > hv_vm_transfer_page_packet_header *vm_xfer_page_pkt; > nvsp_msg *nvsp_msg_pkt; >- netvsc_packet vsc_pkt; >- netvsc_packet *net_vsc_pkt = &vsc_pkt; >- device_t dev = device->device; >+ netvsc_packet *net_vsc_pkt = NULL; >+ unsigned long start; >+ xfer_page_packet *xfer_page_pkt = NULL; >+ STAILQ_HEAD(PKT_LIST, netvsc_packet_) mylist_head = >+ STAILQ_HEAD_INITIALIZER(mylist_head); > int count = 0; > int i = 0; >- int status = nvsp_status_success; > >+ net_dev = hv_nv_get_inbound_net_device(device); >+ if (!net_dev) >+ return; >+ > /* > * All inbound packets other than send completion should be > * xfer page packet. > */ >- if (pkt->type != HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES) { >- device_printf(dev, "packet type %d is invalid!\n", pkt->type); >+ if (pkt->type != HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES) > return; >- } > > nvsp_msg_pkt = (nvsp_msg *)((unsigned long)pkt > + (pkt->data_offset8 << 3)); > > /* 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); >+ if (nvsp_msg_pkt->hdr.msg_type != nvsp_msg_1_type_send_rndis_pkt) > return; >- } > > vm_xfer_page_pkt = (hv_vm_transfer_page_packet_header *)pkt; > >- 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 (vm_xfer_page_pkt->transfer_page_set_id >+ != NETVSC_RECEIVE_BUFFER_ID) { > return; > } > >- count = vm_xfer_page_pkt->range_count; >- net_vsc_pkt->device = device; >+ STAILQ_INIT(&mylist_head); > >+ /* >+ * Grab free packets (range count + 1) to represent this xfer page >+ * packet. +1 to represent the xfer page packet itself. We grab it >+ * here so that we know exactly how many we can fulfill. >+ */ >+ mtx_lock_spin(&net_dev->rx_pkt_list_lock); >+ while (!STAILQ_EMPTY(&net_dev->myrx_packet_list)) { >+ net_vsc_pkt = STAILQ_FIRST(&net_dev->myrx_packet_list); >+ STAILQ_REMOVE_HEAD(&net_dev->myrx_packet_list, mylist_entry); >+ >+ STAILQ_INSERT_TAIL(&mylist_head, net_vsc_pkt, mylist_entry); >+ >+ if (++count == vm_xfer_page_pkt->range_count + 1) >+ break; >+ } >+ >+ mtx_unlock_spin(&net_dev->rx_pkt_list_lock); >+ >+ /* >+ * We need at least 2 netvsc pkts (1 to represent the xfer page >+ * and at least 1 for the range) i.e. we can handle some of the >+ * xfer page packet ranges... >+ */ >+ if (count < 2) { >+ /* Return netvsc packet to the freelist */ >+ mtx_lock_spin(&net_dev->rx_pkt_list_lock); >+ for (i=count; i != 0; i--) { >+ net_vsc_pkt = STAILQ_FIRST(&mylist_head); >+ STAILQ_REMOVE_HEAD(&mylist_head, mylist_entry); >+ >+ STAILQ_INSERT_TAIL(&net_dev->myrx_packet_list, >+ net_vsc_pkt, mylist_entry); >+ } >+ mtx_unlock_spin(&net_dev->rx_pkt_list_lock); >+ >+ hv_nv_send_receive_completion(device, >+ vm_xfer_page_pkt->d.transaction_id); >+ >+ return; >+ } >+ >+ /* Take the first packet in the list */ >+ xfer_page_pkt = (xfer_page_packet *)STAILQ_FIRST(&mylist_head); >+ STAILQ_REMOVE_HEAD(&mylist_head, mylist_entry); >+ >+ /* This is how many data packets we can supply */ >+ xfer_page_pkt->count = count - 1; >+ > /* 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 = >+ for (i=0; i < (count - 1); i++) { >+ net_vsc_pkt = STAILQ_FIRST(&mylist_head); >+ STAILQ_REMOVE_HEAD(&mylist_head, mylist_entry); >+ >+ /* >+ * Initialize the netvsc packet >+ */ >+ net_vsc_pkt->xfer_page_pkt = xfer_page_pkt; >+ net_vsc_pkt->compl.rx.rx_completion_context = net_vsc_pkt; >+ net_vsc_pkt->device = device; >+ /* Save this so that we can send it back */ >+ net_vsc_pkt->compl.rx.rx_completion_tid = >+ vm_xfer_page_pkt->d.transaction_id; >+ >+ net_vsc_pkt->tot_data_buf_len = > vm_xfer_page_pkt->ranges[i].byte_count; >+ net_vsc_pkt->page_buf_count = 1; > >- hv_rf_on_receive(net_dev, device, net_vsc_pkt); >- if (net_vsc_pkt->status != nvsp_status_success) { >- status = nvsp_status_failure; >- } >+ net_vsc_pkt->page_buffers[0].length = >+ vm_xfer_page_pkt->ranges[i].byte_count; >+ >+ /* The virtual address of the packet in the receive buffer */ >+ start = ((unsigned long)net_dev->rx_buf + >+ vm_xfer_page_pkt->ranges[i].byte_offset); >+ start = ((unsigned long)start) & ~(PAGE_SIZE - 1); >+ >+ /* Page number of the virtual page containing packet start */ >+ net_vsc_pkt->page_buffers[0].pfn = start >> PAGE_SHIFT; >+ >+ /* Calculate the page relative offset */ >+ net_vsc_pkt->page_buffers[0].offset = >+ vm_xfer_page_pkt->ranges[i].byte_offset & (PAGE_SIZE - 1); >+ >+ /* >+ * In this implementation, we are dealing with virtual >+ * addresses exclusively. Since we aren't using physical >+ * addresses at all, we don't care if a packet crosses a >+ * page boundary. For this reason, the original code to >+ * check for and handle page crossings has been removed. >+ */ >+ >+ /* >+ * Pass it to the upper layer. The receive completion call >+ * has been moved into this function. >+ */ >+ hv_rf_on_receive(device, net_vsc_pkt); >+ >+ /* >+ * Moved completion call back here so that all received >+ * messages (not just data messages) will trigger a response >+ * message back to the host. >+ */ >+ hv_nv_on_receive_completion(net_vsc_pkt); > } >- >- /* >- * Moved completion call back here so that all received >- * messages (not just data messages) will trigger a response >- * message back to the host. >- */ >- hv_nv_on_receive_completion(device, vm_xfer_page_pkt->d.transaction_id, >- status); > } > > /* >- * Net VSC on receive completion >- * >- * Send a receive completion packet to RNDIS device (ie NetVsp) >+ * Net VSC send receive completion > */ >-void >-hv_nv_on_receive_completion(struct hv_device *device, uint64_t tid, >- uint32_t status) >+static void >+hv_nv_send_receive_completion(struct hv_device *device, uint64_t tid) > { > nvsp_msg rx_comp_msg; > int retries = 0; >@@ -937,7 +1010,7 @@ > > /* Pass in the status */ > rx_comp_msg.msgs.vers_1_msgs.send_rndis_pkt_complete.status = >- status; >+ nvsp_status_success; > > retry_send_cmplt: > /* Send the completion */ >@@ -958,27 +1031,82 @@ > } > > /* >+ * Net VSC on receive completion >+ * >+ * Send a receive completion packet to RNDIS device (ie NetVsp) >+ */ >+void >+hv_nv_on_receive_completion(void *context) >+{ >+ netvsc_packet *packet = (netvsc_packet *)context; >+ struct hv_device *device = (struct hv_device *)packet->device; >+ netvsc_dev *net_dev; >+ uint64_t tid = 0; >+ boolean_t send_rx_completion = FALSE; >+ >+ /* >+ * Even though it seems logical to do a hv_nv_get_outbound_net_device() >+ * here to send out receive completion, we are using >+ * hv_nv_get_inbound_net_device() since we may have disabled >+ * outbound traffic already. >+ */ >+ net_dev = hv_nv_get_inbound_net_device(device); >+ if (net_dev == NULL) >+ return; >+ >+ /* Overloading use of the lock. */ >+ mtx_lock_spin(&net_dev->rx_pkt_list_lock); >+ >+ packet->xfer_page_pkt->count--; >+ >+ /* >+ * Last one in the line that represent 1 xfer page packet. >+ * Return the xfer page packet itself to the free list. >+ */ >+ if (packet->xfer_page_pkt->count == 0) { >+ send_rx_completion = TRUE; >+ tid = packet->compl.rx.rx_completion_tid; >+ STAILQ_INSERT_TAIL(&net_dev->myrx_packet_list, >+ (netvsc_packet *)(packet->xfer_page_pkt), mylist_entry); >+ } >+ >+ /* Put the packet back on the free list */ >+ STAILQ_INSERT_TAIL(&net_dev->myrx_packet_list, packet, mylist_entry); >+ mtx_unlock_spin(&net_dev->rx_pkt_list_lock); >+ >+ /* Send a receive completion for the xfer page packet */ >+ if (send_rx_completion) >+ hv_nv_send_receive_completion(device, tid); >+} >+ >+/* > * Net VSC on channel callback > */ > static void > hv_nv_on_channel_callback(void *context) > { >+ /* Fixme: Magic number */ >+ const int net_pkt_size = 2048; > struct hv_device *device = (struct hv_device *)context; > netvsc_dev *net_dev; >- device_t dev = device->device; > uint32_t bytes_rxed; > uint64_t request_id; >- hv_vm_packet_descriptor *desc; >+ uint8_t *packet; >+ hv_vm_packet_descriptor *desc; > uint8_t *buffer; >- int bufferlen = NETVSC_PACKET_SIZE; >- int ret = 0; >+ int bufferlen = net_pkt_size; >+ int ret = 0; > >+ packet = malloc(net_pkt_size * sizeof(uint8_t), M_DEVBUF, M_NOWAIT); >+ if (!packet) >+ return; >+ >+ buffer = packet; >+ > net_dev = hv_nv_get_inbound_net_device(device); > if (net_dev == NULL) >- return; >+ goto out; > >- buffer = net_dev->callback_buf; >- > do { > ret = hv_vmbus_channel_recv_packet_raw(device->channel, > buffer, bufferlen, &bytes_rxed, &request_id); >@@ -987,15 +1115,12 @@ > desc = (hv_vm_packet_descriptor *)buffer; > switch (desc->type) { > case HV_VMBUS_PACKET_TYPE_COMPLETION: >- hv_nv_on_send_completion(net_dev, device, desc); >+ hv_nv_on_send_completion(device, desc); > break; > case HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES: >- hv_nv_on_receive(net_dev, device, desc); >+ hv_nv_on_receive(device, desc); > break; > default: >- device_printf(dev, >- "hv_cb recv unknow type %d " >- " packet\n", desc->type); > break; > } > } else { >@@ -1003,18 +1128,9 @@ > } > } else if (ret == ENOBUFS) { > /* Handle large packet */ >- if (bufferlen > NETVSC_PACKET_SIZE) { >- free(buffer, M_NETVSC); >- buffer = NULL; >- } >- >- /* alloc new buffer */ >- buffer = malloc(bytes_rxed, M_NETVSC, M_NOWAIT); >+ free(buffer, M_DEVBUF); >+ buffer = malloc(bytes_rxed, M_DEVBUF, M_NOWAIT); > if (buffer == NULL) { >- device_printf(dev, >- "hv_cb malloc buffer failed, len=%u\n", >- bytes_rxed); >- bufferlen = 0; > break; > } > bufferlen = bytes_rxed; >@@ -1021,6 +1137,7 @@ > } > } while (1); > >- if (bufferlen > NETVSC_PACKET_SIZE) >- free(buffer, M_NETVSC); >+out: >+ free(buffer, M_DEVBUF); > } >+ >Index: sys/dev/hyperv/netvsc/hv_rndis.h >=================================================================== >--- sys/dev/hyperv/netvsc/hv_rndis.h (revision 285236) >+++ sys/dev/hyperv/netvsc/hv_rndis.h (revision 285224) >@@ -24,8 +24,6 @@ > * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF > * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >- * >- * $FreeBSD$ > */ > > #ifndef __HV_RNDIS_H__ >@@ -38,9 +36,6 @@ > #define NDIS_VERSION_5_0 0x00050000 > #define NDIS_VERSION_5_1 0x00050001 > #define NDIS_VERSION_6_0 0x00060000 >-#define NDIS_VERSION_6_1 0x00060001 >-#define NDIS_VERSION_6_30 0x0006001e >- > #define NDIS_VERSION (NDIS_VERSION_5_1) > > /* >@@ -352,37 +347,7 @@ > #define RNDIS_MAJOR_VERSION 0x00000001 > #define RNDIS_MINOR_VERSION 0x00000000 > >- > /* >- * Remote NDIS offload parameters >- */ >-#define RNDIS_OBJECT_TYPE_DEFAULT 0x80 >- >-#define RNDIS_OFFLOAD_PARAMETERS_REVISION_3 3 >-#define RNDIS_OFFLOAD_PARAMETERS_NO_CHANGE 0 >-#define RNDIS_OFFLOAD_PARAMETERS_LSOV2_DISABLED 1 >-#define RNDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED 2 >-#define RNDIS_OFFLOAD_PARAMETERS_LSOV1_ENABLED 2 >-#define RNDIS_OFFLOAD_PARAMETERS_RSC_DISABLED 1 >-#define RNDIS_OFFLOAD_PARAMETERS_RSC_ENABLED 2 >-#define RNDIS_OFFLOAD_PARAMETERS_TX_RX_DISABLED 1 >-#define RNDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED 2 >-#define RNDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED 3 >-#define RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED 4 >- >-#define RNDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE 1 >-#define RNDIS_TCP_LARGE_SEND_OFFLOAD_IPV4 0 >-#define RNDIS_TCP_LARGE_SEND_OFFLOAD_IPV6 1 >- >- >-#define RNDIS_OID_TCP_OFFLOAD_CURRENT_CONFIG 0xFC01020B /* query only */ >-#define RNDIS_OID_TCP_OFFLOAD_PARAMETERS 0xFC01020C /* set only */ >-#define RNDIS_OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES 0xFC01020D/* query only */ >-#define RNDIS_OID_TCP_CONNECTION_OFFLOAD_CURRENT_CONFIG 0xFC01020E /* query only */ >-#define RNDIS_OID_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES 0xFC01020F /* query */ >-#define RNDIS_OID_OFFLOAD_ENCAPSULATION 0x0101010A /* set/query */ >- >-/* > * NdisInitialize message > */ > typedef struct rndis_initialize_request_ { >@@ -620,108 +585,6 @@ > } u1; > } ndis_8021q_info; > >-struct rndis_object_header { >- uint8_t type; >- uint8_t revision; >- uint16_t size; >-}; >- >-typedef struct rndis_offload_params_ { >- struct rndis_object_header header; >- uint8_t ipv4_csum; >- uint8_t tcp_ipv4_csum; >- uint8_t udp_ipv4_csum; >- uint8_t tcp_ipv6_csum; >- uint8_t udp_ipv6_csum; >- uint8_t lso_v1; >- uint8_t ip_sec_v1; >- uint8_t lso_v2_ipv4; >- uint8_t lso_v2_ipv6; >- uint8_t tcp_connection_ipv4; >- uint8_t tcp_connection_ipv6; >- uint32_t flags; >- uint8_t ip_sec_v2; >- uint8_t ip_sec_v2_ipv4; >- struct { >- uint8_t rsc_ipv4; >- uint8_t rsc_ipv6; >- }; >- struct { >- uint8_t encapsulated_packet_task_offload; >- uint8_t encapsulation_types; >- }; >- >-} rndis_offload_params; >- >- >-typedef struct rndis_tcp_ip_csum_info_ { >- union { >- struct { >- uint32_t is_ipv4:1; >- uint32_t is_ipv6:1; >- uint32_t tcp_csum:1; >- uint32_t udp_csum:1; >- uint32_t ip_header_csum:1; >- uint32_t reserved:11; >- uint32_t tcp_header_offset:10; >- } xmit; >- struct { >- uint32_t tcp_csum_failed:1; >- uint32_t udp_csum_failed:1; >- uint32_t ip_csum_failed:1; >- uint32_t tcp_csum_succeeded:1; >- uint32_t udp_csum_succeeded:1; >- uint32_t ip_csum_succeeded:1; >- uint32_t loopback:1; >- uint32_t tcp_csum_value_invalid:1; >- uint32_t ip_csum_value_invalid:1; >- } receive; >- uint32_t value; >- }; >-} rndis_tcp_ip_csum_info; >- >-typedef struct rndis_tcp_tso_info_ { >- union { >- struct { >- uint32_t unused:30; >- uint32_t type:1; >- uint32_t reserved2:1; >- } xmit; >- struct { >- uint32_t mss:20; >- uint32_t tcp_header_offset:10; >- uint32_t type:1; >- uint32_t reserved2:1; >- } lso_v1_xmit; >- struct { >- uint32_t tcp_payload:30; >- uint32_t type:1; >- uint32_t reserved2:1; >- } lso_v1_xmit_complete; >- struct { >- uint32_t mss:20; >- uint32_t tcp_header_offset:10; >- uint32_t type:1; >- uint32_t ip_version:1; >- } lso_v2_xmit; >- struct { >- uint32_t reserved:30; >- uint32_t type:1; >- uint32_t reserved2:1; >- } lso_v2_xmit_complete; >- uint32_t value; >- }; >-} rndis_tcp_tso_info; >- >-#define RNDIS_VLAN_PPI_SIZE (sizeof(rndis_per_packet_info) + \ >- sizeof(ndis_8021q_info)) >- >-#define RNDIS_CSUM_PPI_SIZE (sizeof(rndis_per_packet_info) + \ >- sizeof(rndis_tcp_ip_csum_info)) >- >-#define RNDIS_TSO_PPI_SIZE (sizeof(rndis_per_packet_info) + \ >- sizeof(rndis_tcp_tso_info)) >- > /* > * Format of Information buffer passed in a SetRequest for the OID > * OID_GEN_RNDIS_CONFIG_PARAMETER. >@@ -1043,18 +906,6 @@ > #define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400 > #define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800 > >-/* >- * Externs >- */ >-int netvsc_recv(struct hv_device *device_ctx, >- netvsc_packet *packet, >- rndis_tcp_ip_csum_info *csum_info); > >-void* hv_set_rppi_data(rndis_msg *rndis_mesg, >- uint32_t rppi_size, >- int pkt_type); >- >-void* hv_get_ppi_data(rndis_packet *rpkt, uint32_t type); >- > #endif /* __HV_RNDIS_H__ */ > >Index: sys/dev/hyperv/netvsc/hv_rndis_filter.c >=================================================================== >--- sys/dev/hyperv/netvsc/hv_rndis_filter.c (revision 285236) >+++ sys/dev/hyperv/netvsc/hv_rndis_filter.c (revision 285224) >@@ -67,67 +67,12 @@ > static int hv_rf_init_device(rndis_device *device); > static int hv_rf_open_device(rndis_device *device); > static int hv_rf_close_device(rndis_device *device); >+static void hv_rf_on_send_completion(void *context); > static void hv_rf_on_send_request_completion(void *context); > static void hv_rf_on_send_request_halt_completion(void *context); >-int >-hv_rf_send_offload_request(struct hv_device *device, >- rndis_offload_params *offloads); >-/* >- * Set the Per-Packet-Info with the specified type >- */ >-void * >-hv_set_rppi_data(rndis_msg *rndis_mesg, uint32_t rppi_size, >- int pkt_type) >-{ >- rndis_packet *rndis_pkt; >- rndis_per_packet_info *rppi; > >- rndis_pkt = &rndis_mesg->msg.packet; >- rndis_pkt->data_offset += rppi_size; > >- rppi = (rndis_per_packet_info *)((char *)rndis_pkt + >- rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_length); >- >- rppi->size = rppi_size; >- rppi->type = pkt_type; >- rppi->per_packet_info_offset = sizeof(rndis_per_packet_info); >- >- rndis_pkt->per_pkt_info_length += rppi_size; >- >- return (rppi); >-} >- > /* >- * Get the Per-Packet-Info with the specified type >- * return NULL if not found. >- */ >-void * >-hv_get_ppi_data(rndis_packet *rpkt, uint32_t type) >-{ >- rndis_per_packet_info *ppi; >- int len; >- >- if (rpkt->per_pkt_info_offset == 0) >- return (NULL); >- >- ppi = (rndis_per_packet_info *)((unsigned long)rpkt + >- rpkt->per_pkt_info_offset); >- len = rpkt->per_pkt_info_length; >- >- while (len > 0) { >- if (ppi->type == type) >- return (void *)((unsigned long)ppi + >- ppi->per_packet_info_offset); >- >- len -= ppi->size; >- ppi = (rndis_per_packet_info *)((unsigned long)ppi + ppi->size); >- } >- >- return (NULL); >-} >- >- >-/* > * Allow module_param to work and override to switch to promiscuous mode. > */ > static inline rndis_device * >@@ -135,7 +80,7 @@ > { > rndis_device *device; > >- device = malloc(sizeof(rndis_device), M_NETVSC, M_NOWAIT | M_ZERO); >+ device = malloc(sizeof(rndis_device), M_DEVBUF, M_NOWAIT | M_ZERO); > if (device == NULL) { > return (NULL); > } >@@ -157,7 +102,7 @@ > hv_put_rndis_device(rndis_device *device) > { > mtx_destroy(&device->req_lock); >- free(device, M_NETVSC); >+ free(device, M_DEVBUF); > } > > /* >@@ -171,7 +116,7 @@ > rndis_msg *rndis_mesg; > rndis_set_request *set; > >- request = malloc(sizeof(rndis_request), M_NETVSC, M_NOWAIT | M_ZERO); >+ request = malloc(sizeof(rndis_request), M_DEVBUF, M_NOWAIT | M_ZERO); > if (request == NULL) { > return (NULL); > } >@@ -216,7 +161,7 @@ > mtx_unlock_spin(&device->req_lock); > > sema_destroy(&request->wait_sema); >- free(request, M_NETVSC); >+ free(request, M_DEVBUF); > } > > /* >@@ -224,7 +169,7 @@ > */ > static int > hv_rf_send_request(rndis_device *device, rndis_request *request, >- uint32_t message_type) >+ uint32_t message_type) > { > int ret; > netvsc_packet *packet; >@@ -251,9 +196,6 @@ > hv_rf_on_send_request_halt_completion; > } > packet->compl.send.send_completion_tid = (unsigned long)device; >- packet->send_buf_section_idx = >- NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX; >- packet->send_buf_section_size = 0; > > ret = hv_nv_on_send(device->net_dev->dev, packet); > >@@ -306,84 +248,6 @@ > } > } > >-int >-hv_rf_send_offload_request(struct hv_device *device, >- rndis_offload_params *offloads) >-{ >- rndis_request *request; >- rndis_set_request *set; >- rndis_offload_params *offload_req; >- rndis_set_complete *set_complete; >- rndis_device *rndis_dev; >- hn_softc_t *sc = device_get_softc(device->device); >- device_t dev = device->device; >- netvsc_dev *net_dev = sc->net_dev; >- uint32_t vsp_version = net_dev->nvsp_version; >- uint32_t extlen = sizeof(rndis_offload_params); >- int ret; >- >- if (vsp_version <= NVSP_PROTOCOL_VERSION_4) { >- extlen = VERSION_4_OFFLOAD_SIZE; >- /* On NVSP_PROTOCOL_VERSION_4 and below, we do not support >- * UDP checksum offload. >- */ >- offloads->udp_ipv4_csum = 0; >- offloads->udp_ipv6_csum = 0; >- } >- >- rndis_dev = net_dev->extension; >- >- request = hv_rndis_request(rndis_dev, REMOTE_NDIS_SET_MSG, >- RNDIS_MESSAGE_SIZE(rndis_set_request) + extlen); >- if (!request) >- return (ENOMEM); >- >- set = &request->request_msg.msg.set_request; >- set->oid = RNDIS_OID_TCP_OFFLOAD_PARAMETERS; >- set->info_buffer_length = extlen; >- set->info_buffer_offset = sizeof(rndis_set_request); >- set->device_vc_handle = 0; >- >- offload_req = (rndis_offload_params *)((unsigned long)set + >- set->info_buffer_offset); >- *offload_req = *offloads; >- offload_req->header.type = RNDIS_OBJECT_TYPE_DEFAULT; >- offload_req->header.revision = RNDIS_OFFLOAD_PARAMETERS_REVISION_3; >- offload_req->header.size = extlen; >- >- ret = hv_rf_send_request(rndis_dev, request, REMOTE_NDIS_SET_MSG); >- if (ret != 0) { >- device_printf(dev, "hv send offload request failed, ret=%d!\n", >- ret); >- goto cleanup; >- } >- >- ret = sema_timedwait(&request->wait_sema, 500); >- if (ret != 0) { >- device_printf(dev, "hv send offload request timeout\n"); >- goto cleanup; >- } >- >- set_complete = &request->response_msg.msg.set_complete; >- if (set_complete->status == RNDIS_STATUS_SUCCESS) { >- device_printf(dev, "hv send offload request succeeded\n"); >- ret = 0; >- } else { >- if (set_complete->status == STATUS_NOT_SUPPORTED) { >- device_printf(dev, "HV Not support offload\n"); >- ret = 0; >- } else { >- ret = set_complete->status; >- } >- } >- >-cleanup: >- if (request) >- hv_put_rndis_request(rndis_dev, request); >- >- return (ret); >-} >- > /* > * RNDIS filter receive indicate status > */ >@@ -392,18 +256,12 @@ > { > rndis_indicate_status *indicate = &response->msg.indicate_status; > >- switch(indicate->status) { >- case RNDIS_STATUS_MEDIA_CONNECT: >+ if (indicate->status == RNDIS_STATUS_MEDIA_CONNECT) { > netvsc_linkstatus_callback(device->net_dev->dev, 1); >- break; >- case RNDIS_STATUS_MEDIA_DISCONNECT: >+ } else if (indicate->status == RNDIS_STATUS_MEDIA_DISCONNECT) { > netvsc_linkstatus_callback(device->net_dev->dev, 0); >- break; >- default: >+ } else { > /* TODO: */ >- device_printf(device->net_dev->dev->device, >- "unknown status %d received\n", indicate->status); >- break; > } > } > >@@ -414,10 +272,9 @@ > hv_rf_receive_data(rndis_device *device, rndis_msg *message, netvsc_packet *pkt) > { > rndis_packet *rndis_pkt; >- ndis_8021q_info *rppi_vlan_info; >+ rndis_per_packet_info *rppi; >+ ndis_8021q_info *rppi_vlan_info; > uint32_t data_offset; >- rndis_tcp_ip_csum_info *csum_info = NULL; >- device_t dev = device->net_dev->dev->device; > > rndis_pkt = &message->msg.packet; > >@@ -429,27 +286,34 @@ > /* Remove rndis header, then pass data packet up the stack */ > data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset; > >- pkt->tot_data_buf_len -= data_offset; >- if (pkt->tot_data_buf_len < rndis_pkt->data_length) { >- pkt->status = nvsp_status_failure; >- device_printf(dev, >- "total length %u is less than data length %u\n", >- pkt->tot_data_buf_len, rndis_pkt->data_length); >- return; >- } >+ /* L2 frame length, with L2 header, not including CRC */ >+ pkt->tot_data_buf_len = rndis_pkt->data_length; >+ pkt->page_buffers[0].offset += data_offset; >+ /* Buffer length now L2 frame length plus trailing junk */ >+ pkt->page_buffers[0].length -= data_offset; > >- pkt->tot_data_buf_len = rndis_pkt->data_length; >- pkt->data = (void *)((unsigned long)pkt->data + data_offset); >+ pkt->is_data_pkt = TRUE; > >- rppi_vlan_info = hv_get_ppi_data(rndis_pkt, ieee_8021q_info); >- if (rppi_vlan_info) { >- pkt->vlan_tci = rppi_vlan_info->u1.s1.vlan_id; >- } else { >- pkt->vlan_tci = 0; >+ pkt->vlan_tci = 0; >+ >+ /* >+ * Read the VLAN ID if supplied by the Hyper-V infrastructure. >+ * Let higher-level driver code decide if it wants to use it. >+ * Ignore CFI, priority for now as FreeBSD does not support these. >+ */ >+ if (rndis_pkt->per_pkt_info_offset != 0) { >+ /* rppi struct exists; compute its address */ >+ rppi = (rndis_per_packet_info *)((uint8_t *)rndis_pkt + >+ rndis_pkt->per_pkt_info_offset); >+ /* if VLAN ppi struct, get the VLAN ID */ >+ if (rppi->type == ieee_8021q_info) { >+ rppi_vlan_info = (ndis_8021q_info *)((uint8_t *)rppi >+ + rppi->per_packet_info_offset); >+ pkt->vlan_tci = rppi_vlan_info->u1.s1.vlan_id; >+ } > } > >- csum_info = hv_get_ppi_data(rndis_pkt, tcpip_chksum_info); >- netvsc_recv(device->net_dev->dev, pkt, csum_info); >+ netvsc_recv(device->net_dev->dev, pkt); > } > > /* >@@ -456,30 +320,54 @@ > * RNDIS filter on receive > */ > int >-hv_rf_on_receive(netvsc_dev *net_dev, struct hv_device *device, netvsc_packet *pkt) >+hv_rf_on_receive(struct hv_device *device, netvsc_packet *pkt) > { >+ hn_softc_t *sc = device_get_softc(device->device); >+ netvsc_dev *net_dev = sc->net_dev; > rndis_device *rndis_dev; >+ rndis_msg rndis_mesg; > rndis_msg *rndis_hdr; > > /* Make sure the rndis device state is initialized */ >- if (net_dev->extension == NULL) { >- pkt->status = nvsp_status_failure; >+ if (net_dev->extension == NULL) > return (ENODEV); >- } > > rndis_dev = (rndis_device *)net_dev->extension; >- if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) { >- pkt->status = nvsp_status_failure; >+ if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) > return (EINVAL); >+ >+ /* Shift virtual page number to form virtual page address */ >+ rndis_hdr = (rndis_msg *)(uintptr_t)(pkt->page_buffers[0].pfn << PAGE_SHIFT); >+ >+ rndis_hdr = (void *)((unsigned long)rndis_hdr >+ + pkt->page_buffers[0].offset); >+ >+ /* >+ * Make sure we got a valid rndis message >+ * Fixme: There seems to be a bug in set completion msg where >+ * its msg_len is 16 bytes but the byte_count field in the >+ * xfer page range shows 52 bytes >+ */ >+#if 0 >+ if (pkt->tot_data_buf_len != rndis_hdr->msg_len) { >+ DPRINT_ERR(NETVSC, "invalid rndis message? (expected %u " >+ "bytes got %u)... dropping this message!", >+ rndis_hdr->msg_len, pkt->tot_data_buf_len); >+ DPRINT_EXIT(NETVSC); >+ >+ return (-1); > } >+#endif > >- rndis_hdr = pkt->data; >+ memcpy(&rndis_mesg, rndis_hdr, >+ (rndis_hdr->msg_len > sizeof(rndis_msg)) ? >+ sizeof(rndis_msg) : rndis_hdr->msg_len); > >- switch (rndis_hdr->ndis_msg_type) { >+ switch (rndis_mesg.ndis_msg_type) { > > /* data message */ > case REMOTE_NDIS_PACKET_MSG: >- hv_rf_receive_data(rndis_dev, rndis_hdr, pkt); >+ hv_rf_receive_data(rndis_dev, &rndis_mesg, pkt); > break; > /* completion messages */ > case REMOTE_NDIS_INITIALIZE_CMPLT: >@@ -487,15 +375,15 @@ > case REMOTE_NDIS_SET_CMPLT: > case REMOTE_NDIS_RESET_CMPLT: > case REMOTE_NDIS_KEEPALIVE_CMPLT: >- hv_rf_receive_response(rndis_dev, rndis_hdr); >+ hv_rf_receive_response(rndis_dev, &rndis_mesg); > break; > /* notification message */ > case REMOTE_NDIS_INDICATE_STATUS_MSG: >- hv_rf_receive_indicate_status(rndis_dev, rndis_hdr); >+ hv_rf_receive_indicate_status(rndis_dev, &rndis_mesg); > break; > default: > printf("hv_rf_on_receive(): Unknown msg_type 0x%x\n", >- rndis_hdr->ndis_msg_type); >+ rndis_mesg.ndis_msg_type); > break; > } > >@@ -823,9 +711,7 @@ > int ret; > netvsc_dev *net_dev; > rndis_device *rndis_dev; >- rndis_offload_params offloads; > netvsc_device_info *dev_info = (netvsc_device_info *)additl_info; >- device_t dev = device->device; > > rndis_dev = hv_get_rndis_device(); > if (rndis_dev == NULL) { >@@ -866,22 +752,6 @@ > if (ret != 0) { > /* TODO: shut down rndis device and the channel */ > } >- >- /* config csum offload and send request to host */ >- memset(&offloads, 0, sizeof(offloads)); >- offloads.ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; >- offloads.tcp_ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; >- offloads.udp_ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; >- offloads.tcp_ipv6_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; >- offloads.udp_ipv6_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; >- offloads.lso_v2_ipv4 = RNDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED; >- >- ret = hv_rf_send_offload_request(device, &offloads); >- if (ret != 0) { >- /* TODO: shut down rndis device and the channel */ >- device_printf(dev, >- "hv_rf_send_offload_request failed, ret=%d\n", ret); >- } > > memcpy(dev_info->mac_addr, rndis_dev->hw_mac_addr, HW_MACADDR_LEN); > >@@ -940,6 +810,103 @@ > } > > /* >+ * RNDIS filter on send >+ */ >+int >+hv_rf_on_send(struct hv_device *device, netvsc_packet *pkt) >+{ >+ rndis_filter_packet *filter_pkt; >+ rndis_msg *rndis_mesg; >+ rndis_packet *rndis_pkt; >+ rndis_per_packet_info *rppi; >+ ndis_8021q_info *rppi_vlan_info; >+ uint32_t rndis_msg_size; >+ int ret = 0; >+ >+ /* Add the rndis header */ >+ filter_pkt = (rndis_filter_packet *)pkt->extension; >+ >+ memset(filter_pkt, 0, sizeof(rndis_filter_packet)); >+ >+ rndis_mesg = &filter_pkt->message; >+ rndis_msg_size = RNDIS_MESSAGE_SIZE(rndis_packet); >+ >+ if (pkt->vlan_tci != 0) { >+ rndis_msg_size += sizeof(rndis_per_packet_info) + >+ sizeof(ndis_8021q_info); >+ } >+ >+ rndis_mesg->ndis_msg_type = REMOTE_NDIS_PACKET_MSG; >+ rndis_mesg->msg_len = pkt->tot_data_buf_len + rndis_msg_size; >+ >+ rndis_pkt = &rndis_mesg->msg.packet; >+ rndis_pkt->data_offset = sizeof(rndis_packet); >+ rndis_pkt->data_length = pkt->tot_data_buf_len; >+ >+ pkt->is_data_pkt = TRUE; >+ pkt->page_buffers[0].pfn = hv_get_phys_addr(rndis_mesg) >> PAGE_SHIFT; >+ pkt->page_buffers[0].offset = >+ (unsigned long)rndis_mesg & (PAGE_SIZE - 1); >+ pkt->page_buffers[0].length = rndis_msg_size; >+ >+ /* Save the packet context */ >+ filter_pkt->completion_context = >+ pkt->compl.send.send_completion_context; >+ >+ /* Use ours */ >+ pkt->compl.send.on_send_completion = hv_rf_on_send_completion; >+ pkt->compl.send.send_completion_context = filter_pkt; >+ >+ /* >+ * If there is a VLAN tag, we need to set up some additional >+ * fields so the Hyper-V infrastructure will stuff the VLAN tag >+ * into the frame. >+ */ >+ if (pkt->vlan_tci != 0) { >+ /* Move data offset past end of rppi + VLAN structs */ >+ rndis_pkt->data_offset += sizeof(rndis_per_packet_info) + >+ sizeof(ndis_8021q_info); >+ >+ /* must be set when we have rppi, VLAN info */ >+ rndis_pkt->per_pkt_info_offset = sizeof(rndis_packet); >+ rndis_pkt->per_pkt_info_length = sizeof(rndis_per_packet_info) + >+ sizeof(ndis_8021q_info); >+ >+ /* rppi immediately follows rndis_pkt */ >+ rppi = (rndis_per_packet_info *)(rndis_pkt + 1); >+ rppi->size = sizeof(rndis_per_packet_info) + >+ sizeof(ndis_8021q_info); >+ rppi->type = ieee_8021q_info; >+ rppi->per_packet_info_offset = sizeof(rndis_per_packet_info); >+ >+ /* VLAN info immediately follows rppi struct */ >+ rppi_vlan_info = (ndis_8021q_info *)(rppi + 1); >+ /* FreeBSD does not support CFI or priority */ >+ rppi_vlan_info->u1.s1.vlan_id = pkt->vlan_tci & 0xfff; >+ } >+ >+ /* >+ * Invoke netvsc send. If return status is bad, the caller now >+ * resets the context pointers before retrying. >+ */ >+ ret = hv_nv_on_send(device, pkt); >+ >+ return (ret); >+} >+ >+/* >+ * RNDIS filter on send completion callback >+ */ >+static void >+hv_rf_on_send_completion(void *context) >+{ >+ rndis_filter_packet *filter_pkt = (rndis_filter_packet *)context; >+ >+ /* Pass it back to the original handler */ >+ netvsc_xmit_completion(filter_pkt->completion_context); >+} >+ >+/* > * RNDIS filter on send request completion callback > */ > static void >Index: sys/dev/hyperv/netvsc/hv_net_vsc.h >=================================================================== >--- sys/dev/hyperv/netvsc/hv_net_vsc.h (revision 285236) >+++ sys/dev/hyperv/netvsc/hv_net_vsc.h (revision 285224) >@@ -41,26 +41,20 @@ > #include <sys/types.h> > #include <sys/param.h> > #include <sys/lock.h> >-#include <sys/malloc.h> > #include <sys/sx.h> > > #include <dev/hyperv/include/hyperv.h> > >-MALLOC_DECLARE(M_NETVSC); > > #define NVSP_INVALID_PROTOCOL_VERSION (0xFFFFFFFF) > > #define NVSP_PROTOCOL_VERSION_1 2 > #define NVSP_PROTOCOL_VERSION_2 0x30002 >-#define NVSP_PROTOCOL_VERSION_4 0x40000 >-#define NVSP_PROTOCOL_VERSION_5 0x50000 > #define NVSP_MIN_PROTOCOL_VERSION (NVSP_PROTOCOL_VERSION_1) > #define NVSP_MAX_PROTOCOL_VERSION (NVSP_PROTOCOL_VERSION_2) > > #define NVSP_PROTOCOL_VERSION_CURRENT NVSP_PROTOCOL_VERSION_2 > >-#define VERSION_4_OFFLOAD_SIZE 22 >- > #define NVSP_OPERATIONAL_STATUS_OK (0x00000000) > #define NVSP_OPERATIONAL_STATUS_DEGRADED (0x00000001) > #define NVSP_OPERATIONAL_STATUS_NONRECOVERABLE (0x00000002) >@@ -550,7 +544,7 @@ > > > #define NVSP_1_CHIMNEY_SEND_INVALID_OOB_INDEX 0xffffu >-#define NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX 0xffffffff >+#define NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX 0xffffu > > /* > * NvspMessage2TypeSendChimneyPacket >@@ -848,11 +842,11 @@ > * Defines > */ > >-#define NETVSC_SEND_BUFFER_SIZE (1024*1024*15) /* 15M */ >+#define NETVSC_SEND_BUFFER_SIZE (64*1024) /* 64K */ > #define NETVSC_SEND_BUFFER_ID 0xface > > >-#define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024*16) /* 16MB */ >+#define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024) /* 1MB */ > > #define NETVSC_RECEIVE_BUFFER_ID 0xcafe > >@@ -868,8 +862,6 @@ > */ > #define NETVSC_MAX_CONFIGURABLE_MTU (9 * 1024) > >-#define NETVSC_PACKET_SIZE PAGE_SIZE >- > /* > * Data types > */ >@@ -881,14 +873,15 @@ > struct hv_device *dev; > int num_outstanding_sends; > >+ /* List of free preallocated NETVSC_PACKET to represent RX packet */ >+ STAILQ_HEAD(PQ, netvsc_packet_) myrx_packet_list; >+ struct mtx rx_pkt_list_lock; >+ > /* Send buffer allocated by us but manages by NetVSP */ > void *send_buf; > uint32_t send_buf_size; > uint32_t send_buf_gpadl_handle; > uint32_t send_section_size; >- uint32_t send_section_count; >- unsigned long bitsmap_words; >- unsigned long *send_section_bitsmap; > > /* Receive buffer allocated by us but managed by NetVSP */ > void *rx_buf; >@@ -910,43 +903,35 @@ > hv_bool_uint8_t destroy; > /* Negotiated NVSP version */ > uint32_t nvsp_version; >- >- uint8_t callback_buf[NETVSC_PACKET_SIZE]; > } netvsc_dev; > > > typedef void (*pfn_on_send_rx_completion)(void *); > >-#define NETVSC_DEVICE_RING_BUFFER_SIZE (128 * PAGE_SIZE) >-#define NETVSC_PACKET_MAXPAGE 32 >+#define NETVSC_DEVICE_RING_BUFFER_SIZE (64 * PAGE_SIZE) >+#define NETVSC_PACKET_MAXPAGE 16 > > >-#define NETVSC_VLAN_PRIO_MASK 0xe000 >-#define NETVSC_VLAN_PRIO_SHIFT 13 >-#define NETVSC_VLAN_VID_MASK 0x0fff >+typedef struct xfer_page_packet_ { >+ /* >+ * This needs to be here because the network RX code casts >+ * an instantiation of this structure to a netvsc_packet. >+ */ >+ STAILQ_ENTRY(netvsc_packet_) mylist_entry; > >-#define TYPE_IPV4 2 >-#define TYPE_IPV6 4 >-#define TYPE_TCP 2 >-#define TYPE_UDP 4 >+ uint32_t count; >+} xfer_page_packet; > >-#define TRANSPORT_TYPE_NOT_IP 0 >-#define TRANSPORT_TYPE_IPV4_TCP ((TYPE_IPV4 << 16) | TYPE_TCP) >-#define TRANSPORT_TYPE_IPV4_UDP ((TYPE_IPV4 << 16) | TYPE_UDP) >-#define TRANSPORT_TYPE_IPV6_TCP ((TYPE_IPV6 << 16) | TYPE_TCP) >-#define TRANSPORT_TYPE_IPV6_UDP ((TYPE_IPV6 << 16) | TYPE_UDP) >- >-#ifdef __LP64__ >-#define BITS_PER_LONG 64 >-#else >-#define BITS_PER_LONG 32 >-#endif >- > typedef struct netvsc_packet_ { >+ /* >+ * List used when enqueued on &net_dev->rx_packet_list, >+ * and when enqueued within the netvsc code >+ */ >+ STAILQ_ENTRY(netvsc_packet_) mylist_entry; > struct hv_device *device; > hv_bool_uint8_t is_data_pkt; /* One byte */ > uint16_t vlan_tci; >- uint32_t status; >+ xfer_page_packet *xfer_page_pkt; > > /* Completion */ > union { >@@ -963,12 +948,9 @@ > pfn_on_send_rx_completion on_send_completion; > } send; > } compl; >- uint32_t send_buf_section_idx; >- uint32_t send_buf_section_size; > >- void *rndis_mesg; >+ void *extension; > uint32_t tot_data_buf_len; >- void *data; > uint32_t page_buf_count; > hv_vmbus_page_buffer page_buffers[NETVSC_PACKET_MAXPAGE]; > } netvsc_packet; >@@ -1002,16 +984,16 @@ > */ > extern int hv_promisc_mode; > >-void netvsc_linkstatus_callback(struct hv_device *device_obj, uint32_t status); >-void netvsc_xmit_completion(void *context); >-void hv_nv_on_receive_completion(struct hv_device *device, >- uint64_t tid, uint32_t status); >-netvsc_dev *hv_nv_on_device_add(struct hv_device *device, >- void *additional_info); >-int hv_nv_on_device_remove(struct hv_device *device, >- boolean_t destroy_channel); >-int hv_nv_on_send(struct hv_device *device, netvsc_packet *pkt); >-int hv_nv_get_next_send_section(netvsc_dev *net_dev); >+extern void netvsc_linkstatus_callback(struct hv_device *device_obj, >+ uint32_t status); >+extern int netvsc_recv(struct hv_device *device_obj, netvsc_packet *packet); >+extern void netvsc_xmit_completion(void *context); > >+extern void hv_nv_on_receive_completion(void *context); >+extern netvsc_dev *hv_nv_on_device_add(struct hv_device *device, void *additional_info); >+extern int hv_nv_on_device_remove(struct hv_device *device, >+ boolean_t destroy_channel); >+extern int hv_nv_on_send(struct hv_device *device, netvsc_packet *pkt); >+ > #endif /* __HV_NET_VSC_H__ */ > >Index: sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c >=================================================================== >--- sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c (revision 285236) >+++ sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c (revision 285224) >@@ -55,9 +55,6 @@ > #include <sys/cdefs.h> > __FBSDID("$FreeBSD$"); > >-#include "opt_inet6.h" >-#include "opt_inet.h" >- > #include <sys/param.h> > #include <sys/systm.h> > #include <sys/sockio.h> >@@ -86,9 +83,6 @@ > #include <netinet/in.h> > #include <netinet/ip.h> > #include <netinet/if_ether.h> >-#include <netinet/tcp.h> >-#include <netinet/udp.h> >-#include <netinet/ip6.h> > > #include <vm/vm.h> > #include <vm/vm_param.h> >@@ -109,8 +103,6 @@ > > #include <machine/intr_machdep.h> > >-#include <machine/in_cksum.h> >- > #include <dev/hyperv/include/hyperv.h> > #include "hv_net_vsc.h" > #include "hv_rndis.h" >@@ -173,62 +165,7 @@ > static int hn_start_locked(struct ifnet *ifp); > static void hn_start(struct ifnet *ifp); > >-/* >- * NetVsc get message transport protocol type >- */ >-static uint32_t get_transport_proto_type(struct mbuf *m_head) >-{ >- uint32_t ret_val = TRANSPORT_TYPE_NOT_IP; >- uint16_t ether_type = 0; >- int ether_len = 0; >- struct ether_vlan_header *eh; >-#ifdef INET >- struct ip *iph; >-#endif >-#ifdef INET6 >- struct ip6_hdr *ip6; >-#endif > >- eh = mtod(m_head, struct ether_vlan_header*); >- if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { >- ether_len = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; >- ether_type = eh->evl_proto; >- } else { >- ether_len = ETHER_HDR_LEN; >- ether_type = eh->evl_encap_proto; >- } >- >- switch (ntohs(ether_type)) { >-#ifdef INET6 >- case ETHERTYPE_IPV6: >- ip6 = (struct ip6_hdr *)(m_head->m_data + ether_len); >- >- if (IPPROTO_TCP == ip6->ip6_nxt) { >- ret_val = TRANSPORT_TYPE_IPV6_TCP; >- } else if (IPPROTO_UDP == ip6->ip6_nxt) { >- ret_val = TRANSPORT_TYPE_IPV6_UDP; >- } >- break; >-#endif >-#ifdef INET >- case ETHERTYPE_IP: >- iph = (struct ip *)(m_head->m_data + ether_len); >- >- if (IPPROTO_TCP == iph->ip_p) { >- ret_val = TRANSPORT_TYPE_IPV4_TCP; >- } else if (IPPROTO_UDP == iph->ip_p) { >- ret_val = TRANSPORT_TYPE_IPV4_UDP; >- } >- break; >-#endif >- default: >- ret_val = TRANSPORT_TYPE_NOT_IP; >- break; >- } >- >- return (ret_val); >-} >- > /* > * NetVsc driver initialization > * Note: Filter init is no longer required >@@ -339,11 +276,8 @@ > * Tell upper layers that we support full VLAN capability. > */ > ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); >- ifp->if_capabilities |= >- IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_TSO; >- ifp->if_capenable |= >- IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_TSO; >- ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_TSO; >+ ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; >+ ifp->if_capenable |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; > > ret = hv_rf_on_device_add(device_ctx, &device_info); > if (ret != 0) { >@@ -413,7 +347,7 @@ > mb = (struct mbuf *)(uintptr_t)packet->compl.send.send_completion_tid; > buf = ((uint8_t *)packet) - HV_NV_PACKET_OFFSET_IN_BUF; > >- free(buf, M_NETVSC); >+ free(buf, M_DEVBUF); > > if (mb != NULL) { > m_freem(mb); >@@ -428,29 +362,17 @@ > { > hn_softc_t *sc = ifp->if_softc; > struct hv_device *device_ctx = vmbus_get_devctx(sc->hn_dev); >- netvsc_dev *net_dev = sc->net_dev; >- device_t dev = device_ctx->device; > uint8_t *buf; > netvsc_packet *packet; > struct mbuf *m_head, *m; > struct mbuf *mc_head = NULL; >- struct ether_vlan_header *eh; >- rndis_msg *rndis_mesg; >- rndis_packet *rndis_pkt; >- rndis_per_packet_info *rppi; >- ndis_8021q_info *rppi_vlan_info; >- rndis_tcp_ip_csum_info *csum_info; >- rndis_tcp_tso_info *tso_info; >- int ether_len; > int i; > int num_frags; > int len; >+ int xlen; >+ int rppi_size; > int retries = 0; >- int ret = 0; >- uint32_t rndis_msg_size = 0; >- uint32_t trans_proto_type; >- uint32_t send_buf_section_idx = >- NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX; >+ int ret = 0; > > while (!IFQ_DRV_IS_EMPTY(&sc->hn_ifp->if_snd)) { > IFQ_DRV_DEQUEUE(&sc->hn_ifp->if_snd, m_head); >@@ -460,6 +382,7 @@ > > len = 0; > num_frags = 0; >+ xlen = 0; > > /* Walk the mbuf list computing total length and num frags */ > for (m = m_head; m != NULL; m = m->m_next) { >@@ -478,35 +401,37 @@ > > /* If exceeds # page_buffers in netvsc_packet */ > if (num_frags > NETVSC_PACKET_MAXPAGE) { >- device_printf(dev, "exceed max page buffers,%d,%d\n", >- num_frags, NETVSC_PACKET_MAXPAGE); >- m_freem(m_head); >- if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); >+ m_freem(m); >+ > return (EINVAL); > } > >+ rppi_size = 0; >+ if (m_head->m_flags & M_VLANTAG) { >+ rppi_size = sizeof(rndis_per_packet_info) + >+ sizeof(ndis_8021q_info); >+ } >+ > /* > * Allocate a buffer with space for a netvsc packet plus a > * number of reserved areas. First comes a (currently 16 > * bytes, currently unused) reserved data area. Second is >- * the netvsc_packet. Third is an area reserved for an >- * rndis_filter_packet struct. Fourth (optional) is a >- * rndis_per_packet_info struct. >+ * the netvsc_packet, which includes (currently 4) page >+ * buffers. Third (optional) is a rndis_per_packet_info >+ * struct, but only if a VLAN tag should be inserted into the >+ * Ethernet frame by the Hyper-V infrastructure. Fourth is >+ * an area reserved for an rndis_filter_packet struct. > * Changed malloc to M_NOWAIT to avoid sleep under spin lock. > * No longer reserving extra space for page buffers, as they > * are already part of the netvsc_packet. > */ > buf = malloc(HV_NV_PACKET_OFFSET_IN_BUF + >- sizeof(netvsc_packet) + >- sizeof(rndis_msg) + >- RNDIS_VLAN_PPI_SIZE + >- RNDIS_TSO_PPI_SIZE + >- RNDIS_CSUM_PPI_SIZE, >- M_NETVSC, M_ZERO | M_NOWAIT); >+ sizeof(netvsc_packet) + rppi_size + >+ sizeof(rndis_filter_packet), >+ M_DEVBUF, M_ZERO | M_NOWAIT); > if (buf == NULL) { >- device_printf(dev, "hn:malloc packet failed\n"); >- m_freem(m_head); >- if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); >+ m_freem(m); >+ > return (ENOMEM); > } > >@@ -513,14 +438,6 @@ > packet = (netvsc_packet *)(buf + HV_NV_PACKET_OFFSET_IN_BUF); > *(vm_offset_t *)buf = HV_NV_SC_PTR_OFFSET_IN_BUF; > >- packet->is_data_pkt = TRUE; >- >- /* Set up the rndis header */ >- packet->page_buf_count = num_frags; >- >- /* Initialize it from the mbuf */ >- packet->tot_data_buf_len = len; >- > /* > * extension points to the area reserved for the > * rndis_filter_packet, which is placed just after >@@ -527,176 +444,24 @@ > * the netvsc_packet (and rppi struct, if present; > * length is updated later). > */ >- packet->rndis_mesg = packet + 1; >- rndis_mesg = (rndis_msg *)packet->rndis_mesg; >- rndis_mesg->ndis_msg_type = REMOTE_NDIS_PACKET_MSG; >+ packet->extension = packet + 1; > >- rndis_pkt = &rndis_mesg->msg.packet; >- rndis_pkt->data_offset = sizeof(rndis_packet); >- rndis_pkt->data_length = packet->tot_data_buf_len; >- rndis_pkt->per_pkt_info_offset = sizeof(rndis_packet); >+ /* Set up the rndis header */ >+ packet->page_buf_count = num_frags; > >- rndis_msg_size = RNDIS_MESSAGE_SIZE(rndis_packet); >+ /* Initialize it from the mbuf */ >+ packet->tot_data_buf_len = len; > > /* > * If the Hyper-V infrastructure needs to embed a VLAN tag, > * initialize netvsc_packet and rppi struct values as needed. > */ >- if (m_head->m_flags & M_VLANTAG) { >- /* >- * set up some additional fields so the Hyper-V infrastructure will stuff the VLAN tag >- * into the frame. >- */ >+ if (rppi_size) { >+ /* Lower layers need the VLAN TCI */ > packet->vlan_tci = m_head->m_pkthdr.ether_vtag; >- >- rndis_msg_size += RNDIS_VLAN_PPI_SIZE; >- >- rppi = hv_set_rppi_data(rndis_mesg, RNDIS_VLAN_PPI_SIZE, >- ieee_8021q_info); >- >- /* VLAN info immediately follows rppi struct */ >- rppi_vlan_info = (ndis_8021q_info *)((char*)rppi + >- rppi->per_packet_info_offset); >- /* FreeBSD does not support CFI or priority */ >- rppi_vlan_info->u1.s1.vlan_id = >- packet->vlan_tci & 0xfff; > } > >- if (0 == m_head->m_pkthdr.csum_flags) { >- goto pre_send; >- } >- >- eh = mtod(m_head, struct ether_vlan_header*); >- if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { >- ether_len = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; >- } else { >- ether_len = ETHER_HDR_LEN; >- } >- >- trans_proto_type = get_transport_proto_type(m_head); >- if (TRANSPORT_TYPE_NOT_IP == trans_proto_type) { >- goto pre_send; >- } >- > /* >- * TSO packet needless to setup the send side checksum >- * offload. >- */ >- if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { >- goto do_tso; >- } >- >- /* setup checksum offload */ >- rndis_msg_size += RNDIS_CSUM_PPI_SIZE; >- rppi = hv_set_rppi_data(rndis_mesg, RNDIS_CSUM_PPI_SIZE, >- tcpip_chksum_info); >- csum_info = (rndis_tcp_ip_csum_info *)((char*)rppi + >- rppi->per_packet_info_offset); >- >- if (trans_proto_type & (TYPE_IPV4 << 16)) { >- csum_info->xmit.is_ipv4 = 1; >- } else { >- csum_info->xmit.is_ipv6 = 1; >- } >- >- if (trans_proto_type & TYPE_TCP) { >- csum_info->xmit.tcp_csum = 1; >- csum_info->xmit.tcp_header_offset = 0; >- } else if (trans_proto_type & TYPE_UDP) { >- csum_info->xmit.udp_csum = 1; >- } >- >- goto pre_send; >- >-do_tso: >- /* setup TCP segmentation offload */ >- rndis_msg_size += RNDIS_TSO_PPI_SIZE; >- rppi = hv_set_rppi_data(rndis_mesg, RNDIS_TSO_PPI_SIZE, >- tcp_large_send_info); >- >- tso_info = (rndis_tcp_tso_info *)((char *)rppi + >- rppi->per_packet_info_offset); >- tso_info->lso_v2_xmit.type = >- RNDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE; >- >-#ifdef INET >- if (trans_proto_type & (TYPE_IPV4 << 16)) { >- struct ip *ip = >- (struct ip *)(m_head->m_data + ether_len); >- unsigned long iph_len = ip->ip_hl << 2; >- struct tcphdr *th = >- (struct tcphdr *)((caddr_t)ip + iph_len); >- >- tso_info->lso_v2_xmit.ip_version = >- RNDIS_TCP_LARGE_SEND_OFFLOAD_IPV4; >- ip->ip_len = 0; >- ip->ip_sum = 0; >- >- th->th_sum = in_pseudo(ip->ip_src.s_addr, >- ip->ip_dst.s_addr, >- htons(IPPROTO_TCP)); >- } >-#endif >-#if defined(INET6) && defined(INET) >- else >-#endif >-#ifdef INET6 >- { >- struct ip6_hdr *ip6 = >- (struct ip6_hdr *)(m_head->m_data + ether_len); >- struct tcphdr *th = (struct tcphdr *)(ip6 + 1); >- >- tso_info->lso_v2_xmit.ip_version = >- RNDIS_TCP_LARGE_SEND_OFFLOAD_IPV6; >- ip6->ip6_plen = 0; >- th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); >- } >-#endif >- tso_info->lso_v2_xmit.tcp_header_offset = 0; >- tso_info->lso_v2_xmit.mss = m_head->m_pkthdr.tso_segsz; >- >-pre_send: >- rndis_mesg->msg_len = packet->tot_data_buf_len + rndis_msg_size; >- packet->tot_data_buf_len = rndis_mesg->msg_len; >- >- /* send packet with send buffer */ >- if (packet->tot_data_buf_len < net_dev->send_section_size) { >- send_buf_section_idx = >- hv_nv_get_next_send_section(net_dev); >- if (send_buf_section_idx != >- NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX) { >- char *dest = ((char *)net_dev->send_buf + >- send_buf_section_idx * >- net_dev->send_section_size); >- >- memcpy(dest, rndis_mesg, rndis_msg_size); >- dest += rndis_msg_size; >- for (m = m_head; m != NULL; m = m->m_next) { >- if (m->m_len) { >- memcpy(dest, >- (void *)mtod(m, vm_offset_t), >- m->m_len); >- dest += m->m_len; >- } >- } >- >- packet->send_buf_section_idx = >- send_buf_section_idx; >- packet->send_buf_section_size = >- packet->tot_data_buf_len; >- packet->page_buf_count = 0; >- goto do_send; >- } >- } >- >- /* send packet with page buffer */ >- packet->page_buffers[0].pfn = >- atop(hv_get_phys_addr(rndis_mesg)); >- packet->page_buffers[0].offset = >- (unsigned long)rndis_mesg & PAGE_MASK; >- packet->page_buffers[0].length = rndis_msg_size; >- >- /* > * Fill the page buffers with mbuf info starting at index > * HV_RF_NUM_TX_RESERVED_PAGE_BUFS. > */ >@@ -714,12 +479,6 @@ > } > } > >- packet->send_buf_section_idx = >- NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX; >- packet->send_buf_section_size = 0; >- >-do_send: >- > /* > * If bpf, copy the mbuf chain. This is less expensive than > * it appears; the mbuf clusters are not copied, only their >@@ -738,7 +497,8 @@ > packet->compl.send.send_completion_tid = (uint64_t)(uintptr_t)m_head; > > /* Removed critical_enter(), does not appear necessary */ >- ret = hv_nv_on_send(device_ctx, packet); >+ ret = hv_rf_on_send(device_ctx, packet); >+ > if (ret == 0) { > ifp->if_opackets++; > /* if bpf && mc_head, call bpf_mtap code */ >@@ -766,7 +526,6 @@ > * send completion > */ > netvsc_xmit_completion(packet); >- if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); > } > > /* if bpf && mc_head, free the mbuf chain copy */ >@@ -862,14 +621,13 @@ > * Note: This is no longer used as a callback > */ > int >-netvsc_recv(struct hv_device *device_ctx, netvsc_packet *packet, >- rndis_tcp_ip_csum_info *csum_info) >+netvsc_recv(struct hv_device *device_ctx, netvsc_packet *packet) > { > hn_softc_t *sc = (hn_softc_t *)device_get_softc(device_ctx->device); > struct mbuf *m_new; > struct ifnet *ifp; >- device_t dev = device_ctx->device; > int size; >+ int i; > > if (sc == NULL) { > return (0); /* TODO: KYS how can this be! */ >@@ -905,35 +663,36 @@ > > m_new = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, size); > >- if (m_new == NULL) { >- device_printf(dev, "alloc mbuf failed.\n"); >+ if (m_new == NULL) > return (0); >- } > >- hv_m_append(m_new, packet->tot_data_buf_len, >- packet->data); >+ /* >+ * Remove trailing junk from RX data buffer. >+ * Fixme: This will not work for multiple Hyper-V RX buffers. >+ * Fortunately, the channel gathers all RX data into one buffer. >+ * >+ * L2 frame length, with L2 header, not including CRC >+ */ >+ packet->page_buffers[0].length = packet->tot_data_buf_len; > >- m_new->m_pkthdr.rcvif = ifp; >+ /* >+ * Copy the received packet to one or more mbufs. >+ * The copy is required since the memory pointed to by netvsc_packet >+ * cannot be deallocated >+ */ >+ for (i=0; i < packet->page_buf_count; i++) { >+ /* Shift virtual page number to form virtual page address */ >+ uint8_t *vaddr = (uint8_t *)(uintptr_t) >+ (packet->page_buffers[i].pfn << PAGE_SHIFT); > >- /* receive side checksum offload */ >- m_new->m_pkthdr.csum_flags = 0; >- if (NULL != csum_info) { >- /* IP csum offload */ >- if (csum_info->receive.ip_csum_succeeded) { >- m_new->m_pkthdr.csum_flags |= >- (CSUM_IP_CHECKED | CSUM_IP_VALID); >- } >- >- /* TCP csum offload */ >- if (csum_info->receive.tcp_csum_succeeded) { >- m_new->m_pkthdr.csum_flags |= >- (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); >- m_new->m_pkthdr.csum_data = 0xffff; >- } >+ hv_m_append(m_new, packet->page_buffers[i].length, >+ vaddr + packet->page_buffers[i].offset); > } > >+ m_new->m_pkthdr.rcvif = ifp; >+ > if ((packet->vlan_tci != 0) && >- (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) { >+ (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) { > m_new->m_pkthdr.ether_vtag = packet->vlan_tci; > m_new->m_flags |= M_VLANTAG; > } >@@ -971,9 +730,6 @@ > { > hn_softc_t *sc = ifp->if_softc; > struct ifreq *ifr = (struct ifreq *)data; >-#ifdef INET >- struct ifaddr *ifa = (struct ifaddr *)data; >-#endif > netvsc_device_info device_info; > struct hv_device *hn_dev; > int mask, error = 0; >@@ -1104,34 +860,13 @@ > break; > case SIOCSIFCAP: > mask = ifr->ifr_reqcap ^ ifp->if_capenable; >- if (mask & IFCAP_TXCSUM) { >- if (IFCAP_TXCSUM & ifp->if_capenable) { >- ifp->if_capenable &= ~IFCAP_TXCSUM; >- ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP); >+ if (mask & IFCAP_HWCSUM) { >+ if (IFCAP_HWCSUM & ifp->if_capenable) { >+ ifp->if_capenable &= ~IFCAP_HWCSUM; > } else { >- ifp->if_capenable |= IFCAP_TXCSUM; >- ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); >+ ifp->if_capenable |= IFCAP_HWCSUM; > } > } >- >- if (mask & IFCAP_RXCSUM) { >- if (IFCAP_RXCSUM & ifp->if_capenable) { >- ifp->if_capenable &= ~IFCAP_RXCSUM; >- } else { >- ifp->if_capenable |= IFCAP_RXCSUM; >- } >- } >- >- if (mask & IFCAP_TSO4) { >- ifp->if_capenable ^= IFCAP_TSO4; >- ifp->if_hwassist ^= CSUM_IP_TSO; >- } >- >- if (mask & IFCAP_TSO6) { >- ifp->if_capenable ^= IFCAP_TSO6; >- ifp->if_hwassist ^= CSUM_IP6_TSO; >- } >- > error = 0; > break; > case SIOCADDMULTI: >Index: sys/dev/hyperv/netvsc/hv_rndis_filter.h >=================================================================== >--- sys/dev/hyperv/netvsc/hv_rndis_filter.h (revision 285236) >+++ sys/dev/hyperv/netvsc/hv_rndis_filter.h (revision 285224) >@@ -24,8 +24,6 @@ > * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF > * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >- * >- * $FreeBSD$ > */ > > #ifndef __HV_RNDIS_FILTER_H__ >@@ -92,16 +90,27 @@ > uint8_t hw_mac_addr[HW_MACADDR_LEN]; > } rndis_device; > >+typedef struct rndis_filter_packet_ { >+ void *completion_context; >+ /* No longer used */ >+ pfn_on_send_rx_completion on_completion; >+ >+ rndis_msg message; >+} rndis_filter_packet; >+ >+ > /* > * Externs > */ > >-int hv_rf_on_receive(netvsc_dev *net_dev, >- struct hv_device *device, netvsc_packet *pkt); >-int hv_rf_on_device_add(struct hv_device *device, void *additl_info); >-int hv_rf_on_device_remove(struct hv_device *device, boolean_t destroy_channel); >-int hv_rf_on_open(struct hv_device *device); >-int hv_rf_on_close(struct hv_device *device); >+extern int hv_rf_on_receive(struct hv_device *device, netvsc_packet *pkt); >+extern int hv_rf_on_device_add(struct hv_device *device, void *additl_info); >+extern int hv_rf_on_device_remove(struct hv_device *device, >+ boolean_t destroy_channel); >+extern int hv_rf_on_open(struct hv_device *device); >+extern int hv_rf_on_close(struct hv_device *device); >+extern int hv_rf_on_send(struct hv_device *device, netvsc_packet *pkt); > >+ > #endif /* __HV_RNDIS_FILTER_H__ */ > >Index: sys/dev/hyperv/include/hyperv.h >=================================================================== >--- sys/dev/hyperv/include/hyperv.h (revision 285236) >+++ sys/dev/hyperv/include/hyperv.h (revision 285224) >@@ -107,7 +107,7 @@ > #define HV_MAX_PIPE_USER_DEFINED_BYTES 116 > > >-#define HV_MAX_PAGE_BUFFER_COUNT 32 >+#define HV_MAX_PAGE_BUFFER_COUNT 16 > #define HV_MAX_MULTIPAGE_BUFFER_COUNT 32 > > #define HV_ALIGN_UP(value, align) \ >Index: . >=================================================================== >--- . (revision 285236) >+++ . (revision 285224) > >Property changes on: . >___________________________________________________________________ >Modified: svn:mergeinfo > Reverse-merged /head:r284746,284889
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 203630
:
162011
|
162111
|
162763