diff --git a/NEWS b/NEWS
index 70bd17584594..58fbcedcb9bf 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,7 @@ Post-v2.13.0
      * The OpenFlow ofp_desc/serial_num may now be configured by setting the
        value of other-config:dp-sn in the Bridge table.
      * Added support to watch CONTROLLER port status in fast failover group.
+     * New action "delete_field".
    - DPDK:
      * Deprecated DPDK pdump packet capture support removed.
      * Deprecated DPDK ring ports (dpdkr) are no longer supported.
diff --git a/include/openvswitch/ofp-actions.h b/include/openvswitch/ofp-actions.h
index c8948e0d694f..226e86d0b0a5 100644
--- a/include/openvswitch/ofp-actions.h
+++ b/include/openvswitch/ofp-actions.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2019 Nicira, Inc.
+ * Copyright (c) 2012-2017, 2019-2020 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -94,6 +94,7 @@ struct vl_mff_map;
     OFPACT(PUSH_MPLS,       ofpact_push_mpls,   ofpact, "push_mpls")    \
     OFPACT(POP_MPLS,        ofpact_pop_mpls,    ofpact, "pop_mpls")     \
     OFPACT(DEC_NSH_TTL,     ofpact_null,        ofpact, "dec_nsh_ttl")  \
+    OFPACT(DELETE_FIELD,    ofpact_delete_field, ofpact, "delete_field") \
                                                                         \
     /* Generic encap & decap */                                         \
     OFPACT(ENCAP,           ofpact_encap,       props, "encap")         \
@@ -576,6 +577,16 @@ struct ofpact_pop_mpls {
     );
 };
 
+/* OFPACT_DELETE_FIELD.
+ *
+ * Used for NXAST_DELETE_FIELD. */
+struct ofpact_delete_field {
+    OFPACT_PADDED_MEMBERS(
+        struct ofpact ofpact;
+        const struct mf_field *field;
+    );
+};
+
 /* OFPACT_SET_TUNNEL.
  *
  * Used for NXAST_SET_TUNNEL, NXAST_SET_TUNNEL64. */
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 058816c7b88f..3ffd7d9d7711 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc.
+ * Copyright (c) 2010-2017, 2020 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -1994,6 +1994,24 @@ nxm_execute_stack_pop(const struct ofpact_stack *pop,
     }
 }
 
+/* Parses a field from '*s' into '*field'.  If successful, stores the
+ * reference to the field in '*field', and returns NULL.  On failure,
+ * returns a malloc()'ed error message.
+ */
+char * OVS_WARN_UNUSED_RESULT
+mf_parse_field(const struct mf_field **field, const char *s)
+{
+    const struct nxm_field *f;
+    int s_len = strlen(s);
+
+    f = nxm_field_by_name(s, s_len);
+    (*field) = f ? mf_from_id(f->id) : mf_from_name_len(s, s_len);
+    if (!*field) {
+        return xasprintf("unknown field `%s'", s);
+    }
+    return NULL;
+}
+
 /* Formats 'sf' into 's' in a format normally acceptable to
  * mf_parse_subfield().  (It won't be acceptable if sf->field is NULL or if
  * sf->field has no NXM name.) */
diff --git a/lib/nx-match.h b/lib/nx-match.h
index 9be40a98150e..3120ac0a0d5f 100644
--- a/lib/nx-match.h
+++ b/lib/nx-match.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2017 Nicira, Inc.
+ * Copyright (c) 2010-2017, 2020 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -42,6 +42,8 @@ struct vl_mff_map;
  * See include/openflow/nicira-ext.h for NXM specification.
  */
 
