ice: low level support for tunnels
authorMichal Swiatkowski <michal.swiatkowski@linux.intel.com>
Tue, 12 Oct 2021 18:31:05 +0000 (11:31 -0700)
committerTony Nguyen <anthony.l.nguyen@intel.com>
Thu, 28 Oct 2021 18:00:20 +0000 (11:00 -0700)
Add definition of UDP tunnel dummy packets. Fill destination port value
in filter based on UDP tunnel port. Append tunnel flags to switch filter
definition in case of matching the tunnel.

Both VXLAN and Geneve are UDP tunnels, so only one new header is needed.

Signed-off-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
Tested-by: Sandeep Penigalapati <sandeep.penigalapati@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
drivers/net/ethernet/intel/ice/ice_flex_pipe.c
drivers/net/ethernet/intel/ice/ice_flex_type.h
drivers/net/ethernet/intel/ice/ice_protocol_type.h
drivers/net/ethernet/intel/ice/ice_switch.c
drivers/net/ethernet/intel/ice/ice_switch.h

index e731b46..8736d3a 100644 (file)
@@ -1566,6 +1566,26 @@ static struct ice_buf_build *ice_pkg_buf_alloc(struct ice_hw *hw)
 }
 
 /**
+ * ice_get_sw_prof_type - determine switch profile type
+ * @hw: pointer to the HW structure
+ * @fv: pointer to the switch field vector
+ */
+static enum ice_prof_type
+ice_get_sw_prof_type(struct ice_hw *hw, struct ice_fv *fv)
+{
+       u16 i;
+
+       for (i = 0; i < hw->blk[ICE_BLK_SW].es.fvw; i++) {
+               /* UDP tunnel will have UDP_OF protocol ID and VNI offset */
+               if (fv->ew[i].prot_id == (u8)ICE_PROT_UDP_OF &&
+                   fv->ew[i].off == ICE_VNI_OFFSET)
+                       return ICE_PROF_TUN_UDP;
+       }
+
+       return ICE_PROF_NON_TUN;
+}
+
+/**
  * ice_get_sw_fv_bitmap - Get switch field vector bitmap based on profile type
  * @hw: pointer to hardware structure
  * @req_profs: type of profiles requested
@@ -1588,6 +1608,7 @@ ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type req_profs,
        bitmap_zero(bm, ICE_MAX_NUM_PROFILES);
        ice_seg = hw->seg;
        do {
+               enum ice_prof_type prof_type;
                u32 offset;
 
                fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
@@ -1595,7 +1616,10 @@ ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type req_profs,
                ice_seg = NULL;
 
                if (fv) {
-                       if (req_profs & ICE_PROF_NON_TUN)
+                       /* Determine field vector type */
+                       prof_type = ice_get_sw_prof_type(hw, fv);
+
+                       if (req_profs & prof_type)
                                set_bit((u16)offset, bm);
                }
        } while (fv);
index 120bceb..07d3795 100644 (file)
@@ -614,6 +614,8 @@ struct ice_chs_chg {
 
 enum ice_prof_type {
        ICE_PROF_NON_TUN = 0x1,
+       ICE_PROF_TUN_UDP = 0x2,
+       ICE_PROF_TUN_ALL = 0x6,
        ICE_PROF_ALL = 0xFF,
 };
 #endif /* _ICE_FLEX_TYPE_H_ */
index d717d11..8309eca 100644 (file)
@@ -48,6 +48,7 @@ enum ice_sw_tunnel_type {
        ICE_NON_TUN = 0,
        ICE_SW_TUN_VXLAN,
        ICE_SW_TUN_GENEVE,
+       ICE_ALL_TUNNELS /* All tunnel types */
 };
 
 /* Decoders for ice_prot_id:
@@ -83,6 +84,8 @@ enum ice_prot_id {
        ICE_PROT_INVALID        = 255  /* when offset == ICE_FV_OFFSET_INVAL */
 };
 
+#define ICE_VNI_OFFSET         12 /* offset of VNI from ICE_PROT_UDP_OF */
+
 #define ICE_MAC_OFOS_HW                1
 #define ICE_MAC_IL_HW          4
 #define ICE_ETYPE_OL_HW                9
