Skip to content

Commit c8e4eff

Browse files
haiyangzdavem330
authored andcommitted
hv_netvsc: Add support for LRO/RSC in the vSwitch
LRO/RSC in the vSwitch is a feature available in Windows Server 2019 hosts and later. It reduces the per packet processing overhead by coalescing multiple TCP segments when possible. This patch adds netvsc driver support for this feature. Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent bd4d08d commit c8e4eff

File tree

4 files changed

+145
-38
lines changed

4 files changed

+145
-38
lines changed

drivers/net/hyperv/hyperv_net.h

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ struct rndis_device {
186186
/* Interface */
187187
struct rndis_message;
188188
struct netvsc_device;
189+
struct netvsc_channel;
189190
struct net_device_context;
190191

191192
extern u32 netvsc_ring_bytes;
@@ -203,10 +204,7 @@ void netvsc_linkstatus_callback(struct net_device *net,
203204
struct rndis_message *resp);
204205
int netvsc_recv_callback(struct net_device *net,
205206
struct netvsc_device *nvdev,
206-
struct vmbus_channel *channel,
207-
void *data, u32 len,
208-
const struct ndis_tcp_ip_checksum_info *csum_info,
209-
const struct ndis_pkt_8021q_info *vlan);
207+
struct netvsc_channel *nvchan);
210208
void netvsc_channel_cb(void *context);
211209
int netvsc_poll(struct napi_struct *napi, int budget);
212210

@@ -222,7 +220,7 @@ int rndis_filter_set_rss_param(struct rndis_device *rdev,
222220
const u8 *key);
223221
int rndis_filter_receive(struct net_device *ndev,
224222
struct netvsc_device *net_dev,
225-
struct vmbus_channel *channel,
223+
struct netvsc_channel *nvchan,
226224
void *data, u32 buflen);
227225

228226
int rndis_filter_set_device_mac(struct netvsc_device *ndev,
@@ -524,6 +522,8 @@ struct nvsp_2_vsc_capability {
524522
u64 ieee8021q:1;
525523
u64 correlation_id:1;
526524
u64 teaming:1;
525+
u64 vsubnetid:1;
526+
u64 rsc:1;
527527
};
528528
};
529529
} __packed;
@@ -826,7 +826,7 @@ struct nvsp_message {
826826

827827
#define NETVSC_SUPPORTED_HW_FEATURES (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | \
828828
NETIF_F_TSO | NETIF_F_IPV6_CSUM | \
829-
NETIF_F_TSO6)
829+
NETIF_F_TSO6 | NETIF_F_LRO)
830830

831831
#define VRSS_SEND_TAB_SIZE 16 /* must be power of 2 */
832832
#define VRSS_CHANNEL_MAX 64
@@ -852,6 +852,18 @@ struct multi_recv_comp {
852852
u32 next; /* next entry for writing */
853853
};
854854

