skb->csum_algo carries the indication on which algorithm is needed to
compute checksum on skb in the transmit path, when skb->ip_summed is
equal to CHECKSUM_PARTIAL. If skb carries a SCTP packet and crc32c
hasn't been yet written in L4 header, skb->csum_algo is assigned to
CRC32C_CHECKSUM. In any other case, skb->csum_algo is set to
INTERNET_CHECKSUM.

Suggested-by: Tom Herbert <t...@herbertland.com>
Signed-off-by: Davide Caratti <dcara...@redhat.com>
---
 include/linux/skbuff.h                | 28 ++++++++++++++++++++--------
 net/core/dev.c                        |  2 +-
 net/netfilter/ipvs/ip_vs_proto_sctp.c |  2 +-
 net/netfilter/nf_nat_proto_sctp.c     |  2 +-
 net/sched/act_csum.c                  |  2 +-
 net/sctp/offload.c                    |  2 +-
 net/sctp/output.c                     |  3 ++-
 7 files changed, 27 insertions(+), 14 deletions(-)

diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index aaf1072..527be47 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -189,12 +189,13 @@
  *
  *   NETIF_F_SCTP_CRC - This feature indicates that a device is capable of
  *     offloading the SCTP CRC in a packet. To perform this offload the stack
- *     will set ip_summed to CHECKSUM_PARTIAL and set csum_start and 
csum_offset
- *     accordingly. Note the there is no indication in the skbuff that the
- *     CHECKSUM_PARTIAL refers to an SCTP checksum, a driver that supports
- *     both IP checksum offload and SCTP CRC offload must verify which offload
- *     is configured for a packet presumably by inspecting packet headers; in
- *     case, skb_crc32c_csum_help is provided to compute CRC on SCTP packets.
+ *     will set set csum_start and csum_offset accordingly, set ip_summed to
+ *     CHECKSUM_PARTIAL and set csum_algo to CRC32C_CHECKSUM, to provide an
+ *     indication in the skbuff that the CHECKSUM_PARTIAL refers to CRC32c.
+ *     A driver that supports both IP checksum offload and SCTP CRC32c offload
+ *     must verify which offload is configured for a packet by testing the
+ *     value of skb->csum_algo; skb_crc32c_csum_help is provided to resolve
+ *     CHECKSUM_PARTIAL on skbs where csum_algo is CRC32C_CHECKSUM.
  *
  *   NETIF_F_FCOE_CRC - This feature indicates that a device is capable of
  *     offloading the FCOE CRC in a packet. To perform this offload the stack
