#include "../nfp_app.h"
 #include "../nfpcore/nfp_cpp.h"
 
-#define NFP_FLOWER_LAYER_META          BIT(0)
+#define NFP_FLOWER_LAYER_EXT_META      BIT(0)
 #define NFP_FLOWER_LAYER_PORT          BIT(1)
 #define NFP_FLOWER_LAYER_MAC           BIT(2)
 #define NFP_FLOWER_LAYER_TP            BIT(3)
 #define NFP_FLOWER_LAYER_CT            BIT(6)
 #define NFP_FLOWER_LAYER_VXLAN         BIT(7)
 
+#define NFP_FLOWER_LAYER2_GENEVE       BIT(5)
+
 #define NFP_FLOWER_MASK_VLAN_PRIO      GENMASK(15, 13)
 #define NFP_FLOWER_MASK_VLAN_CFI       BIT(12)
 #define NFP_FLOWER_MASK_VLAN_VID       GENMASK(11, 0)
 enum nfp_flower_tun_type {
        NFP_FL_TUNNEL_NONE =    0,
        NFP_FL_TUNNEL_VXLAN =   2,
+       NFP_FL_TUNNEL_GENEVE =  4,
 };
 
 struct nfp_fl_act_head {
        __be16 tci;
 };
 
+/* Extended metadata for additional key_layers (1W/4B)
+ * ----------------------------------------------------------------
+ *    3                   2                   1
+ *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                      nfp_flow_key_layer2                      |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct nfp_flower_ext_meta {
+       __be32 nfp_flow_key_layer2;
+};
+
 /* Port details (1W/4B)
  * ----------------------------------------------------------------
  *    3                   2                   1
        struct in6_addr ipv6_dst;
 };
 
-/* Flow Frame VXLAN --> Tunnel details (4W/16B)
+/* Flow Frame IPv4 UDP TUNNEL --> Tunnel details (4W/16B)
  * -----------------------------------------------------------------
  *    3                   2                   1
  *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  * |                         ipv4_addr_dst                         |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |           tun_flags           |       tos     |       ttl     |
+ * |                            Reserved                           |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |   gpe_flags   |            Reserved           | Next Protocol |
+ * |                            Reserved                           |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  * |                     VNI                       |   Reserved    |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  */
-struct nfp_flower_vxlan {
+struct nfp_flower_ipv4_udp_tun {
        __be32 ip_src;
        __be32 ip_dst;
-       __be16 tun_flags;
-       u8 tos;
-       u8 ttl;
-       u8 gpe_flags;
-       u8 reserved[2];
-       u8 nxt_proto;
+       __be32 reserved[2];
        __be32 tun_id;
 };
 
 
 #ifndef __NFP_FLOWER_H__
 #define __NFP_FLOWER_H__ 1
 
+#include "cmsg.h"
+
 #include <linux/circ_buf.h>
 #include <linux/hashtable.h>
 #include <linux/time64.h>
 #define NFP_FL_MASK_ID_LOCATION                1
 
 #define NFP_FL_VXLAN_PORT              4789
+#define NFP_FL_GENEVE_PORT             6081
+
+/* Extra features bitmap. */
+#define NFP_FL_FEATS_GENEVE            BIT(0)
 
 struct nfp_fl_mask_id {
        struct circ_buf mask_id_free_list;
 int nfp_flower_compile_flow_match(struct tc_cls_flower_offload *flow,
                                  struct nfp_fl_key_ls *key_ls,
                                  struct net_device *netdev,
-                                 struct nfp_fl_payload *nfp_flow);
+                                 struct nfp_fl_payload *nfp_flow,
+                                 enum nfp_flower_tun_type tun_type);
 int nfp_flower_compile_action(struct tc_cls_flower_offload *flow,
                              struct net_device *netdev,
                              struct nfp_fl_payload *nfp_flow);
 
        }
 }
 
+static void
+nfp_flower_compile_ext_meta(struct nfp_flower_ext_meta *frame, u32 key_ext)
+{
+       frame->nfp_flow_key_layer2 = cpu_to_be32(key_ext);
+}
+
 static int
 nfp_flower_compile_port(struct nfp_flower_in_port *frame, u32 cmsg_port,
                        bool mask_version, enum nfp_flower_tun_type tun_type)
 }
 
 static void
