Re: [PATCH net-next] net/mlx4_en: don't set CHECKSUM_COMPLETE on SCTP packets
On 19/06/2017 8:04 PM, Davide Caratti wrote: hello Tariq, On Sun, 2017-06-18 at 14:10 +0300, Tariq Toukan wrote: @@ -624,12 +632,13 @@ static int check_csum(struct mlx4_cqe *cqe, struct sk_buff *skb, void *va, hdr += sizeof(struct vlan_hdr); } - if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV4)) - get_fixed_ipv4_csum(hw_checksum, skb, hdr); + if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV4)) && + (unlikely(get_fixed_ipv4_csum(hw_checksum, skb, hdr No! The lazy evaluation trick is wrong here. This way you'll end up going almost always to the else (ipv6) for the wrong reason. you are right! thanks for spotting this. + return -1; #if IS_ENABLED(CONFIG_IPV6) - else if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV6)) - if (unlikely(get_fixed_ipv6_csum(hw_checksum, skb, hdr))) - return -1; + else if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV6)) && + (unlikely(get_fixed_ipv6_csum(hw_checksum, skb, hdr + return -1; Let's not change this, might cause future bugs, similarly to the one above. #endif return 0; } maybe we can avoid adding braces, remove that 'else' keyword and the nested 'if', thus saving one line, given that check_csum() returns the same set of values as get_fixed_ipv{4,6}_checksum(), with the same meaning (-1 => go with CHECKSUM_NONE, 0 => go with CHECKSUM_COMPLETE). Yeah this sounds good. >8 @@ -625,11 +633,10 @@ static int check_csum(struct mlx4_cqe *cqe, struct sk_buff *skb, void *va, } if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV4)) - get_fixed_ipv4_csum(hw_checksum, skb, hdr); + return get_fixed_ipv4_csum(hw_checksum, skb, hdr); #if IS_ENABLED(CONFIG_IPV6) - else if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV6)) - if (unlikely(get_fixed_ipv6_csum(hw_checksum, skb, hdr))) - return -1; + if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV6)) + return get_fixed_ipv6_csum(hw_checksum, skb, hdr); #endif return 0; } 8< Looks good to me. I will test and repost a v2 with this modification, unless you have any objections. Thank you in advance! regards -- davide Thank you Davide. Regards, Tariq
Re: [PATCH net-next] net/mlx4_en: don't set CHECKSUM_COMPLETE on SCTP packets
hello Tariq, On Sun, 2017-06-18 at 14:10 +0300, Tariq Toukan wrote: > > @@ -624,12 +632,13 @@ static int check_csum(struct mlx4_cqe *cqe, struct > > sk_buff *skb, void *va, > > hdr += sizeof(struct vlan_hdr); > > } > > > > - if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV4)) > > - get_fixed_ipv4_csum(hw_checksum, skb, hdr); > > + if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV4)) && > > + (unlikely(get_fixed_ipv4_csum(hw_checksum, skb, hdr > > No! The lazy evaluation trick is wrong here. > This way you'll end up going almost always to the else (ipv6) for the > wrong reason. you are right! thanks for spotting this. > > + return -1; > > #if IS_ENABLED(CONFIG_IPV6) > > - else if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV6)) > > - if (unlikely(get_fixed_ipv6_csum(hw_checksum, skb, hdr))) > > - return -1; > > + else if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV6)) && > > + (unlikely(get_fixed_ipv6_csum(hw_checksum, skb, hdr > > + return -1; > > Let's not change this, might cause future bugs, similarly to the one above. > > #endif > > return 0; > > } maybe we can avoid adding braces, remove that 'else' keyword and the nested 'if', thus saving one line, given that check_csum() returns the same set of values as get_fixed_ipv{4,6}_checksum(), with the same meaning (-1 => go with CHECKSUM_NONE, 0 => go with CHECKSUM_COMPLETE). >8 @@ -625,11 +633,10 @@ static int check_csum(struct mlx4_cqe *cqe, struct sk_buff *skb, void *va, } if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV4)) - get_fixed_ipv4_csum(hw_checksum, skb, hdr); + return get_fixed_ipv4_csum(hw_checksum, skb, hdr); #if IS_ENABLED(CONFIG_IPV6) - else if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV6)) - if (unlikely(get_fixed_ipv6_csum(hw_checksum, skb, hdr))) - return -1; + if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV6)) + return get_fixed_ipv6_csum(hw_checksum, skb, hdr); #endif return 0; } 8< I will test and repost a v2 with this modification, unless you have any objections. Thank you in advance! regards -- davide
Re: [PATCH net-next] net/mlx4_en: don't set CHECKSUM_COMPLETE on SCTP packets
On 16/06/2017 5:01 PM, Davide Caratti wrote: if the NIC fails to validate the checksum on TCP/UDP, and validation of IP checksum is successful, the driver subtracts the pseudo-header checksum from the value obtained by the hardware and sets CHECKSUM_COMPLETE. Don't do that if protocol is IPPROTO_SCTP, otherwise CRC32c validation fails. Reported-by: Shuang LiFixes: f8c6455bb04b ("net/mlx4_en: Extend checksum offloading by CHECKSUM COMPLETE") Signed-off-by: Davide Caratti --- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 33 +++--- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 77abd18..d9293e4 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -572,16 +572,21 @@ static inline __wsum get_fixed_vlan_csum(__wsum hw_checksum, * header, the HW adds it. To address that, we are subtracting the pseudo * header checksum from the checksum value provided by the HW. */ -static void get_fixed_ipv4_csum(__wsum hw_checksum, struct sk_buff *skb, - struct iphdr *iph) +static int get_fixed_ipv4_csum(__wsum hw_checksum, struct sk_buff *skb, + struct iphdr *iph) { __u16 length_for_csum = 0; __wsum csum_pseudo_header = 0; + __u8 ipproto = iph->protocol; + + if (ipproto == IPPROTO_SCTP) This is unlikely(). + return -1; length_for_csum = (be16_to_cpu(iph->tot_len) - (iph->ihl << 2)); csum_pseudo_header = csum_tcpudp_nofold(iph->saddr, iph->daddr, - length_for_csum, iph->protocol, 0); + length_for_csum, ipproto, 0); skb->csum = csum_sub(hw_checksum, csum_pseudo_header); + return 0; } #if IS_ENABLED(CONFIG_IPV6) @@ -592,17 +597,20 @@ static void get_fixed_ipv4_csum(__wsum hw_checksum, struct sk_buff *skb, static int get_fixed_ipv6_csum(__wsum hw_checksum, struct sk_buff *skb, struct ipv6hdr *ipv6h) { + __u8 nexthdr = ipv6h->nexthdr; __wsum csum_pseudo_hdr = 0; - if (unlikely(ipv6h->nexthdr == IPPROTO_FRAGMENT || -ipv6h->nexthdr == IPPROTO_HOPOPTS)) + if (unlikely(nexthdr == IPPROTO_FRAGMENT || +nexthdr == IPPROTO_HOPOPTS || +nexthdr == IPPROTO_SCTP)) return -1; - hw_checksum = csum_add(hw_checksum, (__force __wsum)htons(ipv6h->nexthdr)); + hw_checksum = csum_add(hw_checksum, (__force __wsum)htons(nexthdr)); csum_pseudo_hdr = csum_partial(>saddr, sizeof(ipv6h->saddr) + sizeof(ipv6h->daddr), 0); csum_pseudo_hdr = csum_add(csum_pseudo_hdr, (__force __wsum)ipv6h->payload_len); - csum_pseudo_hdr = csum_add(csum_pseudo_hdr, (__force __wsum)ntohs(ipv6h->nexthdr)); + csum_pseudo_hdr = csum_add(csum_pseudo_hdr, + (__force __wsum)htons(nexthdr)); skb->csum = csum_sub(hw_checksum, csum_pseudo_hdr); skb->csum = csum_add(skb->csum, csum_partial(ipv6h, sizeof(struct ipv6hdr), 0)); @@ -624,12 +632,13 @@ static int check_csum(struct mlx4_cqe *cqe, struct sk_buff *skb, void *va, hdr += sizeof(struct vlan_hdr); } - if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV4)) - get_fixed_ipv4_csum(hw_checksum, skb, hdr); + if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV4)) && + (unlikely(get_fixed_ipv4_csum(hw_checksum, skb, hdr No! The lazy evaluation trick is wrong here. This way you'll end up going almost always to the else (ipv6) for the wrong reason. + return -1; #if IS_ENABLED(CONFIG_IPV6) - else if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV6)) - if (unlikely(get_fixed_ipv6_csum(hw_checksum, skb, hdr))) - return -1; + else if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV6)) && +(unlikely(get_fixed_ipv6_csum(hw_checksum, skb, hdr + return -1; Let's not change this, might cause future bugs, similarly to the one above. #endif return 0; } Regards, Tariq
[PATCH net-next] net/mlx4_en: don't set CHECKSUM_COMPLETE on SCTP packets
if the NIC fails to validate the checksum on TCP/UDP, and validation of IP checksum is successful, the driver subtracts the pseudo-header checksum from the value obtained by the hardware and sets CHECKSUM_COMPLETE. Don't do that if protocol is IPPROTO_SCTP, otherwise CRC32c validation fails. Reported-by: Shuang LiFixes: f8c6455bb04b ("net/mlx4_en: Extend checksum offloading by CHECKSUM COMPLETE") Signed-off-by: Davide Caratti --- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 33 +++--- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 77abd18..d9293e4 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -572,16 +572,21 @@ static inline __wsum get_fixed_vlan_csum(__wsum hw_checksum, * header, the HW adds it. To address that, we are subtracting the pseudo * header checksum from the checksum value provided by the HW. */ -static void get_fixed_ipv4_csum(__wsum hw_checksum, struct sk_buff *skb, - struct iphdr *iph) +static int get_fixed_ipv4_csum(__wsum hw_checksum, struct sk_buff *skb, + struct iphdr *iph) { __u16 length_for_csum = 0; __wsum csum_pseudo_header = 0; + __u8 ipproto = iph->protocol; + + if (ipproto == IPPROTO_SCTP) + return -1; length_for_csum = (be16_to_cpu(iph->tot_len) - (iph->ihl << 2)); csum_pseudo_header = csum_tcpudp_nofold(iph->saddr, iph->daddr, - length_for_csum, iph->protocol, 0); + length_for_csum, ipproto, 0); skb->csum = csum_sub(hw_checksum, csum_pseudo_header); + return 0; } #if IS_ENABLED(CONFIG_IPV6) @@ -592,17 +597,20 @@ static void get_fixed_ipv4_csum(__wsum hw_checksum, struct sk_buff *skb, static int get_fixed_ipv6_csum(__wsum hw_checksum, struct sk_buff *skb, struct ipv6hdr *ipv6h) { + __u8 nexthdr = ipv6h->nexthdr; __wsum csum_pseudo_hdr = 0; - if (unlikely(ipv6h->nexthdr == IPPROTO_FRAGMENT || -ipv6h->nexthdr == IPPROTO_HOPOPTS)) + if (unlikely(nexthdr == IPPROTO_FRAGMENT || +nexthdr == IPPROTO_HOPOPTS || +nexthdr == IPPROTO_SCTP)) return -1; - hw_checksum = csum_add(hw_checksum, (__force __wsum)htons(ipv6h->nexthdr)); + hw_checksum = csum_add(hw_checksum, (__force __wsum)htons(nexthdr)); csum_pseudo_hdr = csum_partial(>saddr, sizeof(ipv6h->saddr) + sizeof(ipv6h->daddr), 0); csum_pseudo_hdr = csum_add(csum_pseudo_hdr, (__force __wsum)ipv6h->payload_len); - csum_pseudo_hdr = csum_add(csum_pseudo_hdr, (__force __wsum)ntohs(ipv6h->nexthdr)); + csum_pseudo_hdr = csum_add(csum_pseudo_hdr, + (__force __wsum)htons(nexthdr)); skb->csum = csum_sub(hw_checksum, csum_pseudo_hdr); skb->csum = csum_add(skb->csum, csum_partial(ipv6h, sizeof(struct ipv6hdr), 0)); @@ -624,12 +632,13 @@ static int check_csum(struct mlx4_cqe *cqe, struct sk_buff *skb, void *va, hdr += sizeof(struct vlan_hdr); } - if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV4)) - get_fixed_ipv4_csum(hw_checksum, skb, hdr); + if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV4)) && + (unlikely(get_fixed_ipv4_csum(hw_checksum, skb, hdr + return -1; #if IS_ENABLED(CONFIG_IPV6) - else if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV6)) - if (unlikely(get_fixed_ipv6_csum(hw_checksum, skb, hdr))) - return -1; + else if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV6)) && +(unlikely(get_fixed_ipv6_csum(hw_checksum, skb, hdr + return -1; #endif return 0; } -- 2.9.4