dpdk版本:dpdk-stable-16.11.1
程序路径:example/vhost
启用dpdk的LRO
static struct rte_eth_conf default_port_conf = {
.rxmode = {
.mq_mode = ETH_MQ_RX_RSS,
.max_rx_pkt_len = ETHER_MAX_LEN,
.split_hdr_size = 0, /**< hdr buf size */
.header_split = 0, /**< Header Split disabled */
.hw_ip_checksum = 0, /**< IP checksum offload enabled */
.hw_vlan_filter = 0, /**< VLAN filtering disabled */
.hw_vlan_strip = 0, /**< VLAN strip disabled. */
.hw_vlan_extend = 0, /**< Extended VLAN disabled. */
.jumbo_frame = 0, /**< Jumbo Frame Support disabled */
.hw_strip_crc = 1, /**< CRC stripped by hardware 这个也得打开*/
.enable_lro = 1, /*打开LRO功能*/
},
.rx_adv_conf = {
.rss_conf = {
.rss_key = default_rsskey_40bytes,
.rss_key_len = 40,
.rss_hf = ETH_RSS_PROTO_MASK,
},
},
.txmode = {
.mq_mode = ETH_MQ_TX_NONE,
},
};
rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
通过上面代码,dpdk就使能了LRO功能
mbuf的默认长度是2048,当网卡收到大于2048的数据包时,会把数据包存入多个mbuf中,通过mbuf->next关联
但现在的dpdk代码虽然把数据包合并了,却没有计算合并后的数据包校验和,导致在vm中的数据直接丢掉。
vhost接口:
在virtio_enqueue_offload函数中设置VIRTIO_NET_HDR_F_DATA_VALID,可以使上层不检查数据包的校验和。
static void
virtio_enqueue_offload(struct rte_mbuf *m_buf, struct virtio_net_hdr *net_hdr)
{
uint64_t csum_l4 = m_buf->ol_flags & PKT_TX_L4_MASK;
ffload
if (m_buf->ol_flags & PKT_TX_TCP_SEG)
csum_l4 |= PKT_TX_TCP_CKSUM;
net_hdr->flags = VIRTIO_NET_HDR_F_DATA_VALID;
#if 0
if (csum_l4) {
net_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
net_hdr->csum_start = m_buf->l2_len + m_buf->l3_len;
switch (csum_l4) {
case PKT_TX_TCP_CKSUM:
net_hdr->csum_offset = (offsetof(struct tcp_hdr,
cksum));
break;
case PKT_TX_UDP_CKSUM:
net_hdr->csum_offset = (offsetof(struct udp_hdr,
dgram_cksum));
break;
case PKT_TX_SCTP_CKSUM:
net_hdr->csum_offset = (offsetof(struct sctp_hdr,
cksum));
。。。。
}
OVS中:
在netdev_dpdk_filter_packet_len函数里会检查数据包的长度,超过max_packet_len的数据都会被丢弃
static int
netdev_dpdk_filter_packet_len(struct netdev_dpdk *dev, struct rte_mbuf **pkts,
int pkt_cnt)
{
int i = 0;
int cnt = 0;
struct rte_mbuf *pkt;
for (i = 0; i < pkt_cnt; i++) {
pkt = pkts[i];
if (OVS_UNLIKELY(pkt->pkt_len > dev->max_packet_len)) {
VLOG_WARN_RL(&rl, "%s: Too big size %" PRIu32 " max_packet_len %d",
dev->up.name, pkt->pkt_len, dev->max_packet_len);
rte_pktmbuf_free(pkt);
continue;
pkt->data_len = 2044;
}
if (OVS_UNLIKELY(i != cnt)) {
pkts[cnt] = pkt;
}
cnt++;
}
return cnt;
}