@@ -96,6 +99,12 @@ enum ice_prot_id {
 #define ICE_UDP_ILOS_HW                53
 
 #define ICE_UDP_OF_HW  52 /* UDP Tunnels */
+#define ICE_META_DATA_ID_HW 255 /* this is used for tunnel type */
+
+#define ICE_MDID_SIZE 2
+#define ICE_TUN_FLAG_MDID 21
+#define ICE_TUN_FLAG_MDID_OFF (ICE_MDID_SIZE * ICE_TUN_FLAG_MDID)
+#define ICE_TUN_FLAG_MASK 0xFF
 
 #define ICE_TUN_FLAG_FV_IND 2
 
index 2742e1c..a2dfe8e 100644 (file)
@@ -35,6 +35,105 @@ struct ice_dummy_pkt_offsets {
        u16 offset; /* ICE_PROTOCOL_LAST indicates end of list */
 };
 
+static const struct ice_dummy_pkt_offsets dummy_udp_tun_tcp_packet_offsets[] = {
+       { ICE_MAC_OFOS,         0 },
+       { ICE_ETYPE_OL,         12 },
+       { ICE_IPV4_OFOS,        14 },
+       { ICE_UDP_OF,           34 },
+       { ICE_VXLAN,            42 },
+       { ICE_GENEVE,           42 },
+       { ICE_VXLAN_GPE,        42 },
+       { ICE_MAC_IL,           50 },
+       { ICE_IPV4_IL,          64 },
+       { ICE_TCP_IL,           84 },
+       { ICE_PROTOCOL_LAST,    0 },
+};
+
+static const u8 dummy_udp_tun_tcp_packet[] = {
+       0x00, 0x00, 0x00, 0x00,  /* ICE_MAC_OFOS 0 */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x08, 0x00,             /* ICE_ETYPE_OL 12 */
+
+       0x45, 0x00, 0x00, 0x5a, /* ICE_IPV4_OFOS 14 */
+       0x00, 0x01, 0x00, 0x00,
+       0x40, 0x11, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x00, 0x00, 0x12, 0xb5, /* ICE_UDP_OF 34 */
+       0x00, 0x46, 0x00, 0x00,
+
+       0x00, 0x00, 0x65, 0x58, /* ICE_VXLAN 42 */
+       0x00, 0x00, 0x00, 0x00,
+
+       0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 50 */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x08, 0x00,
+
+       0x45, 0x00, 0x00, 0x28, /* ICE_IPV4_IL 64 */
+       0x00, 0x01, 0x00, 0x00,
+       0x40, 0x06, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 84 */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x50, 0x02, 0x20, 0x00,
+       0x00, 0x00, 0x00, 0x00
+};
+
+static const struct ice_dummy_pkt_offsets dummy_udp_tun_udp_packet_offsets[] = {
+       { ICE_MAC_OFOS,         0 },
+       { ICE_ETYPE_OL,         12 },
+       { ICE_IPV4_OFOS,        14 },
+       { ICE_UDP_OF,           34 },
+       { ICE_VXLAN,            42 },
+       { ICE_GENEVE,           42 },
+       { ICE_VXLAN_GPE,        42 },
+       { ICE_MAC_IL,           50 },
+       { ICE_IPV4_IL,          64 },
+       { ICE_UDP_ILOS,         84 },
+       { ICE_PROTOCOL_LAST,    0 },
+};
+
+static const u8 dummy_udp_tun_udp_packet[] = {
+       0x00, 0x00, 0x00, 0x00,  /* ICE_MAC_OFOS 0 */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x08, 0x00,             /* ICE_ETYPE_OL 12 */
+
+       0x45, 0x00, 0x00, 0x4e, /* ICE_IPV4_OFOS 14 */
+       0x00, 0x01, 0x00, 0x00,
+       0x00, 0x11, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x00, 0x00, 0x12, 0xb5, /* ICE_UDP_OF 34 */
+       0x00, 0x3a, 0x00, 0x00,
+
+       0x00, 0x00, 0x65, 0x58, /* ICE_VXLAN 42 */
+       0x00, 0x00, 0x00, 0x00,
+
+       0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 50 */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x08, 0x00,
+
+       0x45, 0x00, 0x00, 0x1c, /* ICE_IPV4_IL 64 */
+       0x00, 0x01, 0x00, 0x00,
+       0x00, 0x11, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 84 */
+       0x00, 0x08, 0x00, 0x00,
+};
+
 /* offset info for MAC + IPv4 + UDP dummy packet */
 static const struct ice_dummy_pkt_offsets dummy_udp_packet_offsets[] = {
        { ICE_MAC_OFOS,         0 },
@@ -3582,6 +3681,8 @@ static const struct ice_prot_ext_tbl_entry ice_prot_ext[ICE_PROTOCOL_LAST] = {
        { ICE_TCP_IL,           { 0, 2 } },
        { ICE_UDP_OF,           { 0, 2 } },
        { ICE_UDP_ILOS,         { 0, 2 } },
+       { ICE_VXLAN,            { 8, 10, 12, 14 } },
+       { ICE_GENEVE,           { 8, 10, 12, 14 } },
 };
 
 static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = {
@@ -3596,6 +3697,8 @@ static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = {
        { ICE_TCP_IL,           ICE_TCP_IL_HW },
        { ICE_UDP_OF,           ICE_UDP_OF_HW },
        { ICE_UDP_ILOS,         ICE_UDP_ILOS_HW },
+       { ICE_VXLAN,            ICE_UDP_OF_HW },
+       { ICE_GENEVE,           ICE_UDP_OF_HW },
 };
 
 /**
@@ -3915,12 +4018,11 @@ ice_find_free_recp_res_idx(struct ice_hw *hw, const unsigned long *profiles,
  * ice_add_sw_recipe - function to call AQ calls to create switch recipe
  * @hw: pointer to hardware structure
  * @rm: recipe management list entry
- * @match_tun_mask: tunnel mask that needs to be programmed
  * @profiles: bitmap of profiles that will be associated.
  */
 static enum ice_status
 ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
-                 u16 match_tun_mask, unsigned long *profiles)
+                 unsigned long *profiles)
 {
        DECLARE_BITMAP(result_idx_bm, ICE_MAX_FV_WORDS);
        struct ice_aqc_recipe_data_elem *tmp;
@@ -4128,15 +4230,6 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
                }
                buf[recps].content.act_ctrl_fwd_priority = rm->priority;
 
-               /* To differentiate among different UDP tunnels, a meta data ID
-                * flag is used.
-                */
-               if (match_tun_mask) {
-                       buf[recps].content.lkup_indx[i] = ICE_TUN_FLAG_FV_IND;
-                       buf[recps].content.mask[i] =
-                               cpu_to_le16(match_tun_mask);
-               }
-
                recps++;
                rm->root_rid = (u8)rid;
        }
