It looks like one of the test files fell out of this patch, I'll re-submit with that corrected.
-M On Wed, Jul 13, 2022 at 2:14 PM Mike Pattrick <[email protected]> wrote: > > From: Flavio Leitner <[email protected]> > > The netdev receiving packets is supposed to provide the flags > indicating if the IP csum was verified and it is GOOD or BAD, > otherwise the stack will check when appropriate by software. > > If the packet comes with good checksum, then postpone the > checksum calculation to the egress device if needed. > > When encapsulate a packet with that flag, set the checksum > of the inner IP header since that is not yet supported. > > Calculate the IP csum when the packet is going to be sent over > a device that doesn't support the feature. > > Linux devices don't support IP csum offload alone, so the > support is not enabled. > > Signed-off-by: Flavio Leitner <[email protected]> > Co-authored-by: Mike Pattrick <[email protected]> > Signed-off-by: Mike Pattrick <[email protected]> > > --- > v5: > - Refactor was mostly removed, except for valid->good > - Reset unsupported offload flags in send_prepare > - Moved send_prepare from process_upcall to netdev_upcall > --- > lib/conntrack.c | 17 +++---- > lib/dp-packet.c | 15 +++++++ > lib/dp-packet.h | 60 +++++++++++++++++++++++-- > lib/dpif-netdev.c | 4 ++ > lib/flow.c | 15 +++++-- > lib/ipf.c | 11 +++-- > lib/netdev-dpdk.c | 70 ++++++++++++++++------------- > lib/netdev-dummy.c | 23 ++++++++++ > lib/netdev-native-tnl.c | 21 ++++++--- > lib/netdev.c | 22 +++++++++ > lib/odp-execute.c | 21 ++++++--- > lib/packets.c | 34 +++++++++++--- > ofproto/ofproto-dpif-upcall.c | 2 +- > tests/automake.mk | 1 + > tests/system-userspace-testsuite.at | 1 + > 15 files changed, 249 insertions(+), 68 deletions(-) > > diff --git a/lib/conntrack.c b/lib/conntrack.c > index faa2d6ab7..d5793856d 100644 > --- a/lib/conntrack.c > +++ b/lib/conntrack.c > @@ -2089,16 +2089,15 @@ conn_key_extract(struct conntrack *ct, struct > dp_packet *pkt, ovs_be16 dl_type, > ctx->key.dl_type = dl_type; > > if (ctx->key.dl_type == htons(ETH_TYPE_IP)) { > - bool hwol_bad_l3_csum = dp_packet_ip_checksum_bad(pkt); > - if (hwol_bad_l3_csum) { > + if (dp_packet_ip_checksum_bad(pkt)) { > ok = false; > COVERAGE_INC(conntrack_l3csum_err); > } else { > - bool hwol_good_l3_csum = dp_packet_ip_checksum_valid(pkt) > - || dp_packet_hwol_is_ipv4(pkt); > - /* Validate the checksum only when hwol is not supported. */ > + /* Validate the checksum only when hwol is not supported and the > + * packets checksum status is not known. */ > ok = extract_l3_ipv4(&ctx->key, l3, dp_packet_l3_size(pkt), NULL, > - !hwol_good_l3_csum); > + !dp_packet_hwol_is_ipv4(pkt) && > + !dp_packet_ip_checksum_good(pkt)); > } > } else if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) { > ok = extract_l3_ipv6(&ctx->key, l3, dp_packet_l3_size(pkt), NULL); > @@ -2109,7 +2108,7 @@ conn_key_extract(struct conntrack *ct, struct dp_packet > *pkt, ovs_be16 dl_type, > if (ok) { > bool hwol_bad_l4_csum = dp_packet_l4_checksum_bad(pkt); > if (!hwol_bad_l4_csum) { > - bool hwol_good_l4_csum = dp_packet_l4_checksum_valid(pkt) > + bool hwol_good_l4_csum = dp_packet_l4_checksum_good(pkt) > || dp_packet_hwol_tx_l4_checksum(pkt); > /* Validate the checksum only when hwol is not supported. */ > if (extract_l4(&ctx->key, l4, dp_packet_l4_size(pkt), > @@ -3402,7 +3401,9 @@ handle_ftp_ctl(struct conntrack *ct, const struct > conn_lookup_ctx *ctx, > } > if (seq_skew) { > ip_len = ntohs(l3_hdr->ip_tot_len) + seq_skew; > - if (!dp_packet_hwol_is_ipv4(pkt)) { > + if (dp_packet_hwol_tx_ip_csum(pkt)) { > + dp_packet_ol_reset_ip_csum_good(pkt); > + } else { > l3_hdr->ip_csum = recalc_csum16(l3_hdr->ip_csum, > l3_hdr->ip_tot_len, > htons(ip_len)); > diff --git a/lib/dp-packet.c b/lib/dp-packet.c > index 35c72542a..7771d0d62 100644 > --- a/lib/dp-packet.c > +++ b/lib/dp-packet.c > @@ -21,6 +21,7 @@ > #include "dp-packet.h" > #include "netdev-afxdp.h" > #include "netdev-dpdk.h" > +#include "netdev-provider.h" > #include "openvswitch/dynamic-string.h" > #include "util.h" > > @@ -506,3 +507,17 @@ dp_packet_resize_l2(struct dp_packet *b, int increment) > dp_packet_adjust_layer_offset(&b->l2_5_ofs, increment); > return dp_packet_data(b); > } > + > +/* Checks if the packet 'p' is compatible with netdev_ol_flags 'flags' > + * and if not, update the packet with the software fall back. */ > +void > +dp_packet_ol_send_prepare(struct dp_packet *p, const uint64_t flags) > +{ > + if (!(flags & NETDEV_TX_OFFLOAD_IPV4_CKSUM)) { > + if (!dp_packet_ip_checksum_good(p) && dp_packet_hwol_tx_ip_csum(p)) { > + dp_packet_ip_set_header_csum(p); > + dp_packet_ol_set_ip_csum_good(p); > + } > + dp_packet_hwol_reset_tx_ip_csum(p); > + } > +} > diff --git a/lib/dp-packet.h b/lib/dp-packet.h > index eea5a9215..48f5e82a7 100644 > --- a/lib/dp-packet.h > +++ b/lib/dp-packet.h > @@ -25,6 +25,7 @@ > #include <rte_mbuf.h> > #endif > > +#include "csum.h" > #include "netdev-afxdp.h" > #include "netdev-dpdk.h" > #include "openvswitch/list.h" > @@ -83,6 +84,8 @@ enum dp_packet_offload_mask { > DEF_OL_FLAG(DP_PACKET_OL_TX_UDP_CKSUM, RTE_MBUF_F_TX_UDP_CKSUM, 0x400), > /* Offload SCTP checksum. */ > DEF_OL_FLAG(DP_PACKET_OL_TX_SCTP_CKSUM, RTE_MBUF_F_TX_SCTP_CKSUM, 0x800), > + /* Offload IP checksum. */ > + DEF_OL_FLAG(DP_PACKET_OL_TX_IP_CKSUM, RTE_MBUF_F_TX_IP_CKSUM, 0x1000), > /* Adding new field requires adding to DP_PACKET_OL_SUPPORTED_MASK. */ > }; > > @@ -97,7 +100,8 @@ enum dp_packet_offload_mask { > DP_PACKET_OL_TX_IPV6 | \ > DP_PACKET_OL_TX_TCP_CKSUM | \ > DP_PACKET_OL_TX_UDP_CKSUM | \ > - DP_PACKET_OL_TX_SCTP_CKSUM) > + DP_PACKET_OL_TX_SCTP_CKSUM | \ > + DP_PACKET_OL_TX_IP_CKSUM) > > #define DP_PACKET_OL_TX_L4_MASK (DP_PACKET_OL_TX_TCP_CKSUM | \ > DP_PACKET_OL_TX_UDP_CKSUM | \ > @@ -235,6 +239,7 @@ void *dp_packet_steal_data(struct dp_packet *); > > static inline bool dp_packet_equal(const struct dp_packet *, > const struct dp_packet *); > +void dp_packet_ol_send_prepare(struct dp_packet *, const uint64_t); > > > /* Frees memory that 'b' points to, as well as 'b' itself. */ > @@ -1024,6 +1029,26 @@ dp_packet_hwol_set_tx_ipv6(struct dp_packet *b) > *dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_IPV6; > } > > +/* Returns 'true' if packet 'p' is marked for IPv4 checksum offloading. */ > +static inline bool > +dp_packet_hwol_tx_ip_csum(const struct dp_packet *p) > +{ > + return !!(*dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_TX_IP_CKSUM); > +} > + > +/* Marks packet 'p' for IPv4 checksum offloading. */ > +static inline void > +dp_packet_hwol_set_tx_ip_csum(struct dp_packet *p) > +{ > + *dp_packet_ol_flags_ptr(p) |= DP_PACKET_OL_TX_IP_CKSUM; > +} > + > +static inline void > +dp_packet_hwol_reset_tx_ip_csum(struct dp_packet *p) > +{ > + *dp_packet_ol_flags_ptr(p) &= ~DP_PACKET_OL_TX_IP_CKSUM; > +} > + > /* Mark packet 'b' for TCP checksum offloading. It implies that either > * the packet 'b' is marked for IPv4 or IPv6 checksum offloading. */ > static inline void > @@ -1057,13 +1082,31 @@ dp_packet_hwol_set_tcp_seg(struct dp_packet *b) > *dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_TCP_SEG; > } > > +/* Returns 'true' is the IP has good integrity and the > + * checksum in it is complete. */ > static inline bool > -dp_packet_ip_checksum_valid(const struct dp_packet *p) > +dp_packet_ip_checksum_good(const struct dp_packet *p) > { > return (*dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_RX_IP_CKSUM_MASK) == > DP_PACKET_OL_RX_IP_CKSUM_GOOD; > } > > +/* Marks packet 'p' with good IPv4 checksum. */ > +static inline void > +dp_packet_ol_set_ip_csum_good(const struct dp_packet *p) > +{ > + *dp_packet_ol_flags_ptr(p) &= ~DP_PACKET_OL_RX_IP_CKSUM_BAD; > + *dp_packet_ol_flags_ptr(p) |= DP_PACKET_OL_RX_IP_CKSUM_GOOD; > +} > + > +/* Resets IP good checksum flag in packet 'p'. */ > +static inline void > +dp_packet_ol_reset_ip_csum_good(const struct dp_packet *p) > +{ > + *dp_packet_ol_flags_ptr(p) &= ~DP_PACKET_OL_RX_IP_CKSUM_GOOD; > +} > + > +/* Marks packet 'p' with bad IPv4 checksum. */ > static inline bool > dp_packet_ip_checksum_bad(const struct dp_packet *p) > { > @@ -1071,8 +1114,19 @@ dp_packet_ip_checksum_bad(const struct dp_packet *p) > DP_PACKET_OL_RX_IP_CKSUM_BAD; > } > > +/* Calculate and set the IPv4 header checksum in packet 'p'. */ > +static inline void > +dp_packet_ip_set_header_csum(struct dp_packet *p) > +{ > + struct ip_header *ip = dp_packet_l3(p); > + > + ovs_assert(ip); > + ip->ip_csum = 0; > + ip->ip_csum = csum(ip, sizeof *ip); > +} > + > static inline bool > -dp_packet_l4_checksum_valid(const struct dp_packet *p) > +dp_packet_l4_checksum_good(const struct dp_packet *p) > { > return (*dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_RX_L4_CKSUM_MASK) == > DP_PACKET_OL_RX_L4_CKSUM_GOOD; > diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c > index 018052d08..20652cdca 100644 > --- a/lib/dpif-netdev.c > +++ b/lib/dpif-netdev.c > @@ -7868,6 +7868,10 @@ dp_netdev_upcall(struct dp_netdev_pmd_thread *pmd, > struct dp_packet *packet_, > ds_destroy(&ds); > } > > + /* The packet is going to be encapsulated and sent to > + * the controller. */ > + dp_packet_ol_send_prepare(packet_, 0); > + > return dp->upcall_cb(packet_, flow, ufid, pmd->core_id, type, userdata, > actions, wc, put_actions, dp->upcall_aux); > } > diff --git a/lib/flow.c b/lib/flow.c > index b1e1fb34d..0ac274dc3 100644 > --- a/lib/flow.c > +++ b/lib/flow.c > @@ -907,6 +907,10 @@ miniflow_extract(struct dp_packet *packet, struct > miniflow *dst) > nw_proto = nh->ip_proto; > nw_frag = ipv4_get_nw_frag(nh); > data_pull(&data, &size, ip_len); > + dp_packet_hwol_set_tx_ipv4(packet); > + if (dp_packet_ip_checksum_good(packet)) { > + dp_packet_hwol_set_tx_ip_csum(packet); > + } > } else if (dl_type == htons(ETH_TYPE_IPV6)) { > const struct ovs_16aligned_ip6_hdr *nh = data; > ovs_be32 tc_flow; > @@ -920,6 +924,7 @@ miniflow_extract(struct dp_packet *packet, struct > miniflow *dst) > } > data_pull(&data, &size, sizeof *nh); > > + dp_packet_hwol_set_tx_ipv6(packet); > plen = ntohs(nh->ip6_plen); > dp_packet_set_l2_pad_size(packet, size - plen); > size = plen; /* Never pull padding. */ > @@ -3221,9 +3226,12 @@ packet_expand(struct dp_packet *p, const struct flow > *flow, size_t size) > struct ip_header *ip = dp_packet_l3(p); > > ip->ip_tot_len = htons(p->l4_ofs - p->l3_ofs + l4_len); > - ip->ip_csum = 0; > - ip->ip_csum = csum(ip, sizeof *ip); > - > + if (dp_packet_hwol_tx_ip_csum(p)) { > + dp_packet_ol_reset_ip_csum_good(p); > + } else { > + dp_packet_ip_set_header_csum(p); > + dp_packet_ol_set_ip_csum_good(p); > + } > pseudo_hdr_csum = packet_csum_pseudoheader(ip); > } else { /* ETH_TYPE_IPV6 */ > struct ovs_16aligned_ip6_hdr *nh = dp_packet_l3(p); > @@ -3313,6 +3321,7 @@ flow_compose(struct dp_packet *p, const struct flow > *flow, > /* Checksum has already been zeroed by put_zeros call. */ > ip->ip_csum = csum(ip, sizeof *ip); > > + dp_packet_ol_set_ip_csum_good(p); > pseudo_hdr_csum = packet_csum_pseudoheader(ip); > flow_compose_l4_csum(p, flow, pseudo_hdr_csum); > } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) { > diff --git a/lib/ipf.c b/lib/ipf.c > index d45266374..18c98576a 100644 > --- a/lib/ipf.c > +++ b/lib/ipf.c > @@ -433,7 +433,9 @@ ipf_reassemble_v4_frags(struct ipf_list *ipf_list) > len += rest_len; > l3 = dp_packet_l3(pkt); > ovs_be16 new_ip_frag_off = l3->ip_frag_off & ~htons(IP_MORE_FRAGMENTS); > - if (!dp_packet_hwol_is_ipv4(pkt)) { > + if (dp_packet_hwol_tx_ip_csum(pkt)) { > + dp_packet_ol_reset_ip_csum_good(pkt); > + } else { > l3->ip_csum = recalc_csum16(l3->ip_csum, l3->ip_frag_off, > new_ip_frag_off); > l3->ip_csum = recalc_csum16(l3->ip_csum, l3->ip_tot_len, htons(len)); > @@ -608,8 +610,7 @@ ipf_is_valid_v4_frag(struct ipf *ipf, struct dp_packet > *pkt) > goto invalid_pkt; > } > > - if (OVS_UNLIKELY(!dp_packet_ip_checksum_valid(pkt) > - && !dp_packet_hwol_is_ipv4(pkt) > + if (OVS_UNLIKELY(!dp_packet_ip_checksum_good(pkt) > && csum(l3, ip_hdr_len) != 0)) { > COVERAGE_INC(ipf_l3csum_err); > goto invalid_pkt; > @@ -1185,7 +1186,9 @@ ipf_post_execute_reass_pkts(struct ipf *ipf, > } else { > struct ip_header *l3_frag = > dp_packet_l3(frag_i->pkt); > struct ip_header *l3_reass = dp_packet_l3(pkt); > - if (!dp_packet_hwol_is_ipv4(frag_i->pkt)) { > + if (dp_packet_hwol_tx_ip_csum(frag_i->pkt)) { > + dp_packet_ol_reset_ip_csum_good(frag_i->pkt); > + } else { > ovs_be32 reass_ip = > get_16aligned_be32(&l3_reass->ip_src); > ovs_be32 frag_ip = > diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c > index 081900576..811c62a87 100644 > --- a/lib/netdev-dpdk.c > +++ b/lib/netdev-dpdk.c > @@ -397,8 +397,9 @@ enum dpdk_hw_ol_features { > NETDEV_RX_CHECKSUM_OFFLOAD = 1 << 0, > NETDEV_RX_HW_CRC_STRIP = 1 << 1, > NETDEV_RX_HW_SCATTER = 1 << 2, > - NETDEV_TX_TSO_OFFLOAD = 1 << 3, > - NETDEV_TX_SCTP_CHECKSUM_OFFLOAD = 1 << 4, > + NETDEV_TX_IPV4_CKSUM_OFFLOAD = 1 << 3, > + NETDEV_TX_TSO_OFFLOAD = 1 << 4, > + NETDEV_TX_SCTP_CHECKSUM_OFFLOAD = 1 << 5, > }; > > /* > @@ -984,6 +985,10 @@ dpdk_eth_dev_port_config(struct netdev_dpdk *dev, int > n_rxq, int n_txq) > conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_KEEP_CRC; > } > > + if (dev->hw_ol_features & NETDEV_TX_IPV4_CKSUM_OFFLOAD) { > + conf.txmode.offloads |= RTE_ETH_TX_OFFLOAD_IPV4_CKSUM; > + } > + > if (dev->hw_ol_features & NETDEV_TX_TSO_OFFLOAD) { > conf.txmode.offloads |= DPDK_TX_TSO_OFFLOAD_FLAGS; > if (dev->hw_ol_features & NETDEV_TX_SCTP_CHECKSUM_OFFLOAD) { > @@ -1124,6 +1129,12 @@ dpdk_eth_dev_init(struct netdev_dpdk *dev) > dev->hw_ol_features &= ~NETDEV_RX_HW_SCATTER; > } > > + if (info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_IPV4_CKSUM) { > + dev->hw_ol_features |= NETDEV_TX_IPV4_CKSUM_OFFLOAD; > + } else { > + dev->hw_ol_features &= ~NETDEV_TX_IPV4_CKSUM_OFFLOAD; > + } > + > dev->hw_ol_features &= ~NETDEV_TX_TSO_OFFLOAD; > if (userspace_tso_enabled()) { > if ((info.tx_offload_capa & tx_tso_offload_capa) > @@ -1693,16 +1704,12 @@ netdev_dpdk_get_config(const struct netdev *netdev, > struct smap *args) > dev->requested_txq_size); > smap_add_format(args, "configured_txq_descriptors", "%d", > dev->txq_size); > - if (dev->hw_ol_features & NETDEV_RX_CHECKSUM_OFFLOAD) { > - smap_add(args, "rx_csum_offload", "true"); > - } else { > - smap_add(args, "rx_csum_offload", "false"); > - } > - if (dev->hw_ol_features & NETDEV_TX_TSO_OFFLOAD) { > - smap_add(args, "tx_tso_offload", "true"); > - } else { > - smap_add(args, "tx_tso_offload", "false"); > - } > +#define HWOL_SMAP_ADD(FIELD, FLAG) \ > + smap_add(args, FIELD, dev->hw_ol_features & FLAG ? "true" : "false"); > + HWOL_SMAP_ADD("rx_csum_offload", NETDEV_RX_CHECKSUM_OFFLOAD); > + HWOL_SMAP_ADD("tx_ip_csum_offload", NETDEV_TX_IPV4_CKSUM_OFFLOAD); > + HWOL_SMAP_ADD("tx_tso_offload", NETDEV_TX_TSO_OFFLOAD); > +#undef HWOL_SMAP_ADD > smap_add(args, "lsc_interrupt_mode", > dev->lsc_interrupt_mode ? "true" : "false"); > > @@ -2145,12 +2152,10 @@ netdev_dpdk_prep_hwol_packet(struct netdev_dpdk *dev, > struct rte_mbuf *mbuf) > { > struct dp_packet *pkt = CONTAINER_OF(mbuf, struct dp_packet, mbuf); > > - if (mbuf->ol_flags & RTE_MBUF_F_TX_L4_MASK) { > - mbuf->l2_len = (char *)dp_packet_l3(pkt) - (char > *)dp_packet_eth(pkt); > - mbuf->l3_len = (char *)dp_packet_l4(pkt) - (char *)dp_packet_l3(pkt); > - mbuf->outer_l2_len = 0; > - mbuf->outer_l3_len = 0; > - } > + mbuf->l2_len = (char *) dp_packet_l3(pkt) - (char *) dp_packet_eth(pkt); > + mbuf->l3_len = (char *) dp_packet_l4(pkt) - (char *) dp_packet_l3(pkt); > + mbuf->outer_l2_len = 0; > + mbuf->outer_l3_len = 0; > > if (mbuf->ol_flags & RTE_MBUF_F_TX_TCP_SEG) { > struct tcp_header *th = dp_packet_l4(pkt); > @@ -2210,13 +2215,11 @@ netdev_dpdk_eth_tx_burst(struct netdev_dpdk *dev, int > qid, > uint32_t nb_tx = 0; > uint16_t nb_tx_prep = cnt; > > - if (userspace_tso_enabled()) { > - nb_tx_prep = rte_eth_tx_prepare(dev->port_id, qid, pkts, cnt); > - if (nb_tx_prep != cnt) { > - VLOG_WARN_RL(&rl, "%s: Output batch contains invalid packets. " > - "Only %u/%u are valid: %s", dev->up.name, > nb_tx_prep, > - cnt, rte_strerror(rte_errno)); > - } > + nb_tx_prep = rte_eth_tx_prepare(dev->port_id, qid, pkts, cnt); > + if (nb_tx_prep != cnt) { > + VLOG_WARN_RL(&rl, "%s: Output batch contains invalid packets. " > + "Only %u/%u are valid: %s", dev->up.name, nb_tx_prep, > + cnt, rte_strerror(rte_errno)); > } > > while (nb_tx != nb_tx_prep) { > @@ -2656,12 +2659,10 @@ dpdk_copy_dp_packet_to_mbuf(struct rte_mempool *mp, > struct dp_packet *pkt_orig) > memcpy(&pkt_dest->l2_pad_size, &pkt_orig->l2_pad_size, > sizeof(struct dp_packet) - offsetof(struct dp_packet, > l2_pad_size)); > > - if (mbuf_dest->ol_flags & RTE_MBUF_F_TX_L4_MASK) { > - mbuf_dest->l2_len = (char *)dp_packet_l3(pkt_dest) > - - (char *)dp_packet_eth(pkt_dest); > - mbuf_dest->l3_len = (char *)dp_packet_l4(pkt_dest) > - - (char *) dp_packet_l3(pkt_dest); > - } > + mbuf_dest->l2_len = (char *) dp_packet_l3(pkt_dest) > + - (char *) dp_packet_eth(pkt_dest); > + mbuf_dest->l3_len = (char *) dp_packet_l4(pkt_dest) > + - (char *) dp_packet_l3(pkt_dest); > > return pkt_dest; > } > @@ -4937,6 +4938,13 @@ netdev_dpdk_reconfigure(struct netdev *netdev) > } > > err = dpdk_eth_dev_init(dev); > + > + if (dev->hw_ol_features & NETDEV_TX_IPV4_CKSUM_OFFLOAD) { > + netdev->ol_flags |= NETDEV_TX_OFFLOAD_IPV4_CKSUM; > + } else { > + netdev->ol_flags &= ~NETDEV_TX_OFFLOAD_IPV4_CKSUM; > + } > + > if (dev->hw_ol_features & NETDEV_TX_TSO_OFFLOAD) { > netdev->ol_flags |= NETDEV_TX_OFFLOAD_TCP_TSO; > netdev->ol_flags |= NETDEV_TX_OFFLOAD_TCP_CKSUM; > diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c > index 72cb95471..db07ee46c 100644 > --- a/lib/netdev-dummy.c > +++ b/lib/netdev-dummy.c > @@ -148,6 +148,11 @@ struct netdev_dummy { > int requested_n_txq OVS_GUARDED; > int requested_n_rxq OVS_GUARDED; > int requested_numa_id OVS_GUARDED; > + > + /* Enable netdev IP csum offload. */ > + bool ol_ip_csum OVS_GUARDED; > + /* Flag RX packet with good csum. */ > + bool ol_ip_csum_set_good OVS_GUARDED; > }; > > /* Max 'recv_queue_len' in struct netdev_dummy. */ > @@ -910,6 +915,13 @@ netdev_dummy_set_config(struct netdev *netdev_, const > struct smap *args, > } > } > > + netdev->ol_ip_csum_set_good = smap_get_bool(args, "ol_ip_csum_set_good", > + false); > + netdev->ol_ip_csum = smap_get_bool(args, "ol_ip_csum", false); > + if (netdev->ol_ip_csum) { > + netdev_->ol_flags |= NETDEV_TX_OFFLOAD_IPV4_CKSUM; > + } > + > netdev_change_seq_changed(netdev_); > > /* 'dummy-pmd' specific config. */ > @@ -1088,6 +1100,10 @@ netdev_dummy_rxq_recv(struct netdev_rxq *rxq_, struct > dp_packet_batch *batch, > netdev->rxq_stats[rxq_->queue_id].bytes += dp_packet_size(packet); > netdev->custom_stats[0].value++; > netdev->custom_stats[1].value++; > + if (netdev->ol_ip_csum_set_good) { > + /* The netdev hardware sets the flag when the packet has good csum. > */ > + dp_packet_ol_set_ip_csum_good(packet); > + } > ovs_mutex_unlock(&netdev->mutex); > > dp_packet_batch_init_packet(batch, packet); > @@ -1170,6 +1186,13 @@ netdev_dummy_send(struct netdev *netdev, int qid, > } > > ovs_mutex_lock(&dev->mutex); > + if (dp_packet_hwol_tx_ip_csum(packet)) { > + if (!dp_packet_ip_checksum_good(packet)) { > + dp_packet_ip_set_header_csum(packet); > + dp_packet_ol_set_ip_csum_good(packet); > + } > + } > + > dev->stats.tx_packets++; > dev->txq_stats[qid].packets++; > dev->stats.tx_bytes += size; > diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c > index b89dfdd52..754e2d78d 100644 > --- a/lib/netdev-native-tnl.c > +++ b/lib/netdev-native-tnl.c > @@ -88,7 +88,10 @@ netdev_tnl_ip_extract_tnl_md(struct dp_packet *packet, > struct flow_tnl *tnl, > > ovs_be32 ip_src, ip_dst; > > - if (OVS_UNLIKELY(!dp_packet_ip_checksum_valid(packet))) { > + /* A packet coming from a network device might have the > + * csum already checked. In this case, skip the check. */ > + if (OVS_UNLIKELY(!dp_packet_ip_checksum_good(packet)) > + && !dp_packet_hwol_tx_ip_csum(packet)) { > if (csum(ip, IP_IHL(ip->ip_ihl_ver) * 4)) { > VLOG_WARN_RL(&err_rl, "ip packet has invalid checksum"); > return NULL; > @@ -142,7 +145,8 @@ netdev_tnl_ip_extract_tnl_md(struct dp_packet *packet, > struct flow_tnl *tnl, > * > * This function sets the IP header's ip_tot_len field (which should be > zeroed > * as part of 'header') and puts its value into '*ip_tot_size' as well. Also > - * updates IP header checksum, as well as the l3 and l4 offsets in 'packet'. > + * updates IP header checksum if not offloaded, as well as the l3 and l4 > + * offsets in 'packet'. > * > * Return pointer to the L4 header added to 'packet'. */ > void * > @@ -167,11 +171,16 @@ netdev_tnl_push_ip_header(struct dp_packet *packet, > *ip_tot_size -= IPV6_HEADER_LEN; > ip6->ip6_plen = htons(*ip_tot_size); > packet->l4_ofs = dp_packet_size(packet) - *ip_tot_size; > + dp_packet_hwol_set_tx_ipv6(packet); > + dp_packet_ol_reset_ip_csum_good(packet); > return ip6 + 1; > } else { > ip = netdev_tnl_ip_hdr(eth); > ip->ip_tot_len = htons(*ip_tot_size); > - ip->ip_csum = recalc_csum16(ip->ip_csum, 0, ip->ip_tot_len); > + /* Postpone checksum to when the packet is pushed to the port. */ > + dp_packet_hwol_set_tx_ipv4(packet); > + dp_packet_hwol_set_tx_ip_csum(packet); > + dp_packet_ol_reset_ip_csum_good(packet); > *ip_tot_size -= IP_HEADER_LEN; > packet->l4_ofs = dp_packet_size(packet) - *ip_tot_size; > return ip + 1; > @@ -190,7 +199,7 @@ udp_extract_tnl_md(struct dp_packet *packet, struct > flow_tnl *tnl, > } > > if (udp->udp_csum) { > - if (OVS_UNLIKELY(!dp_packet_l4_checksum_valid(packet))) { > + if (OVS_UNLIKELY(!dp_packet_l4_checksum_good(packet))) { > uint32_t csum; > if (netdev_tnl_is_header_ipv6(dp_packet_data(packet))) { > csum = packet_csum_pseudoheader6(dp_packet_l3(packet)); > @@ -297,8 +306,8 @@ netdev_tnl_ip_build_header(struct ovs_action_push_tnl > *data, > ip->ip_frag_off = (params->flow->tunnel.flags & > FLOW_TNL_F_DONT_FRAGMENT) ? > htons(IP_DF) : 0; > > - /* Checksum has already been zeroed by eth_build_header. */ > - ip->ip_csum = csum(ip, sizeof *ip); > + /* The checksum will be calculated when the headers are pushed > + * to the packet if offloading is not enabled. */ > > data->header_len += IP_HEADER_LEN; > return ip + 1; > diff --git a/lib/netdev.c b/lib/netdev.c > index 32ec45bbe..be546a291 100644 > --- a/lib/netdev.c > +++ b/lib/netdev.c > @@ -801,6 +801,14 @@ netdev_send_prepare_packet(const uint64_t netdev_flags, > return false; > } > > + /* Packet with IP csum offloading enabled was received with verified > csum. > + * Leave the IP csum offloading enabled even with good checksum to the > + * netdev to decide what would be the best to do. > + * Provide a software fallback in case the device doesn't support IP csum > + * offloading. Note: Encapsulated packet must have the inner IP header > + * csum already calculated. */ > + dp_packet_ol_send_prepare(packet, netdev_flags); > + > l4_mask = dp_packet_hwol_l4_mask(packet); > if (l4_mask) { > if (dp_packet_hwol_l4_is_tcp(packet)) { > @@ -968,7 +976,21 @@ netdev_push_header(const struct netdev *netdev, > "not supported: packet dropped", > netdev_get_name(netdev)); > } else { > + /* The packet is going to be encapsulated and there is > + * no support yet for inner network header csum offloading. */ > + if (dp_packet_hwol_tx_ip_csum(packet) > + && !dp_packet_ip_checksum_good(packet)) { > + dp_packet_ip_set_header_csum(packet); > + } > + > netdev->netdev_class->push_header(netdev, packet, data); > + if (dp_packet_hwol_tx_ip_csum(packet)) { > + dp_packet_ol_reset_ip_csum_good(packet); > + } else if (dp_packet_hwol_is_ipv4(packet)) { > + dp_packet_ip_set_header_csum(packet); > + dp_packet_ol_set_ip_csum_good(packet); > + } > + > pkt_metadata_init(&packet->md, data->out_port); > dp_packet_batch_refill(batch, packet, i); > } > diff --git a/lib/odp-execute.c b/lib/odp-execute.c > index 7da56793d..9b25db0ea 100644 > --- a/lib/odp-execute.c > +++ b/lib/odp-execute.c > @@ -167,9 +167,14 @@ odp_set_ipv4(struct dp_packet *packet, const struct > ovs_key_ipv4 *key, > new_tos = key->ipv4_tos | (nh->ip_tos & ~mask->ipv4_tos); > > if (nh->ip_tos != new_tos) { > - nh->ip_csum = recalc_csum16(nh->ip_csum, > - htons((uint16_t) nh->ip_tos), > - htons((uint16_t) new_tos)); > + if (dp_packet_hwol_tx_ip_csum(packet)) { > + dp_packet_ol_reset_ip_csum_good(packet); > + } else { > + nh->ip_csum = recalc_csum16(nh->ip_csum, > + htons((uint16_t) nh->ip_tos), > + htons((uint16_t) new_tos)); > + } > + > nh->ip_tos = new_tos; > } > } > @@ -178,8 +183,14 @@ odp_set_ipv4(struct dp_packet *packet, const struct > ovs_key_ipv4 *key, > new_ttl = key->ipv4_ttl | (nh->ip_ttl & ~mask->ipv4_ttl); > > if (OVS_LIKELY(nh->ip_ttl != new_ttl)) { > - nh->ip_csum = recalc_csum16(nh->ip_csum, htons(nh->ip_ttl << 8), > - htons(new_ttl << 8)); > + if (dp_packet_hwol_tx_ip_csum(packet)) { > + dp_packet_ol_reset_ip_csum_good(packet); > + } else { > + nh->ip_csum = recalc_csum16(nh->ip_csum, > + htons(nh->ip_ttl << 8), > + htons(new_ttl << 8)); > + } > + > nh->ip_ttl = new_ttl; > } > } > diff --git a/lib/packets.c b/lib/packets.c > index 874066e3c..8334dc523 100644 > --- a/lib/packets.c > +++ b/lib/packets.c > @@ -1144,7 +1144,12 @@ packet_set_ipv4_addr(struct dp_packet *packet, > } > } > } > - nh->ip_csum = recalc_csum32(nh->ip_csum, old_addr, new_addr); > + > + if (dp_packet_hwol_tx_ip_csum(packet)) { > + dp_packet_ol_reset_ip_csum_good(packet); > + } else { > + nh->ip_csum = recalc_csum32(nh->ip_csum, old_addr, new_addr); > + } > put_16aligned_be32(addr, new_addr); > } > > @@ -1309,16 +1314,26 @@ packet_set_ipv4(struct dp_packet *packet, ovs_be32 > src, ovs_be32 dst, > if (nh->ip_tos != tos) { > uint8_t *field = &nh->ip_tos; > > - nh->ip_csum = recalc_csum16(nh->ip_csum, htons((uint16_t) *field), > - htons((uint16_t) tos)); > + if (dp_packet_hwol_tx_ip_csum(packet)) { > + dp_packet_ol_reset_ip_csum_good(packet); > + } else { > + nh->ip_csum = recalc_csum16(nh->ip_csum, htons((uint16_t) > *field), > + htons((uint16_t) tos)); > + } > + > *field = tos; > } > > if (nh->ip_ttl != ttl) { > uint8_t *field = &nh->ip_ttl; > > - nh->ip_csum = recalc_csum16(nh->ip_csum, htons(*field << 8), > - htons(ttl << 8)); > + if (dp_packet_hwol_tx_ip_csum(packet)) { > + dp_packet_ol_reset_ip_csum_good(packet); > + } else { > + nh->ip_csum = recalc_csum16(nh->ip_csum, htons(*field << 8), > + htons(ttl << 8)); > + } > + > *field = ttl; > } > } > @@ -1927,8 +1942,13 @@ IP_ECN_set_ce(struct dp_packet *pkt, bool is_ipv6) > > tos |= IP_ECN_CE; > if (nh->ip_tos != tos) { > - nh->ip_csum = recalc_csum16(nh->ip_csum, htons(nh->ip_tos), > - htons((uint16_t) tos)); > + if (dp_packet_hwol_tx_ip_csum(pkt)) { > + dp_packet_ol_reset_ip_csum_good(pkt); > + } else { > + nh->ip_csum = recalc_csum16(nh->ip_csum, htons(nh->ip_tos), > + htons((uint16_t) tos)); > + } > + > nh->ip_tos = tos; > } > } > diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c > index 57f94df54..8de8a4c2e 100644 > --- a/ofproto/ofproto-dpif-upcall.c > +++ b/ofproto/ofproto-dpif-upcall.c > @@ -215,7 +215,7 @@ struct upcall { > enum odp_key_fitness fitness; /* Fitness of 'flow' relative to ODP key. > */ > const ovs_u128 *ufid; /* Unique identifier for 'flow'. */ > unsigned pmd_id; /* Datapath poll mode driver id. */ > - const struct dp_packet *packet; /* Packet associated with this upcall. > */ > + const struct dp_packet *packet; /* Packet associated with this upcall. > */ > ofp_port_t ofp_in_port; /* OpenFlow in port, or OFPP_NONE. */ > uint16_t mru; /* If !0, Maximum receive unit of > fragmented IP packet */ > diff --git a/tests/automake.mk b/tests/automake.mk > index b29cb783e..1b6296411 100644 > --- a/tests/automake.mk > +++ b/tests/automake.mk > @@ -161,6 +161,7 @@ SYSTEM_KMOD_TESTSUITE_AT = \ > SYSTEM_USERSPACE_TESTSUITE_AT = \ > tests/system-userspace-testsuite.at \ > tests/system-userspace-macros.at \ > + tests/system-userspace-offload.at \ > tests/system-userspace-packet-type-aware.at \ > tests/system-route.at > > diff --git a/tests/system-userspace-testsuite.at > b/tests/system-userspace-testsuite.at > index 2e9659a67..1021b4ad4 100644 > --- a/tests/system-userspace-testsuite.at > +++ b/tests/system-userspace-testsuite.at > @@ -25,5 +25,6 @@ m4_include([tests/system-common-macros.at]) > m4_include([tests/system-traffic.at]) > m4_include([tests/system-layer3-tunnels.at]) > m4_include([tests/system-interface.at]) > +m4_include([tests/system-userspace-offload.at]) > m4_include([tests/system-userspace-packet-type-aware.at]) > m4_include([tests/system-route.at]) > -- > 2.31.1 > _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