855+
#define NVSP_RSC_MAX 562 /* Max #RSC frags in a vmbus xfer page pkt */
856+
857+
struct nvsc_rsc {
858+
const struct ndis_pkt_8021q_info *vlan;
859+
const struct ndis_tcp_ip_checksum_info *csum_info;
860+
u8 is_last; /* last RNDIS msg in a vmtransfer_page */
861+
u32 cnt; /* #fragments in an RSC packet */
862+
u32 pktlen; /* Full packet length */
863+
void *data[NVSP_RSC_MAX];
864+
u32 len[NVSP_RSC_MAX];
865+
};
866+
855867
struct netvsc_stats {
856868
u64 packets;
857869
u64 bytes;
@@ -955,6 +967,7 @@ struct netvsc_channel {
955967
struct multi_send_data msd;
956968
struct multi_recv_comp mrc;
957969
atomic_t queue_sends;
970+
struct nvsc_rsc rsc;
958971

959972
struct netvsc_stats tx_stats;
960973
struct netvsc_stats rx_stats;
@@ -1136,7 +1149,8 @@ struct rndis_oobd {
11361149
/* Packet extension field contents associated with a Data message. */
11371150
struct rndis_per_packet_info {
11381151
u32 size;
1139-
u32 type;
1152+
u32 type:31;
1153+
u32 internal:1;
11401154
u32 ppi_offset;
11411155
};
11421156

@@ -1157,6 +1171,25 @@ enum ndis_per_pkt_info_type {
11571171
MAX_PER_PKT_INFO
11581172
};
11591173

1174+
enum rndis_per_pkt_info_interal_type {
1175+
RNDIS_PKTINFO_ID = 1,
1176+
/* Add more memebers here */
1177+
1178+
RNDIS_PKTINFO_MAX
1179+
};
1180+
1181+
#define RNDIS_PKTINFO_SUBALLOC BIT(0)
1182+
#define RNDIS_PKTINFO_1ST_FRAG BIT(1)
1183+
#define RNDIS_PKTINFO_LAST_FRAG BIT(2)
1184+
1185+
#define RNDIS_PKTINFO_ID_V1 1
1186+
1187+
struct rndis_pktinfo_id {
1188+
u8 ver;
1189+
u8 flag;
1190+
u16 pkt_id;
1191+
};
1192+
11601193
struct ndis_pkt_8021q_info {
11611194
union {
11621195
struct {

drivers/net/hyperv/netvsc.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,9 @@ static int negotiate_nvsp_ver(struct hv_device *device,
542542
init_packet->msg.v2_msg.send_ndis_config.capability.teaming = 1;
543543
}
544544

545+
if (nvsp_ver >= NVSP_PROTOCOL_VERSION_61)
546+
init_packet->msg.v2_msg.send_ndis_config.capability.rsc = 1;
547+
545548
trace_nvsp_send(ndev, init_packet);
546549

547550
ret = vmbus_sendpacket(device->channel, init_packet,
@@ -1111,11 +1114,12 @@ static void enq_receive_complete(struct net_device *ndev,
11111114

11121115
static int netvsc_receive(struct net_device *ndev,
11131116
struct netvsc_device *net_device,
1114-
struct vmbus_channel *channel,
1117+
struct netvsc_channel *nvchan,
11151118
const struct vmpacket_descriptor *desc,
11161119
const struct nvsp_message *nvsp)
11171120
{
11181121
struct net_device_context *net_device_ctx = netdev_priv(ndev);
1122+
struct vmbus_channel *channel = nvchan->channel;
11191123
const struct vmtransfer_page_packet_header *vmxferpage_packet
11201124
= container_of(desc, const struct vmtransfer_page_packet_header, d);
11211125
u16 q_idx = channel->offermsg.offer.sub_channel_index;
@@ -1150,6 +1154,7 @@ static int netvsc_receive(struct net_device *ndev,
11501154
int ret;
11511155

11521156
if (unlikely(offset + buflen > net_device->recv_buf_size)) {
1157+
nvchan->rsc.cnt = 0;
11531158
status = NVSP_STAT_FAIL;
11541159
netif_err(net_device_ctx, rx_err, ndev,
11551160
"Packet offset:%u + len:%u too big\n",
@@ -1160,11 +1165,13 @@ static int netvsc_receive(struct net_device *ndev,
11601165

11611166
data = recv_buf + offset;
11621167

1168+
nvchan->rsc.is_last = (i == count - 1);
1169+
11631170
trace_rndis_recv(ndev, q_idx, data);
11641171

11651172
/* Pass it to the upper layer */
11661173
ret = rndis_filter_receive(ndev, net_device,
1167-
channel, data, buflen);
1174+
nvchan, data, buflen);
11681175

11691176
if (unlikely(ret != NVSP_STAT_SUCCESS))
11701177
status = NVSP_STAT_FAIL;
@@ -1223,12 +1230,13 @@ static void netvsc_receive_inband(struct net_device *ndev,
12231230
}
12241231

12251232
static int netvsc_process_raw_pkt(struct hv_device *device,
1226-
struct vmbus_channel *channel,
1233+
struct netvsc_channel *nvchan,
12271234
struct netvsc_device *net_device,
12281235
struct net_device *ndev,
12291236
const struct vmpacket_descriptor *desc,
12301237
int budget)
12311238
{
1239+
struct vmbus_channel *channel = nvchan->channel;
12321240
const struct nvsp_message *nvmsg = hv_pkt_data(desc);
12331241

12341242
trace_nvsp_recv(ndev, channel, nvmsg);
@@ -1240,7 +1248,7 @@ static int netvsc_process_raw_pkt(struct hv_device *device,
12401248
break;
12411249

12421250
case VM_PKT_DATA_USING_XFER_PAGES:
1243-
return netvsc_receive(ndev, net_device, channel,
1251+
return netvsc_receive(ndev, net_device, nvchan,
12441252
desc, nvmsg);
12451253
break;
12461254

@@ -1284,7 +1292,7 @@ int netvsc_poll(struct napi_struct *napi, int budget)
12841292
nvchan->desc = hv_pkt_iter_first(channel);
12851293

12861294
while (nvchan->desc && work_done < budget) {
1287-
work_done += netvsc_process_raw_pkt(device, channel, net_device,
1295+
work_done += netvsc_process_raw_pkt(device, nvchan, net_device,
12881296
ndev, nvchan->desc, budget);
12891297
nvchan->desc = hv_pkt_iter_next(channel, nvchan->desc);
12901298
}

drivers/net/hyperv/netvsc_drv.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -744,22 +744,25 @@ void netvsc_linkstatus_callback(struct net_device *net,
744744
}
745745

746746
static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net,
747-
struct napi_struct *napi,
748-
const struct ndis_tcp_ip_checksum_info *csum_info,
749-
const struct ndis_pkt_8021q_info *vlan,
750-
void *data, u32 buflen)
747+
struct netvsc_channel *nvchan)
751748
{
749+
struct napi_struct *napi = &nvchan->napi;
750+
const struct ndis_pkt_8021q_info *vlan = nvchan->rsc.vlan;
751+
const struct ndis_tcp_ip_checksum_info *csum_info =
752+
nvchan->rsc.csum_info;
752753
struct sk_buff *skb;
754+
int i;
753755

754-
skb = napi_alloc_skb(napi, buflen);
756+
skb = napi_alloc_skb(napi, nvchan->rsc.pktlen);
755757
if (!skb)
756758
return skb;
757759

758760
/*
759761
* Copy to skb. This copy is needed here since the memory pointed by
760762
* hv_netvsc_packet cannot be deallocated
761763
*/
762-
skb_put_data(skb, data, buflen);
764+
for (i = 0; i < nvchan->rsc.cnt; i++)
765+
skb_put_data(skb, nvchan->rsc.data[i], nvchan->rsc.len[i]);
763766

764767
skb->protocol = eth_type_trans(skb, net);
765768

@@ -792,23 +795,20 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net,
792795
*/
793796
int netvsc_recv_callback(struct net_device *net,
794797
struct netvsc_device *net_device,
795-
struct vmbus_channel *channel,
796-
void *data, u32 len,
797-
const struct ndis_tcp_ip_checksum_info *csum_info,
798-
const struct ndis_pkt_8021q_info *vlan)
798+
struct netvsc_channel *nvchan)
799799
{
800800
struct net_device_context *net_device_ctx = netdev_priv(net);
801+
struct vmbus_channel *channel = nvchan->channel;
801802
u16 q_idx = channel->offermsg.offer.sub_channel_index;
802-
struct netvsc_channel *nvchan = &net_device->chan_table[q_idx];
803803
struct sk_buff *skb;
804804
struct netvsc_stats *rx_stats;
805805

806806
if (net->reg_state != NETREG_REGISTERED)
807807
return NVSP_STAT_FAIL;
808808

809809
/* Allocate a skb - TODO direct I/O to pages? */
810-
skb = netvsc_alloc_recv_skb(net, &nvchan->napi,
811-
csum_info, vlan, data, len);
810+
skb = netvsc_alloc_recv_skb(net, nvchan);
811+
812812
if (unlikely(!skb)) {
813813
++net_device_ctx->eth_stats.rx_no_memory;
814814
rcu_read_unlock();
@@ -825,7 +825,7 @@ int netvsc_recv_callback(struct net_device *net,
825825
rx_stats = &nvchan->rx_stats;
826826
u64_stats_update_begin(&rx_stats->syncp);
827827
rx_stats->packets++;
828-
rx_stats->bytes += len;
828+
rx_stats->bytes += nvchan->rsc.pktlen;
829829

830830
if (skb->pkt_type == PACKET_BROADCAST)
831831
++rx_stats->broadcast;

0 commit comments

Comments
 (0)