-nfp_flower_compile_vxlan(struct nfp_flower_vxlan *frame,
-                        struct tc_cls_flower_offload *flow,
-                        bool mask_version)
+nfp_flower_compile_ipv4_udp_tun(struct nfp_flower_ipv4_udp_tun *frame,
+                               struct tc_cls_flower_offload *flow,
+                               bool mask_version)
 {
        struct fl_flow_key *target = mask_version ? flow->mask : flow->key;
-       struct flow_dissector_key_ipv4_addrs *vxlan_ips;
+       struct flow_dissector_key_ipv4_addrs *tun_ips;
        struct flow_dissector_key_keyid *vni;
 
-       /* Wildcard TOS/TTL/GPE_FLAGS/NXT_PROTO for now. */
-       memset(frame, 0, sizeof(struct nfp_flower_vxlan));
+       memset(frame, 0, sizeof(struct nfp_flower_ipv4_udp_tun));
 
        if (dissector_uses_key(flow->dissector,
                               FLOW_DISSECTOR_KEY_ENC_KEYID)) {
 
        if (dissector_uses_key(flow->dissector,
                               FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) {
-               vxlan_ips =
+               tun_ips =
                   skb_flow_dissector_target(flow->dissector,
                                             FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS,
                                             target);
-               frame->ip_src = vxlan_ips->src;
-               frame->ip_dst = vxlan_ips->dst;
+               frame->ip_src = tun_ips->src;
+               frame->ip_dst = tun_ips->dst;
        }
 }
 
 int nfp_flower_compile_flow_match(struct tc_cls_flower_offload *flow,
                                  struct nfp_fl_key_ls *key_ls,
                                  struct net_device *netdev,
-                                 struct nfp_fl_payload *nfp_flow)
+                                 struct nfp_fl_payload *nfp_flow,
+                                 enum nfp_flower_tun_type tun_type)
 {
-       enum nfp_flower_tun_type tun_type = NFP_FL_TUNNEL_NONE;
        struct nfp_repr *netdev_repr;
        int err;
        u8 *ext;
        u8 *msk;
 
-       if (key_ls->key_layer & NFP_FLOWER_LAYER_VXLAN)
-               tun_type = NFP_FL_TUNNEL_VXLAN;
-
        memset(nfp_flow->unmasked_data, 0, key_ls->key_size);
        memset(nfp_flow->mask_data, 0, key_ls->key_size);
 
        ext += sizeof(struct nfp_flower_meta_tci);
        msk += sizeof(struct nfp_flower_meta_tci);
 
+       /* Populate Extended Metadata if Required. */
+       if (NFP_FLOWER_LAYER_EXT_META & key_ls->key_layer) {
+               nfp_flower_compile_ext_meta((struct nfp_flower_ext_meta *)ext,
+                                           key_ls->key_layer_two);
+               nfp_flower_compile_ext_meta((struct nfp_flower_ext_meta *)msk,
+                                           key_ls->key_layer_two);
+               ext += sizeof(struct nfp_flower_ext_meta);
+               msk += sizeof(struct nfp_flower_ext_meta);
+       }
+
        /* Populate Exact Port data. */
        err = nfp_flower_compile_port((struct nfp_flower_in_port *)ext,
                                      nfp_repr_get_port_id(netdev),
                msk += sizeof(struct nfp_flower_ipv6);
        }
 
-       if (key_ls->key_layer & NFP_FLOWER_LAYER_VXLAN) {
+       if (key_ls->key_layer & NFP_FLOWER_LAYER_VXLAN ||
+           key_ls->key_layer_two & NFP_FLOWER_LAYER2_GENEVE) {
                __be32 tun_dst;
 
                /* Populate Exact VXLAN Data. */
-               nfp_flower_compile_vxlan((struct nfp_flower_vxlan *)ext,
-                                        flow, false);
+               nfp_flower_compile_ipv4_udp_tun((void *)ext, flow, false);
                /* Populate Mask VXLAN Data. */
-               nfp_flower_compile_vxlan((struct nfp_flower_vxlan *)msk,
-                                        flow, true);
-               tun_dst = ((struct nfp_flower_vxlan *)ext)->ip_dst;
-               ext += sizeof(struct nfp_flower_vxlan);
-               msk += sizeof(struct nfp_flower_vxlan);
+               nfp_flower_compile_ipv4_udp_tun((void *)msk, flow, true);
+               tun_dst = ((struct nfp_flower_ipv4_udp_tun *)ext)->ip_dst;
+               ext += sizeof(struct nfp_flower_ipv4_udp_tun);
+               msk += sizeof(struct nfp_flower_ipv4_udp_tun);
 
                /* Configure tunnel end point MAC. */
                if (nfp_netdev_is_nfp_repr(netdev)) {
 
 }
 
 static int
-nfp_flower_calculate_key_layers(struct nfp_fl_key_ls *ret_key_ls,
+nfp_flower_calculate_key_layers(struct nfp_app *app,
+                               struct nfp_fl_key_ls *ret_key_ls,
                                struct tc_cls_flower_offload *flow,
-                               bool egress)
+                               bool egress,
+                               enum nfp_flower_tun_type *tun_type)
 {
        struct flow_dissector_key_basic *mask_basic = NULL;
        struct flow_dissector_key_basic *key_basic = NULL;
+       struct nfp_flower_priv *priv = app->priv;
        u32 key_layer_two;
        u8 key_layer;
        int key_size;
                                                  FLOW_DISSECTOR_KEY_ENC_PORTS,
                                                  flow->key);
 
-               if (mask_enc_ports->dst != cpu_to_be16(~0) ||
-                   enc_ports->dst != htons(NFP_FL_VXLAN_PORT))
+               if (mask_enc_ports->dst != cpu_to_be16(~0))
                        return -EOPNOTSUPP;
 
-               key_layer |= NFP_FLOWER_LAYER_VXLAN;
-               key_size += sizeof(struct nfp_flower_vxlan);
+               switch (enc_ports->dst) {
+               case htons(NFP_FL_VXLAN_PORT):
+                       *tun_type = NFP_FL_TUNNEL_VXLAN;
+                       key_layer |= NFP_FLOWER_LAYER_VXLAN;
+                       key_size += sizeof(struct nfp_flower_ipv4_udp_tun);
+                       break;
+               case htons(NFP_FL_GENEVE_PORT):
+                       if (!(priv->flower_ext_feats & NFP_FL_FEATS_GENEVE))
+                               return -EOPNOTSUPP;
+                       *tun_type = NFP_FL_TUNNEL_GENEVE;
+                       key_layer |= NFP_FLOWER_LAYER_EXT_META;
+                       key_size += sizeof(struct nfp_flower_ext_meta);
+                       key_layer_two |= NFP_FLOWER_LAYER2_GENEVE;
+                       key_size += sizeof(struct nfp_flower_ipv4_udp_tun);
+                       break;
+               default:
+                       return -EOPNOTSUPP;
+               }
        } else if (egress) {
                /* Reject non tunnel matches offloaded to egress repr. */
                return -EOPNOTSUPP;
 nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev,
                       struct tc_cls_flower_offload *flow, bool egress)
 {
+       enum nfp_flower_tun_type tun_type = NFP_FL_TUNNEL_NONE;
        struct nfp_flower_priv *priv = app->priv;
        struct nfp_fl_payload *flow_pay;
        struct nfp_fl_key_ls *key_layer;
        if (!key_layer)
                return -ENOMEM;
 
-       err = nfp_flower_calculate_key_layers(key_layer, flow, egress);
+       err = nfp_flower_calculate_key_layers(app, key_layer, flow, egress,
+                                             &tun_type);
        if (err)
                goto err_free_key_ls;
 
                goto err_free_key_ls;
        }
 
-       err = nfp_flower_compile_flow_match(flow, key_layer, netdev, flow_pay);
+       err = nfp_flower_compile_flow_match(flow, key_layer, netdev, flow_pay,
+                                           tun_type);
        if (err)
                goto err_destroy_flow;