@@ -4199,6 +4292,7 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
                recp->chain_idx = entry->chain_idx;
                recp->priority = buf[buf_idx].content.act_ctrl_fwd_priority;
                recp->n_grp_count = rm->n_grp_count;
+               recp->tun_type = rm->tun_type;
                recp->recp_created = true;
        }
        rm->root_buf = buf;
@@ -4279,6 +4373,54 @@ free_mem:
        return status;
 }
 
+/**
+ * ice_tun_type_match_word - determine if tun type needs a match mask
+ * @tun_type: tunnel type
+ * @mask: mask to be used for the tunnel
+ */
+static bool ice_tun_type_match_word(enum ice_sw_tunnel_type tun_type, u16 *mask)
+{
+       switch (tun_type) {
+       case ICE_SW_TUN_GENEVE:
+       case ICE_SW_TUN_VXLAN:
+               *mask = ICE_TUN_FLAG_MASK;
+               return true;
+
+       default:
+               *mask = 0;
+               return false;
+       }
+}
+
+/**
+ * ice_add_special_words - Add words that are not protocols, such as metadata
+ * @rinfo: other information regarding the rule e.g. priority and action info
+ * @lkup_exts: lookup word structure
+ */
+static enum ice_status
+ice_add_special_words(struct ice_adv_rule_info *rinfo,
+                     struct ice_prot_lkup_ext *lkup_exts)
+{
+       u16 mask;
+
+       /* If this is a tunneled packet, then add recipe index to match the
+        * tunnel bit in the packet metadata flags.
+        */
+       if (ice_tun_type_match_word(rinfo->tun_type, &mask)) {
+               if (lkup_exts->n_val_words < ICE_MAX_CHAIN_WORDS) {
+                       u8 word = lkup_exts->n_val_words++;
+
+                       lkup_exts->fv_words[word].prot_id = ICE_META_DATA_ID_HW;
+                       lkup_exts->fv_words[word].off = ICE_TUN_FLAG_MDID_OFF;
+                       lkup_exts->field_mask[word] = mask;
+               } else {
+                       return ICE_ERR_MAX_LIMIT;
+               }
+       }
+
+       return 0;
+}
+
 /* ice_get_compat_fv_bitmap - Get compatible field vector bitmap for rule
  * @hw: pointer to hardware structure
  * @rinfo: other information regarding the rule e.g. priority and action info
@@ -4288,9 +4430,27 @@ static void
 ice_get_compat_fv_bitmap(struct ice_hw *hw, struct ice_adv_rule_info *rinfo,
                         unsigned long *bm)
 {
+       enum ice_prof_type prof_type;
+
        bitmap_zero(bm, ICE_MAX_NUM_PROFILES);
 
-       ice_get_sw_fv_bitmap(hw, ICE_PROF_NON_TUN, bm);
+       switch (rinfo->tun_type) {
+       case ICE_NON_TUN:
+               prof_type = ICE_PROF_NON_TUN;
+               break;
+       case ICE_ALL_TUNNELS:
+               prof_type = ICE_PROF_TUN_ALL;
+               break;
+       case ICE_SW_TUN_GENEVE:
+       case ICE_SW_TUN_VXLAN:
+               prof_type = ICE_PROF_TUN_UDP;
+               break;
+       default:
+               prof_type = ICE_PROF_ALL;
+               break;
+       }
+
+       ice_get_sw_fv_bitmap(hw, prof_type, bm);
 }
 
 /**
@@ -4315,7 +4475,6 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
        struct ice_sw_fv_list_entry *tmp;
        enum ice_status status = 0;
        struct ice_sw_recipe *rm;
-       u16 match_tun_mask = 0;
        u8 i;
 
        if (!lkups_cnt)
@@ -4365,6 +4524,13 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
        if (status)
                goto err_unroll;
 
+       /* Create any special protocol/offset pairs, such as looking at tunnel
+        * bits by extracting metadata
+        */
+       status = ice_add_special_words(rinfo, lkup_exts);
+       if (status)
+               goto err_free_lkup_exts;
+
        /* Group match words into recipes using preferred recipe grouping
         * criteria.
         */
