diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index ac3d2edebff2..d83f3a90370f 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -1954,6 +1954,7 @@ parse_flow_put(struct dpif_netlink *dpif, struct dpif_flow_put *put)
     struct netdev *dev;
     struct offload_info info;
     ovs_be16 dst_port = 0;
+    uint8_t csum_on = false;
     int err;
 
     if (put->flags & DPIF_FP_PROBE) {
@@ -1994,12 +1995,16 @@ parse_flow_put(struct dpif_netlink *dpif, struct dpif_flow_put *put)
             if (tnl_cfg && tnl_cfg->dst_port != 0) {
                 dst_port = tnl_cfg->dst_port;
             }
+            if (tnl_cfg) {
+                csum_on = tnl_cfg->csum;
+            }
             netdev_close(outdev);
         }
     }
 
     info.dpif_class = dpif_class;
     info.tp_dst_port = dst_port;
+    info.tunnel_csum_on = csum_on;
     err = netdev_flow_put(dev, &match,
                           CONST_CAST(struct nlattr *, put->actions),
                           put->actions_len,
diff --git a/lib/netdev-tc-offloads.c b/lib/netdev-tc-offloads.c
index 62ae021e06d5..6f1fbe6678f9 100644
--- a/lib/netdev-tc-offloads.c
+++ b/lib/netdev-tc-offloads.c
@@ -643,6 +643,10 @@ parse_tc_flower_to_match(struct tc_flower *flower,
                 }
                 nl_msg_put_be16(buf, OVS_TUNNEL_KEY_ATTR_TP_DST,
                                 action->encap.tp_dst);
+                if (!action->encap.no_csum) {
+                    nl_msg_put_u8(buf, OVS_TUNNEL_KEY_ATTR_CSUM,
+                                  !action->encap.no_csum);
+                }
 
                 parse_tc_flower_geneve_opts(action, buf);
                 nl_msg_end_nested(buf, tunnel_offset);
@@ -1276,6 +1280,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
             }
             if (action->type == TC_ACT_ENCAP) {
                 action->encap.tp_dst = info->tp_dst_port;
+                action->encap.no_csum = !info->tunnel_csum_on;
             }
         } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_SET_MASKED) {
             const struct nlattr *set = nl_attr_get(nla);
diff --git a/lib/netdev.h b/lib/netdev.h
index 556676046395..5ceba88dbf03 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -201,6 +201,7 @@ void netdev_send_wait(struct netdev *, int qid);
 struct offload_info {
     const struct dpif_class *dpif_class;
     ovs_be16 tp_dst_port; /* Destination port for tunnel in SET action */
+    uint8_t tunnel_csum_on; /* Tunnel header with checksum */
 
     /*
      * The flow mark id assigened to the flow. If any pkts hit the flow,
diff --git a/lib/tc.c b/lib/tc.c
index 20428bb9e952..47127ca2ce90 100644
--- a/lib/tc.c
+++ b/lib/tc.c
@@ -865,6 +865,7 @@ static const struct nl_policy tunnel_key_policy[] = {
     [TCA_TUNNEL_KEY_ENC_TOS] = { .type = NL_A_U8, .optional = true, },
     [TCA_TUNNEL_KEY_ENC_TTL] = { .type = NL_A_U8, .optional = true, },
     [TCA_TUNNEL_KEY_ENC_OPTS] = { .type = NL_A_NESTED, .optional = true, },
+    [TCA_TUNNEL_KEY_NO_CSUM] = { .type = NL_A_U8, .optional = true, },
 };
 
 static int
@@ -995,6 +996,7 @@ nl_parse_act_tunnel_key(struct nlattr *options, struct tc_flower *flower)
         struct nlattr *tos = tun_attrs[TCA_TUNNEL_KEY_ENC_TOS];
         struct nlattr *ttl = tun_attrs[TCA_TUNNEL_KEY_ENC_TTL];
         struct nlattr *tun_opt = tun_attrs[TCA_TUNNEL_KEY_ENC_OPTS];
+        struct nlattr *no_csum = tun_attrs[TCA_TUNNEL_KEY_NO_CSUM];
 
         action = &flower->actions[flower->action_count++];
         action->type = TC_ACT_ENCAP;
@@ -1010,6 +1012,7 @@ nl_parse_act_tunnel_key(struct nlattr *options, struct tc_flower *flower)
         action->encap.tp_dst = dst_port ? nl_attr_get_be16(dst_port) : 0;
         action->encap.tos = tos ? nl_attr_get_u8(tos) : 0;
         action->encap.ttl = ttl ? nl_attr_get_u8(ttl) : 0;
+        action->encap.no_csum = no_csum ? nl_attr_get_u8(no_csum) : 0;
 
         err = nl_parse_act_tunnel_opts(tun_opt, action);
         if (err) {
@@ -1628,7 +1631,8 @@ nl_msg_put_act_tunnel_key_set(struct ofpbuf *request, ovs_be64 id,
                               struct in6_addr *ipv6_src,
                               struct in6_addr *ipv6_dst,
                               ovs_be16 tp_dst, uint8_t tos, uint8_t ttl,
-                              struct tun_metadata tun_metadata)
+                              struct tun_metadata tun_metadata,
+                              uint8_t no_csum)
 {
     size_t offset;
 
@@ -1659,6 +1663,7 @@ nl_msg_put_act_tunnel_key_set(struct ofpbuf *request, ovs_be64 id,
         }
         nl_msg_put_be16(request, TCA_TUNNEL_KEY_ENC_DST_PORT, tp_dst);
         nl_msg_put_act_tunnel_geneve_option(request, tun_metadata);
+        nl_msg_put_u8(request, TCA_TUNNEL_KEY_NO_CSUM, no_csum);
     }
     nl_msg_end_nested(request, offset);
 }
@@ -1902,7 +1907,8 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)
                                               action->encap.tp_dst,
                                               action->encap.tos,
                                               action->encap.ttl,
-                                              action->encap.data);
+                                              action->encap.data,
+                                              action->encap.no_csum);
                 nl_msg_end_nested(request, act_offset);
             }
             break;
diff --git a/lib/tc.h b/lib/tc.h
index cff96c5c2e0b..fe64fa887cc0 100644
--- a/lib/tc.h
+++ b/lib/tc.h
@@ -151,6 +151,7 @@ struct tc_action {
             ovs_be16 tp_dst;
             uint8_t tos;
             uint8_t ttl;
+            uint8_t no_csum;
             struct {
                 ovs_be32 ipv4_src;
                 ovs_be32 ipv4_dst;
