bool               collect_md;
        bool               use_udp6_rx_checksums;
        bool               ttl_inherit;
+       enum ifla_geneve_df df;
 };
 
 struct geneve_sock {
        struct rtable *rt;
        struct flowi4 fl4;
        __u8 tos, ttl;
+       __be16 df = 0;
        __be16 sport;
-       __be16 df;
        int err;
 
        rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info);
        if (geneve->collect_md) {
                tos = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
                ttl = key->ttl;
+
+               df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
        } else {
                tos = ip_tunnel_ecn_encap(fl4.flowi4_tos, ip_hdr(skb), skb);
                if (geneve->ttl_inherit)
                else
                        ttl = key->ttl;
                ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
+
+               if (geneve->df == GENEVE_DF_SET) {
+                       df = htons(IP_DF);
+               } else if (geneve->df == GENEVE_DF_INHERIT) {
+                       struct ethhdr *eth = eth_hdr(skb);
+
+                       if (ntohs(eth->h_proto) == ETH_P_IPV6) {
+                               df = htons(IP_DF);
+                       } else if (ntohs(eth->h_proto) == ETH_P_IP) {
+                               struct iphdr *iph = ip_hdr(skb);
+
+                               if (iph->frag_off & htons(IP_DF))
+                                       df = htons(IP_DF);
+                       }
+               }
        }
-       df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
 
        err = geneve_build_skb(&rt->dst, skb, info, xnet, sizeof(struct iphdr));
        if (unlikely(err))
        [IFLA_GENEVE_UDP_ZERO_CSUM6_TX] = { .type = NLA_U8 },
        [IFLA_GENEVE_UDP_ZERO_CSUM6_RX] = { .type = NLA_U8 },
        [IFLA_GENEVE_TTL_INHERIT]       = { .type = NLA_U8 },
+       [IFLA_GENEVE_DF]                = { .type = NLA_U8 },
 };
 
 static int geneve_validate(struct nlattr *tb[], struct nlattr *data[],
                }
        }
 
+       if (data[IFLA_GENEVE_DF]) {
+               enum ifla_geneve_df df = nla_get_u8(data[IFLA_GENEVE_DF]);
+
+               if (df < 0 || df > GENEVE_DF_MAX) {
+                       NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_GENEVE_DF],
+                                           "Invalid DF attribute");
+                       return -EINVAL;
+               }
+       }
+
        return 0;
 }
 
                            struct netlink_ext_ack *extack,
                            const struct ip_tunnel_info *info,
                            bool metadata, bool ipv6_rx_csum,
-                           bool ttl_inherit)
+                           bool ttl_inherit, enum ifla_geneve_df df)
 {
        struct geneve_net *gn = net_generic(net, geneve_net_id);
        struct geneve_dev *t, *geneve = netdev_priv(dev);
        geneve->collect_md = metadata;
        geneve->use_udp6_rx_checksums = ipv6_rx_csum;
        geneve->ttl_inherit = ttl_inherit;
+       geneve->df = df;
 
        err = register_netdevice(dev);
        if (err)
                          struct netlink_ext_ack *extack,
                          struct ip_tunnel_info *info, bool *metadata,
                          bool *use_udp6_rx_checksums, bool *ttl_inherit,
-                         bool changelink)
+                         enum ifla_geneve_df *df, bool changelink)
 {
        int attrtype;
 
        if (data[IFLA_GENEVE_TOS])
                info->key.tos = nla_get_u8(data[IFLA_GENEVE_TOS]);
 
+       if (data[IFLA_GENEVE_DF])
+               *df = nla_get_u8(data[IFLA_GENEVE_DF]);
+
        if (data[IFLA_GENEVE_LABEL]) {
                info->key.label = nla_get_be32(data[IFLA_GENEVE_LABEL]) &
                                  IPV6_FLOWLABEL_MASK;
                          struct nlattr *tb[], struct nlattr *data[],
                          struct netlink_ext_ack *extack)
 {
+       enum ifla_geneve_df df = GENEVE_DF_UNSET;
        bool use_udp6_rx_checksums = false;
        struct ip_tunnel_info info;
        bool ttl_inherit = false;
 
        init_tnl_info(&info, GENEVE_UDP_PORT);
        err = geneve_nl2info(tb, data, extack, &info, &metadata,
-                            &use_udp6_rx_checksums, &ttl_inherit, false);
+                            &use_udp6_rx_checksums, &ttl_inherit, &df, false);
        if (err)
                return err;
 
        err = geneve_configure(net, dev, extack, &info, metadata,
-                              use_udp6_rx_checksums, ttl_inherit);
+                              use_udp6_rx_checksums, ttl_inherit, df);
        if (err)
                return err;
 
        struct ip_tunnel_info info;
        bool metadata;
        bool use_udp6_rx_checksums;
+       enum ifla_geneve_df df;
        bool ttl_inherit;
        int err;
 
        use_udp6_rx_checksums = geneve->use_udp6_rx_checksums;
        ttl_inherit = geneve->ttl_inherit;
        err = geneve_nl2info(tb, data, extack, &info, &metadata,
-                            &use_udp6_rx_checksums, &ttl_inherit, true);
+                            &use_udp6_rx_checksums, &ttl_inherit, &df, true);
        if (err)
                return err;
 
                nla_total_size(sizeof(struct in6_addr)) + /* IFLA_GENEVE_REMOTE{6} */
                nla_total_size(sizeof(__u8)) +  /* IFLA_GENEVE_TTL */
                nla_total_size(sizeof(__u8)) +  /* IFLA_GENEVE_TOS */
+               nla_total_size(sizeof(__u8)) +  /* IFLA_GENEVE_DF */
                nla_total_size(sizeof(__be32)) +  /* IFLA_GENEVE_LABEL */
                nla_total_size(sizeof(__be16)) +  /* IFLA_GENEVE_PORT */
                nla_total_size(0) +      /* IFLA_GENEVE_COLLECT_METADATA */
            nla_put_be32(skb, IFLA_GENEVE_LABEL, info->key.label))
                goto nla_put_failure;
 
+       if (nla_put_u8(skb, IFLA_GENEVE_DF, geneve->df))
+               goto nla_put_failure;
+
        if (nla_put_be16(skb, IFLA_GENEVE_PORT, info->key.tp_dst))
                goto nla_put_failure;
 
                return dev;
 
        init_tnl_info(&info, dst_port);
-       err = geneve_configure(net, dev, NULL, &info, true, true, false);
+       err = geneve_configure(net, dev, NULL, &info,
+                              true, true, false, GENEVE_DF_UNSET);
        if (err) {
                free_netdev(dev);
                return ERR_PTR(err);