@@ -4396,7 +4562,7 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
                goto err_unroll;
 
        /* Recipe we need does not exist, add a recipe */
-       status = ice_add_sw_recipe(hw, rm, match_tun_mask, profiles);
+       status = ice_add_sw_recipe(hw, rm, profiles);
        if (status)
                goto err_unroll;
 
@@ -4466,12 +4632,14 @@ err_free_lkup_exts:
  * @lkups: lookup elements or match criteria for the advanced recipe, one
  *        structure per protocol header
  * @lkups_cnt: number of protocols
+ * @tun_type: tunnel type
  * @pkt: dummy packet to fill according to filter match criteria
  * @pkt_len: packet length of dummy packet
  * @offsets: pointer to receive the pointer to the offsets for the packet
  */
 static void
 ice_find_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
+                     enum ice_sw_tunnel_type tun_type,
                      const u8 **pkt, u16 *pkt_len,
                      const struct ice_dummy_pkt_offsets **offsets)
 {
@@ -4495,6 +4663,21 @@ ice_find_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
                        ipv6 = true;
        }
 
+       if (tun_type == ICE_SW_TUN_VXLAN ||
+           tun_type == ICE_SW_TUN_GENEVE) {
+               if (tcp) {
+                       *pkt = dummy_udp_tun_tcp_packet;
+                       *pkt_len = sizeof(dummy_udp_tun_tcp_packet);
+                       *offsets = dummy_udp_tun_tcp_packet_offsets;
+                       return;
+               }
+
+               *pkt = dummy_udp_tun_udp_packet;
+               *pkt_len = sizeof(dummy_udp_tun_udp_packet);
+               *offsets = dummy_udp_tun_udp_packet_offsets;
+               return;
+       }
+
        if (udp && !ipv6) {
                if (vlan) {
                        *pkt = dummy_vlan_udp_packet;
@@ -4615,6 +4798,10 @@ ice_fill_adv_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
                case ICE_SCTP_IL:
                        len = sizeof(struct ice_sctp_hdr);
                        break;
+               case ICE_VXLAN:
+               case ICE_GENEVE:
+                       len = sizeof(struct ice_udp_tnl_hdr);
+                       break;
                default:
                        return ICE_ERR_PARAM;
                }
@@ -4645,6 +4832,48 @@ ice_fill_adv_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
 }
 
 /**
+ * ice_fill_adv_packet_tun - fill dummy packet with udp tunnel port
+ * @hw: pointer to the hardware structure
+ * @tun_type: tunnel type
+ * @pkt: dummy packet to fill in
+ * @offsets: offset info for the dummy packet
+ */
+static enum ice_status
+ice_fill_adv_packet_tun(struct ice_hw *hw, enum ice_sw_tunnel_type tun_type,
+                       u8 *pkt, const struct ice_dummy_pkt_offsets *offsets)
+{
+       u16 open_port, i;
+
+       switch (tun_type) {
+       case ICE_SW_TUN_VXLAN:
+       case ICE_SW_TUN_GENEVE:
+               if (!ice_get_open_tunnel_port(hw, &open_port))
+                       return ICE_ERR_CFG;
+               break;
+
+       default:
+               /* Nothing needs to be done for this tunnel type */
+               return 0;
+       }
+
+       /* Find the outer UDP protocol header and insert the port number */
+       for (i = 0; offsets[i].type != ICE_PROTOCOL_LAST; i++) {
+               if (offsets[i].type == ICE_UDP_OF) {
+                       struct ice_l4_hdr *hdr;
+                       u16 offset;
+
+                       offset = offsets[i].offset;
+                       hdr = (struct ice_l4_hdr *)&pkt[offset];
+                       hdr->dst_port = cpu_to_be16(open_port);
+
+                       return 0;
+               }
+       }
+
+       return ICE_ERR_CFG;
+}
+
+/**
  * ice_find_adv_rule_entry - Search a rule entry
  * @hw: pointer to the hardware structure
  * @lkups: lookup elements or match criteria for the advanced recipe, one
@@ -4678,6 +4907,7 @@ ice_find_adv_rule_entry(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
                                break;
                        }
                if (rinfo->sw_act.flag == list_itr->rule_info.sw_act.flag &&
+                   rinfo->tun_type == list_itr->rule_info.tun_type &&
                    lkups_matched)
                        return list_itr;
        }
@@ -4852,7 +5082,7 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
                return ICE_ERR_PARAM;
 
        /* make sure that we can locate a dummy packet */