+char * mf_parse_field(const struct mf_field **field, const char *s)
+    OVS_WARN_UNUSED_RESULT;
 void mf_format_subfield(const struct mf_subfield *, struct ds *);
 char *mf_parse_subfield__(struct mf_subfield *sf, const char **s)
     OVS_WARN_UNUSED_RESULT;
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index a94d1a7ca918..be08a53fd589 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2017, 2019 Nicira, Inc.
+ * Copyright (c) 2008-2017, 2019-2020 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -361,6 +361,9 @@ enum ofp_raw_action_type {
     /* NX1.0+(49): struct nx_action_check_pkt_larger, ... VLMFF */
     NXAST_RAW_CHECK_PKT_LARGER,
 
+    /* NX1.0+(50): struct nx_action_delete_field. VLMFF */
+    NXAST_RAW_DELETE_FIELD,
+
 /* ## ------------------ ## */
 /* ## Debugging actions. ## */
 /* ## ------------------ ## */
@@ -500,6 +503,7 @@ ofpact_next_flattened(const struct ofpact *ofpact)
     case OFPACT_DECAP:
     case OFPACT_DEC_NSH_TTL:
     case OFPACT_CHECK_PKT_LARGER:
+    case OFPACT_DELETE_FIELD:
         return ofpact_next(ofpact);
 
     case OFPACT_CLONE:
@@ -4140,6 +4144,87 @@ check_SET_TUNNEL(const struct ofpact_tunnel *a OVS_UNUSED,
     return 0;
 }
 
+/* Delete field action. */
+
+/* Action structure for DELETE_FIELD */
+struct nx_action_delete_field {
+    ovs_be16 type;          /* OFPAT_VENDOR */
+    ovs_be16 len;           /* Length is 24. */
+    ovs_be32 vendor;        /* NX_VENDOR_ID. */
+    ovs_be16 subtype;       /* NXAST_DELETE_FIELD. */
+    /* Followed by:
+     * - OXM/NXM header for field to delete (4 or 8 bytes).
+     * - Enough 0-bytes to pad out the action to 24 bytes. */
+    uint8_t pad[14];
+};
+OFP_ASSERT(sizeof(struct nx_action_delete_field ) == 24);
+
+static enum ofperr
+decode_NXAST_RAW_DELETE_FIELD(const struct nx_action_delete_field *nadf,
+                              enum ofp_version ofp_version OVS_UNUSED,
+                              const struct vl_mff_map *vl_mff_map,
+                              uint64_t *tlv_bitmap, struct ofpbuf *out)
+{
+    struct ofpact_delete_field *delete_field;
+    enum ofperr err;
+
+    delete_field = ofpact_put_DELETE_FIELD(out);
+    delete_field->ofpact.raw = NXAST_RAW_DELETE_FIELD;
+
+    struct ofpbuf b = ofpbuf_const_initializer(nadf, ntohs(nadf->len));
+    ofpbuf_pull(&b, OBJECT_OFFSETOF(nadf, pad));
+
+    err = mf_vl_mff_nx_pull_header(&b, vl_mff_map, &delete_field->field,
+                                   NULL, tlv_bitmap);
+    if (err) {
+        return err;
+    }
+
+    return 0;
+}
+
+static void
+encode_DELETE_FIELD(const struct ofpact_delete_field *delete_field,
+                    enum ofp_version ofp_version OVS_UNUSED,
+                    struct ofpbuf *out)
+{
+    struct nx_action_delete_field *nadf = put_NXAST_DELETE_FIELD(out);
+    size_t size = out->size;
+
+    out->size = size - sizeof nadf->pad;
+    nx_put_mff_header(out, delete_field->field, 0, false);
+    out->size = size;
+}
+
+static char * OVS_WARN_UNUSED_RESULT
+parse_DELETE_FIELD(char *arg, const struct ofpact_parse_params *pp)
+{
+    struct ofpact_delete_field *delete_field;
+
+    delete_field = ofpact_put_DELETE_FIELD(pp->ofpacts);
+    return mf_parse_field(&delete_field->field, arg);
+}
+
+static void
+format_DELETE_FIELD(const struct ofpact_delete_field *odf,
+                          const struct ofpact_format_params *fp)
+{
+    ds_put_format(fp->s, "%sdelete_field:%s", colors.param,
+                  colors.end);
+    ds_put_format(fp->s, "%s", odf->field->name);
+}
+
+static enum ofperr
+check_DELETE_FIELD(const struct ofpact_delete_field *odf,
+                         struct ofpact_check_params *cp OVS_UNUSED)
+{
+    if (odf->field->id < MFF_TUN_METADATA0 ||
+        odf->field->id > MFF_TUN_METADATA63) {
+        return OFPERR_OFPBAC_BAD_ARGUMENT;
+    }
+    return 0;
+}
+
 /* Set queue action. */
 
 static enum ofperr
@@ -7870,6 +7955,7 @@ action_set_classify(const struct ofpact *a)
     case OFPACT_DEBUG_RECIRC:
     case OFPACT_DEBUG_SLOW:
     case OFPACT_CHECK_PKT_LARGER:
+    case OFPACT_DELETE_FIELD:
         return ACTION_SLOT_INVALID;
 
     default:
@@ -8073,6 +8159,7 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type,
     case OFPACT_DECAP:
     case OFPACT_DEC_NSH_TTL:
     case OFPACT_CHECK_PKT_LARGER:
+    case OFPACT_DELETE_FIELD:
     default:
         return OVSINST_OFPIT11_APPLY_ACTIONS;
     }
@@ -8984,6 +9071,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port)
     case OFPACT_DECAP:
     case OFPACT_DEC_NSH_TTL:
     case OFPACT_CHECK_PKT_LARGER:
+    case OFPACT_DELETE_FIELD:
     default:
         return false;
     }