@@ -614,6 +615,7 @@ static inline bool skb_mstamp_after(const struct skb_mstamp 
*t1,
  *     @wifi_acked_valid: wifi_acked was set
  *     @wifi_acked: whether frame was acked on wifi or not
  *     @no_fcs:  Request NIC to treat last 4 bytes as Ethernet FCS
+ *     @csum_algo: algorithm used to compute checksum
  *     @dst_pending_confirm: need to confirm neighbour
   *    @napi_id: id of the NAPI struct this skb came from
  *     @secmark: security marking
@@ -742,8 +744,10 @@ struct sk_buff {
        __u8                    csum_valid:1;
        __u8                    csum_complete_sw:1;
        __u8                    csum_level:2;
-       __u8                    __unused:1; /* one bit hole */
-
+       enum {
+               INTERNET_CHECKSUM = 0,
+               CRC32C_CHECKSUM,
+       }                       csum_algo:1;
        __u8                    dst_pending_confirm:1;
 #ifdef CONFIG_IPV6_NDISC_NODETYPE
        __u8                    ndisc_nodetype:2;
@@ -3129,6 +3133,14 @@ struct skb_checksum_ops {
 
 extern const struct skb_checksum_ops *crc32c_csum_stub __read_mostly;
 
+static inline void skb_set_crc32c_ipsummed(struct sk_buff *skb,
+                                          const u8 ip_summed)
+{
+       skb->csum_algo = ip_summed == CHECKSUM_PARTIAL ? CRC32C_CHECKSUM :
+               INTERNET_CHECKSUM;
+       skb->ip_summed = ip_summed;
+}
+
 __wsum __skb_checksum(const struct sk_buff *skb, int offset, int len,
                      __wsum csum, const struct skb_checksum_ops *ops);
 __wsum skb_checksum(const struct sk_buff *skb, int offset, int len,
diff --git a/net/core/dev.c b/net/core/dev.c
index 91ba01a..c6a4281 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2641,7 +2641,7 @@ int skb_crc32c_csum_help(struct sk_buff *skb)
                        goto out;
        }
        *(__le32 *)(skb->data + offset) = crc32c_csum;
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_set_crc32c_ipsummed(skb, CHECKSUM_NONE);
 out:
        return ret;
 }
diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c 
b/net/netfilter/ipvs/ip_vs_proto_sctp.c
index 56f8e4b..8800bf7 100644
--- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
@@ -81,7 +81,7 @@ static void sctp_nat_csum(struct sk_buff *skb, sctp_sctphdr_t 
*sctph,
                          unsigned int sctphoff)
 {
        sctph->checksum = sctp_compute_cksum(skb, sctphoff);
-       skb->ip_summed = CHECKSUM_UNNECESSARY;
+       skb_set_crc32c_ipsummed(skb, CHECKSUM_UNNECESSARY);
 }
 
 static int
diff --git a/net/netfilter/nf_nat_proto_sctp.c 
b/net/netfilter/nf_nat_proto_sctp.c
index 804e8a0..82a7c4c 100644
--- a/net/netfilter/nf_nat_proto_sctp.c
+++ b/net/netfilter/nf_nat_proto_sctp.c
@@ -60,7 +60,7 @@ sctp_manip_pkt(struct sk_buff *skb,
 
        if (skb->ip_summed != CHECKSUM_PARTIAL) {
                hdr->checksum = sctp_compute_cksum(skb, hdroff);
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_set_crc32c_ipsummed(skb, CHECKSUM_NONE);
        }
 
        return true;
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c
index 6c319a4..6e7e862 100644
--- a/net/sched/act_csum.c
+++ b/net/sched/act_csum.c
@@ -349,7 +349,7 @@ static int tcf_csum_sctp(struct sk_buff *skb, unsigned int 
ihl,
 
        sctph->checksum = sctp_compute_cksum(skb,
                                             skb_network_offset(skb) + ihl);
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_set_crc32c_ipsummed(skb, CHECKSUM_NONE);
 
        return 1;
 }
diff --git a/net/sctp/offload.c b/net/sctp/offload.c
index 378f462..4b98339 100644
--- a/net/sctp/offload.c
+++ b/net/sctp/offload.c
@@ -34,7 +34,7 @@
 
 static __le32 sctp_gso_make_checksum(struct sk_buff *skb)
 {
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_set_crc32c_ipsummed(skb, CHECKSUM_NONE);
        return sctp_compute_cksum(skb, skb_transport_offset(skb));
 }
 
diff --git a/net/sctp/output.c b/net/sctp/output.c
index 1224421..386cbd8 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -524,10 +524,11 @@ static int sctp_packet_pack(struct sctp_packet *packet,
                struct sctphdr *sh =
                        (struct sctphdr *)skb_transport_header(head);
 
+               skb_set_crc32c_ipsummed(head, CHECKSUM_NONE);
                sh->checksum = sctp_compute_cksum(head, 0);
        } else {
 chksum:
-               head->ip_summed = CHECKSUM_PARTIAL;
+               skb_set_crc32c_ipsummed(head, CHECKSUM_PARTIAL);
                head->csum_start = skb_transport_header(head) - head->head;
                head->csum_offset = offsetof(struct sctphdr, checksum);
        }
-- 
2.7.4

Reply via email to