-       ice_find_dummy_packet(lkups, lkups_cnt, &pkt, &pkt_len,
+       ice_find_dummy_packet(lkups, lkups_cnt, rinfo->tun_type, &pkt, &pkt_len,
                              &pkt_offsets);
        if (!pkt) {
                status = ICE_ERR_PARAM;
@@ -4963,6 +5193,14 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
        if (status)
                goto err_ice_add_adv_rule;
 
+       if (rinfo->tun_type != ICE_NON_TUN) {
+               status = ice_fill_adv_packet_tun(hw, rinfo->tun_type,
+                                                s_rule->pdata.lkup_tx_rx.hdr,
+                                                pkt_offsets);
+               if (status)
+                       goto err_ice_add_adv_rule;
+       }
+
        status = ice_aq_sw_rules(hw, (struct ice_aqc_sw_rules *)s_rule,
                                 rule_buf_sz, 1, ice_aqc_opc_add_sw_rules,
                                 NULL);
@@ -5198,6 +5436,13 @@ ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
                        return ICE_ERR_CFG;
        }
 
+       /* Create any special protocol/offset pairs, such as looking at tunnel
+        * bits by extracting metadata
+        */
+       status = ice_add_special_words(rinfo, &lkup_exts);
+       if (status)
+               return status;
+
        rid = ice_find_recp(hw, &lkup_exts);
        /* If did not find a recipe that match the existing criteria */
        if (rid == ICE_MAX_NUM_RECIPES)
index 7d661c9..d8a3890 100644 (file)
@@ -212,6 +212,8 @@ struct ice_sw_recipe {
        /* Bit map specifying the IDs associated with this group of recipe */
        DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES);
 
+       enum ice_sw_tunnel_type tun_type;
+
        /* List of type ice_fltr_mgmt_list_entry or adv_rule */
        u8 adv_rule;
        struct list_head filt_rules;