diff --git a/lib/ovs-actions.xml b/lib/ovs-actions.xml
index ab8e08b84d8b..060a079b4852 100644
--- a/lib/ovs-actions.xml
+++ b/lib/ovs-actions.xml
@@ -1552,6 +1552,22 @@ for <var>i</var> in [1,<var>n_slaves</var>]:
         This action was added in Open vSwitch 2.11.90.
       </p>
     </action>
+
+    <action name="DELETE_FIELD">
+      <h2>The <code>delete_field</code> action</h2>
+      <syntax><code>delete_field:</code><var>field</var></syntax>
+
+      <p>
+        The <code>delete_field</code> action deletes a field in the syntax
+        described under ``Field Specifications'' above.  Currently, only
+        the tun_metadta fields are supported.
+      </p>
+
+      <p>
+        This action was added in Open vSwitch 2.13.90.
+      </p>
+    </action>
+
   </group>
 
   <group title="Metadata Actions">
diff --git a/lib/tun-metadata.c b/lib/tun-metadata.c
index f8a0e19524e9..c0b0ae044897 100644
--- a/lib/tun-metadata.c
+++ b/lib/tun-metadata.c
@@ -261,6 +261,23 @@ tun_metadata_write(struct flow_tnl *tnl,
                        value->tun_metadata + mf->n_bytes - loc->len, loc, idx);
 }
 
+/* Deletes field 'mf' in 'tnl' (in non-UDPIF format).
+ * 'mf' must be an MFF_TUN_METADATA* field.
+ */
+void
+tun_metadata_delete(struct flow_tnl *tnl, const struct mf_field *mf)
+{
+    unsigned int idx;
+
+    if (tnl->flags & FLOW_TNL_F_UDPIF) {
+        return;
+    }
+
+    idx = mf->id - MFF_TUN_METADATA0;
+    ovs_assert(idx < TUN_METADATA_NUM_OPTS);
+    ULLONG_SET0(tnl->metadata.present.map, idx);
+}
+
 static const struct tun_metadata_loc *
 metadata_loc_from_match(const struct tun_table *map, struct match *match,
                         const char *name, unsigned int idx,
diff --git a/lib/tun-metadata.h b/lib/tun-metadata.h
index 7dad9504b8da..67dedae2522b 100644
--- a/lib/tun-metadata.h
+++ b/lib/tun-metadata.h
@@ -47,6 +47,7 @@ void tun_metadata_read(const struct flow_tnl *,
                        const struct mf_field *, union mf_value *);
 void tun_metadata_write(struct flow_tnl *,
                         const struct mf_field *, const union mf_value *);
+void tun_metadata_delete(struct flow_tnl *, const struct mf_field *);
 void tun_metadata_set_match(const struct mf_field *,
                             const union mf_value *value,
                             const union mf_value *mask, struct match *,
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index abce976c6c2f..80fba84cb1a5 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019 Nicira, Inc.
+/* Copyright (c) 2009-2017, 2019-2020 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -5159,6 +5159,21 @@ compose_dec_mpls_ttl_action(struct xlate_ctx *ctx)
     return true;
 }
 
+static void
+xlate_delete_field(struct xlate_ctx *ctx,
+                   struct flow *flow,
+                   const struct ofpact_delete_field *odf)
+{
+    struct ds s = DS_EMPTY_INITIALIZER;
+
+    /* Currently, only tun_metadata is allowed for delete_field action. */
+    tun_metadata_delete(&flow->tunnel, odf->field);
+
+    ds_put_format(&s, "delete %s", odf->field->name);
+    xlate_report(ctx, OFT_DETAIL, "%s", ds_cstr(&s));
+    ds_destroy(&s);
+}
+
 /* Emits an action that outputs to 'port', within 'ctx'.
  *
  * 'controller_len' affects only packets sent to an OpenFlow controller.  It
@@ -5684,6 +5699,7 @@ reversible_actions(const struct ofpact *ofpacts, size_t ofpacts_len)
         case OFPACT_WRITE_ACTIONS:
         case OFPACT_WRITE_METADATA:
         case OFPACT_CHECK_PKT_LARGER:
+        case OFPACT_DELETE_FIELD:
             break;
 
         case OFPACT_CT:
@@ -5993,6 +6009,7 @@ freeze_unroll_actions(const struct ofpact *a, const struct ofpact *end,
         case OFPACT_CT_CLEAR:
         case OFPACT_NAT:
         case OFPACT_CHECK_PKT_LARGER:
+        case OFPACT_DELETE_FIELD:
             /* These may not generate PACKET INs. */
             break;
 
@@ -6653,6 +6670,7 @@ recirc_for_mpls(const struct ofpact *a, struct xlate_ctx *ctx)
     case OFPACT_WRITE_METADATA:
     case OFPACT_GOTO_TABLE:
     case OFPACT_CHECK_PKT_LARGER:
+    case OFPACT_DELETE_FIELD:
     default:
         break;
     }
@@ -7030,6 +7048,10 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             xlate_fin_timeout(ctx, ofpact_get_FIN_TIMEOUT(a));
             break;
 
+        case OFPACT_DELETE_FIELD:
+            xlate_delete_field(ctx, flow, ofpact_get_DELETE_FIELD(a));
+            break;
+
         case OFPACT_CLEAR_ACTIONS:
             xlate_report_action_set(ctx, "was");
             ofpbuf_clear(&ctx->action_set);
diff --git a/tests/ofp-actions.at b/tests/ofp-actions.at
index 4893280a998f..28b2099a0c71 100644
--- a/tests/ofp-actions.at
+++ b/tests/ofp-actions.at
@@ -316,6 +316,9 @@ ffff 0018 00002320 0031 05dc 000000010004000000000000
 # actions=check_pkt_larger(1000)->NXM_NX_XXREG1[4]
 ffff 0018 00002320 0031 03e8 00040001e010000000000000
 
+# actions=delete_field:tun_metadata10
+ffff 0018 00002320 0032 00 01 64 7c 00 00 00 00 000000000000
+
 ])
 sed '/^[[#&]]/d' < test-data > input.txt
 sed -n 's/^# //p; /^$/p' < test-data > expout
diff --git a/tests/tunnel.at b/tests/tunnel.at
index d65bf4412aa9..b3764aed8e9e 100644
--- a/tests/tunnel.at
+++ b/tests/tunnel.at
@@ -890,6 +890,43 @@ Datapath actions: set(tunnel(dst=1.1.1.1,ttl=64,tp_dst=6081,geneve({class=0xffff
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([tunnel - Delete Geneve option])
+OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=geneve \
+                    options:remote_ip=1.1.1.1 ofport_request=1 \
+                    -- add-port br0 p2 -- set Interface p2 type=dummy \
+                    ofport_request=2 ofport_request=2])
+OVS_VSWITCHD_DISABLE_TUNNEL_PUSH_POP
+
+AT_CHECK([ovs-ofctl add-tlv-map br0 "{class=0xffff,type=0,len=4}->tun_metadata0,{class=0xffff,type=1,len=4}->tun_metadata1,{class=0xffff,type=2,len=4}->tun_metadata3"])
+
+AT_DATA([flows.txt], [dnl
+table=0,tun_metadata0=0x11112222,actions=set_field:0x55556666->tun_metadata1,resubmit(,1)
+table=0,tun_metadata0=0x33334444,actions=delete_field:tun_metadata0,set_field:0x77778888->tun_metadata1,resubmit(,1)
+table=0,tun_metadata0=0x88889999,actions=delete_field:tun_metadata3,resubmit(,1)
+table=1,actions=IN_PORT
+])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=0,len=4,0x11112222}),flags(df|key)),in_port(6081),skb_mark(0),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(frag=no)'], [0], [stdout])
+AT_CHECK([tail -2 stdout], [0],
+  [Megaflow: recirc_id=0,eth,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-csum+key,tun_metadata0=0x11112222,tun_metadata1=NP,in_port=1,nw_ecn=0,nw_frag=no
+Datapath actions: set(tunnel(dst=1.1.1.1,ttl=64,tp_dst=6081,geneve({class=0xffff,type=0,len=4,0x11112222}{class=0xffff,type=0x1,len=4,0x55556666}),flags(df))),6081
+])
+
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=0,len=4,0x33334444}),flags(df|key)),in_port(6081),skb_mark(0),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(frag=no)'], [0], [stdout])
+AT_CHECK([tail -2 stdout], [0],
+  [Megaflow: recirc_id=0,eth,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-csum+key,tun_metadata0=0x33334444,tun_metadata1=NP,in_port=1,nw_ecn=0,nw_frag=no
+Datapath actions: set(tunnel(dst=1.1.1.1,ttl=64,tp_dst=6081,geneve({class=0xffff,type=0x1,len=4,0x77778888}),flags(df))),6081
+])
+
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=0,len=4,0x88889999}),flags(df|key)),in_port(6081),skb_mark(0),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(frag=no)'], [0], [stdout])
+AT_CHECK([tail -2 stdout], [0],
+  [Megaflow: recirc_id=0,eth,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-csum+key,tun_metadata0=0x88889999,in_port=1,nw_ecn=0,nw_frag=no
+Datapath actions: set(tunnel(dst=1.1.1.1,ttl=64,tp_dst=6081,geneve({class=0xffff,type=0,len=4,0x88889999}),flags(df))),6081
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([tunnel - concomitant IPv6 and IPv4 tunnels])
 OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=vxlan \
                     options:remote_ip=1.1.1.1 ofport_request=1 \
