> -----Original Message-----
> From: Intel-wired-lan <[email protected]> On Behalf Of
> Aleksandr Loktionov
> Sent: Monday, September 15, 2025 3:39 PM
> To: [email protected]; [email protected]; Schmidt, Michal
> <[email protected]>; Nguyen, Anthony L
> <[email protected]>; Loktionov, Aleksandr
> <[email protected]>
> Cc: Nowlin, Dan <[email protected]>; Zhang, Qi Z
> <[email protected]>; Kitszel, Przemyslaw <[email protected]>;
> Simon Horman <[email protected]>
> Subject: [Intel-wired-lan] [PATCH iwl-next v5 2/5] ice: add virtchnl and VF
> context support for GTP RSS
> 
> Introduce infrastructure to support GTP-specific RSS configuration
> in the ICE driver, enabling flexible and programmable flow hashing
> on virtual functions (VFs).
> 
>  - Define new virtchnl protocol header and field types for GTPC, GTPU,
>    L2TPv2, ECPRI, PPP, GRE, and IP fragment headers.
>  - Extend virtchnl.h to support additional RSS fields including checksums,
>    TEID, QFI, and IPv6 prefix matching.
>  - Add VF-side hash context structures for IPv4/IPv6 and GTPU flows.
>  - Implement context tracking and rule ordering logic for TCAM-based
>    RSS configuration.
>  - Introduce symmetric hashing support for raw and tunnel flows.
>  - Update ice_vf_lib.h and virt/rss.c to handle advanced RSS
>    configuration via virtchnl messages.
> 
> VFs can express RSS configuration for GTP flows
> using ethtool and virtchnl, laying the foundation for tunnel-aware
> RSS offloads in virtualized environments.
> 
> Co-developed-by: Dan Nowlin <[email protected]>
> Signed-off-by: Dan Nowlin <[email protected]>
> Co-developed-by: Jie Wang <[email protected]>
> Signed-off-by: Jie Wang <[email protected]>
> Co-developed-by: Junfeng Guo <[email protected]>
> Signed-off-by: Junfeng Guo <[email protected]>
> Co-developed-by: Qi Zhang <[email protected]>
> Signed-off-by: Qi Zhang <[email protected]>
> Co-developed-by: Ting Xu <[email protected]>
> Signed-off-by: Ting Xu <[email protected]>
> Signed-off-by: Przemek Kitszel <[email protected]>
> Reviewed-by: Simon Horman <[email protected]>
> Signed-off-by: Aleksandr Loktionov <[email protected]>
> ---
>  drivers/net/ethernet/intel/ice/ice_parser.c |    3 +
>  drivers/net/ethernet/intel/ice/ice_vf_lib.h |   48 +
>  drivers/net/ethernet/intel/ice/virt/rss.c   | 1307 ++++++++++++++++++-
>  include/linux/avf/virtchnl.h                |   50 +
>  4 files changed, 1353 insertions(+), 55 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/ice/ice_parser.c
> b/drivers/net/ethernet/intel/ice/ice_parser.c
> index 664beb6..a8fec1c 100644
> --- a/drivers/net/ethernet/intel/ice/ice_parser.c
> +++ b/drivers/net/ethernet/intel/ice/ice_parser.c
> @@ -2115,6 +2115,9 @@ struct ice_parser *ice_parser_create(struct ice_hw
> *hw)
>   */
>  void ice_parser_destroy(struct ice_parser *psr)
>  {
> +     if (!psr)
> +             return;
> +
>       kfree(psr->imem_table);
>       kfree(psr->mi_table);
>       kfree(psr->pg_cam_table);
> diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h
> b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
> index b007089..7a9c75d 100644
> --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h
> +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
> @@ -53,6 +53,46 @@ struct ice_mdd_vf_events {
>       u16 last_printed;
>  };
> 
> +enum ice_hash_ip_ctx_type {
> +     ICE_HASH_IP_CTX_IP = 0,
> +     ICE_HASH_IP_CTX_IP_ESP,
> +     ICE_HASH_IP_CTX_IP_UDP_ESP,
> +     ICE_HASH_IP_CTX_IP_AH,
> +     ICE_HASH_IP_CTX_IP_PFCP,
> +     ICE_HASH_IP_CTX_IP_UDP,
> +     ICE_HASH_IP_CTX_IP_TCP,
> +     ICE_HASH_IP_CTX_IP_SCTP,
> +     ICE_HASH_IP_CTX_MAX,
> +};
> +
> +struct ice_vf_hash_ip_ctx {
> +     struct ice_rss_hash_cfg ctx[ICE_HASH_IP_CTX_MAX];
> +};
> +
> +enum ice_hash_gtpu_ctx_type {
> +     ICE_HASH_GTPU_CTX_EH_IP = 0,
> +     ICE_HASH_GTPU_CTX_EH_IP_UDP,
> +     ICE_HASH_GTPU_CTX_EH_IP_TCP,
> +     ICE_HASH_GTPU_CTX_UP_IP,
> +     ICE_HASH_GTPU_CTX_UP_IP_UDP,
> +     ICE_HASH_GTPU_CTX_UP_IP_TCP,
> +     ICE_HASH_GTPU_CTX_DW_IP,
> +     ICE_HASH_GTPU_CTX_DW_IP_UDP,
> +     ICE_HASH_GTPU_CTX_DW_IP_TCP,
> +     ICE_HASH_GTPU_CTX_MAX,
> +};
> +
> +struct ice_vf_hash_gtpu_ctx {
> +     struct ice_rss_hash_cfg ctx[ICE_HASH_GTPU_CTX_MAX];
> +};
> +
> +struct ice_vf_hash_ctx {
> +     struct ice_vf_hash_ip_ctx v4;
> +     struct ice_vf_hash_ip_ctx v6;
> +     struct ice_vf_hash_gtpu_ctx ipv4;
> +     struct ice_vf_hash_gtpu_ctx ipv6;
> +};
> +
>  /* Structure to store fdir fv entry */
>  struct ice_fdir_prof_info {
>       struct ice_parser_profile prof;
> @@ -66,6 +106,12 @@ struct ice_vf_qs_bw {
>       u8 tc;
>  };
> 
> +/* Structure to store RSS field vector entry */
> +struct ice_rss_prof_info {
> +     struct ice_parser_profile prof;
> +     bool symm;
> +};
> +
>  /* VF operations */
>  struct ice_vf_ops {
>       enum ice_disq_rst_src reset_type;
> @@ -106,6 +152,8 @@ struct ice_vf {
>       u16 ctrl_vsi_idx;
>       struct ice_vf_fdir fdir;
>       struct ice_fdir_prof_info fdir_prof_info[ICE_MAX_PTGS];
> +     struct ice_rss_prof_info rss_prof_info[ICE_MAX_PTGS];
> +     struct ice_vf_hash_ctx hash_ctx;
>       u64 rss_hashcfg;                /* RSS hash configuration */
>       struct ice_sw *vf_sw_id;        /* switch ID the VF VSIs connect to */
>       struct virtchnl_version_info vf_ver;
> diff --git a/drivers/net/ethernet/intel/ice/virt/rss.c
> b/drivers/net/ethernet/intel/ice/virt/rss.c
> index cbdbb32..1f3bed9 100644
> --- a/drivers/net/ethernet/intel/ice/virt/rss.c
> +++ b/drivers/net/ethernet/intel/ice/virt/rss.c
> @@ -36,6 +36,11 @@ static const struct ice_vc_hdr_match_type
> ice_vc_hdr_list[] = {
>       {VIRTCHNL_PROTO_HDR_ESP,        ICE_FLOW_SEG_HDR_ESP},
>       {VIRTCHNL_PROTO_HDR_AH,         ICE_FLOW_SEG_HDR_AH},
>       {VIRTCHNL_PROTO_HDR_PFCP,
>       ICE_FLOW_SEG_HDR_PFCP_SESSION},
> +     {VIRTCHNL_PROTO_HDR_GTPC,       ICE_FLOW_SEG_HDR_GTPC},
> +     {VIRTCHNL_PROTO_HDR_L2TPV2,
>       ICE_FLOW_SEG_HDR_L2TPV2},
> +     {VIRTCHNL_PROTO_HDR_IPV4_FRAG,
>       ICE_FLOW_SEG_HDR_IPV_FRAG},
> +     {VIRTCHNL_PROTO_HDR_IPV6_EH_FRAG,
>       ICE_FLOW_SEG_HDR_IPV_FRAG},
> +     {VIRTCHNL_PROTO_HDR_GRE,        ICE_FLOW_SEG_HDR_GRE},
>  };
> 
>  struct ice_vc_hash_field_match_type {
> @@ -87,8 +92,125 @@ ice_vc_hash_field_match_type
> ice_vc_hash_field_list[] = {
>               FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
>               FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT),
>               ICE_FLOW_HASH_IPV4 |
> BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)},
> -     {VIRTCHNL_PROTO_HDR_IPV4,
> FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT),
> +     {VIRTCHNL_PROTO_HDR_IPV4,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_FRAG_PKID),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_ID)},
> +     {VIRTCHNL_PROTO_HDR_IPV4,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_IPV4,
> FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_IPV4,
> FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_IPV4,
> FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
> +             ICE_FLOW_HASH_IPV4 |
> BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_IPV4,
> FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_IPV4,
> FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_IPV4,
> FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
> +             ICE_FLOW_HASH_IPV4 |
> BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_IPV4,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_IPV4_FRAG,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)},
> +     {VIRTCHNL_PROTO_HDR_IPV4_FRAG,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA)},
> +     {VIRTCHNL_PROTO_HDR_IPV4_FRAG,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA)},
> +     {VIRTCHNL_PROTO_HDR_IPV4_FRAG,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST),
> +             ICE_FLOW_HASH_IPV4},
> +     {VIRTCHNL_PROTO_HDR_IPV4_FRAG,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)},
> +     {VIRTCHNL_PROTO_HDR_IPV4_FRAG,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA) |
>               BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)},
> +     {VIRTCHNL_PROTO_HDR_IPV4_FRAG,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT),
> +             ICE_FLOW_HASH_IPV4 |
> BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)},
> +     {VIRTCHNL_PROTO_HDR_IPV4_FRAG,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)},
> +     {VIRTCHNL_PROTO_HDR_IPV4_FRAG,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_FRAG_PKID),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_ID)},
> +     {VIRTCHNL_PROTO_HDR_IPV4_FRAG,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_IPV4_FRAG,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_IPV4_FRAG,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_IPV4_FRAG,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
> +             ICE_FLOW_HASH_IPV4 |
> BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_IPV4_FRAG,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_IPV4_FRAG,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_IPV4_FRAG,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
> +             ICE_FLOW_HASH_IPV4 |
> BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_IPV4_FRAG,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
>       {VIRTCHNL_PROTO_HDR_IPV6,
> FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_SRC),
>               BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA)},
>       {VIRTCHNL_PROTO_HDR_IPV6,
> FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_DST),
> @@ -110,6 +232,35 @@ ice_vc_hash_field_match_type
> ice_vc_hash_field_list[] = {
>               ICE_FLOW_HASH_IPV6 |
> BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)},
>       {VIRTCHNL_PROTO_HDR_IPV6,
> FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT),
>               BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)},
> +     {VIRTCHNL_PROTO_HDR_IPV6_EH_FRAG,
> +
>       FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_EH_FRAG_PKID),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_ID)},
> +     {VIRTCHNL_PROTO_HDR_IPV6,
> +
>       FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PREFIX64_SRC) |
> +
>       FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PREFIX64_DST),
> +             ICE_FLOW_HASH_IPV6_PRE64},
> +     {VIRTCHNL_PROTO_HDR_IPV6,
> +
>       FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PREFIX64_SRC),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PRE64_SA)},
> +     {VIRTCHNL_PROTO_HDR_IPV6,
> +
>       FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PREFIX64_DST),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PRE64_DA)},
> +     {VIRTCHNL_PROTO_HDR_IPV6,
> +
>       FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PREFIX64_SRC) |
> +
>       FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PREFIX64_DST) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT),
> +             ICE_FLOW_HASH_IPV6_PRE64 |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)},
> +     {VIRTCHNL_PROTO_HDR_IPV6,
> +
>       FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PREFIX64_SRC) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PRE64_SA) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)},
> +     {VIRTCHNL_PROTO_HDR_IPV6,
> +
>       FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PREFIX64_DST) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PRE64_DA) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)},
>       {VIRTCHNL_PROTO_HDR_TCP,
>               FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_SRC_PORT),
>               BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_SRC_PORT)},
> @@ -120,6 +271,25 @@ ice_vc_hash_field_match_type
> ice_vc_hash_field_list[] = {
>               FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_SRC_PORT) |
>               FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_DST_PORT),
>               ICE_FLOW_HASH_TCP_PORT},
> +     {VIRTCHNL_PROTO_HDR_TCP,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_TCP,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_SRC_PORT) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_SRC_PORT) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_TCP,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_DST_PORT) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_DST_PORT) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_TCP,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_SRC_PORT) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_DST_PORT) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_CHKSUM),
> +             ICE_FLOW_HASH_TCP_PORT |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_CHKSUM)},
>       {VIRTCHNL_PROTO_HDR_UDP,
>               FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_SRC_PORT),
>               BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_SRC_PORT)},
> @@ -130,6 +300,25 @@ ice_vc_hash_field_match_type
> ice_vc_hash_field_list[] = {
>               FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_SRC_PORT) |
>               FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_DST_PORT),
>               ICE_FLOW_HASH_UDP_PORT},
> +     {VIRTCHNL_PROTO_HDR_UDP,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_UDP,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_SRC_PORT) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_SRC_PORT) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_UDP,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_DST_PORT) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_DST_PORT) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_UDP,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_SRC_PORT) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_DST_PORT) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_CHKSUM),
> +             ICE_FLOW_HASH_UDP_PORT |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_CHKSUM)},
>       {VIRTCHNL_PROTO_HDR_SCTP,
>               FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_SRC_PORT),
>               BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT)},
> @@ -140,6 +329,25 @@ ice_vc_hash_field_match_type
> ice_vc_hash_field_list[] = {
>               FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_SRC_PORT) |
>               FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_DST_PORT),
>               ICE_FLOW_HASH_SCTP_PORT},
> +     {VIRTCHNL_PROTO_HDR_SCTP,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_SCTP,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_SRC_PORT) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_SCTP,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_DST_PORT) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_CHKSUM),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_DST_PORT) |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_CHKSUM)},
> +     {VIRTCHNL_PROTO_HDR_SCTP,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_SRC_PORT) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_DST_PORT) |
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_CHKSUM),
> +             ICE_FLOW_HASH_SCTP_PORT |
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_CHKSUM)},
>       {VIRTCHNL_PROTO_HDR_PPPOE,
>               FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_PPPOE_SESS_ID),
>               BIT_ULL(ICE_FLOW_FIELD_IDX_PPPOE_SESS_ID)},
> @@ -155,8 +363,56 @@ ice_vc_hash_field_match_type
> ice_vc_hash_field_list[] = {
>               BIT_ULL(ICE_FLOW_FIELD_IDX_AH_SPI)},
>       {VIRTCHNL_PROTO_HDR_PFCP,
> FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_PFCP_SEID),
>               BIT_ULL(ICE_FLOW_FIELD_IDX_PFCP_SEID)},
> +     {VIRTCHNL_PROTO_HDR_GTPC,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_GTPC_TEID),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_GTPC_TEID)},
> +     {VIRTCHNL_PROTO_HDR_L2TPV2,
> +             FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_L2TPV2_SESS_ID),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_L2TPV2_SESS_ID)},
> +     {VIRTCHNL_PROTO_HDR_L2TPV2,
> +
>       FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_L2TPV2_LEN_SESS_ID),
> +             BIT_ULL(ICE_FLOW_FIELD_IDX_L2TPV2_LEN_SESS_ID)},
>  };
> 
> +static enum virtchnl_status_code
> +ice_vc_rss_hash_update(struct ice_hw *hw, struct ice_vsi *vsi, u8 hash_type)
> +{
> +     enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
> +     struct ice_vsi_ctx *ctx;
> +     int ret;
> +
> +     ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> +     if (!ctx)
> +             return VIRTCHNL_STATUS_ERR_NO_MEMORY;
> +
> +     /* clear previous hash_type */
> +     ctx->info.q_opt_rss = vsi->info.q_opt_rss &
> +             ~ICE_AQ_VSI_Q_OPT_RSS_HASH_M;
> +     /* hash_type is passed in as
> ICE_AQ_VSI_Q_OPT_RSS_<XOR|TPLZ|SYM_TPLZ */
> +     ctx->info.q_opt_rss |=
> FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_HASH_M,
> +                                       hash_type);
> +
> +     /* Preserve existing queueing option setting */
> +     ctx->info.q_opt_tc = vsi->info.q_opt_tc;
> +     ctx->info.q_opt_flags = vsi->info.q_opt_flags;
> +
> +     ctx->info.valid_sections =
> +                     cpu_to_le16(ICE_AQ_VSI_PROP_Q_OPT_VALID);
> +
> +     ret = ice_update_vsi(hw, vsi->idx, ctx, NULL);
> +     if (ret) {
> +             dev_err(ice_hw_to_dev(hw), "update VSI for RSS failed, err
> %d aq_err %s\n",
> +                     ret, libie_aq_str(hw->adminq.sq_last_status));
> +             v_ret = VIRTCHNL_STATUS_ERR_PARAM;
> +     } else {
> +             vsi->info.q_opt_rss = ctx->info.q_opt_rss;
> +     }
> +
> +     kfree(ctx);
> +
> +     return v_ret;
> +}
> +
>  /**
>   * ice_vc_validate_pattern
>   * @vf: pointer to the VF info
> @@ -271,6 +527,11 @@ static bool ice_vc_parse_rss_cfg(struct ice_hw *hw,
>       const struct ice_vc_hash_field_match_type *hf_list;
>       const struct ice_vc_hdr_match_type *hdr_list;
>       int i, hf_list_len, hdr_list_len;
> +     bool outer_ipv4 = false;
> +     bool outer_ipv6 = false;
> +     bool inner_hdr = false;
> +     bool has_gre = false;
> +
>       u32 *addl_hdrs = &hash_cfg->addl_hdrs;
>       u64 *hash_flds = &hash_cfg->hash_flds;
> 
> @@ -290,17 +551,17 @@ static bool ice_vc_parse_rss_cfg(struct ice_hw *hw,
>       for (i = 0; i < rss_cfg->proto_hdrs.count; i++) {
>               struct virtchnl_proto_hdr *proto_hdr =
>                                       &rss_cfg->proto_hdrs.proto_hdr[i];
> -             bool hdr_found = false;
> +             u32 hdr_found = 0;
>               int j;
> 
> -             /* Find matched ice headers according to virtchnl headers. */
> +             /* Find matched ice headers according to virtchnl headers.
> +              * Also figure out the outer type of GTPU headers.
> +              */
>               for (j = 0; j < hdr_list_len; j++) {
>                       struct ice_vc_hdr_match_type hdr_map = hdr_list[j];
> 
> -                     if (proto_hdr->type == hdr_map.vc_hdr) {
> -                             *addl_hdrs |= hdr_map.ice_hdr;
> -                             hdr_found = true;
> -                     }
> +                     if (proto_hdr->type == hdr_map.vc_hdr)
> +                             hdr_found = hdr_map.ice_hdr;
>               }
> 
>               if (!hdr_found)
> @@ -318,8 +579,98 @@ static bool ice_vc_parse_rss_cfg(struct ice_hw *hw,
>                               break;
>                       }
>               }
> +
> +             if (proto_hdr->type == VIRTCHNL_PROTO_HDR_IPV4 &&
> !inner_hdr)
> +                     outer_ipv4 = true;
> +             else if (proto_hdr->type == VIRTCHNL_PROTO_HDR_IPV6 &&
> +                      !inner_hdr)
> +                     outer_ipv6 = true;
> +             /* for GRE and L2TPv2, take inner header as input set if no
> +              * any field is selected from outer headers.
> +              * for GTPU, take inner header and GTPU teid as input set.
> +              */
> +             else if ((proto_hdr->type == VIRTCHNL_PROTO_HDR_GTPU_IP
> ||
> +                       proto_hdr->type ==
> VIRTCHNL_PROTO_HDR_GTPU_EH ||
> +                       proto_hdr->type ==
> VIRTCHNL_PROTO_HDR_GTPU_EH_PDU_DWN ||
> +                       proto_hdr->type ==
> +                             VIRTCHNL_PROTO_HDR_GTPU_EH_PDU_UP)
> ||
> +                      ((proto_hdr->type ==
> VIRTCHNL_PROTO_HDR_L2TPV2 ||
> +                        proto_hdr->type == VIRTCHNL_PROTO_HDR_GRE)
> &&
> +                        *hash_flds == 0)) {
> +                     /* set inner_hdr flag, and clean up outer header */
> +                     inner_hdr = true;
> +
> +                     /* clear outer headers */
> +                     *addl_hdrs = 0;
> +
> +                     if (outer_ipv4 && outer_ipv6)
> +                             return false;
> +
> +                     if (outer_ipv4)
> +                             hash_cfg->hdr_type =
> ICE_RSS_INNER_HEADERS_W_OUTER_IPV4;
> +                     else if (outer_ipv6)
> +                             hash_cfg->hdr_type =
> ICE_RSS_INNER_HEADERS_W_OUTER_IPV6;
> +                     else
> +                             hash_cfg->hdr_type =
> ICE_RSS_INNER_HEADERS;
> +
> +                     if (has_gre && outer_ipv4)
> +                             hash_cfg->hdr_type =
> +
>       ICE_RSS_INNER_HEADERS_W_OUTER_IPV4_GRE;
> +                     if (has_gre && outer_ipv6)
> +                             hash_cfg->hdr_type =
> +
>       ICE_RSS_INNER_HEADERS_W_OUTER_IPV6_GRE;
> +
> +                     if (proto_hdr->type == VIRTCHNL_PROTO_HDR_GRE)
> +                             has_gre = true;
> +             }
> +
> +             *addl_hdrs |= hdr_found;
> +
> +             /* refine hash hdrs and fields for IP fragment */
> +             if (VIRTCHNL_TEST_PROTO_HDR_FIELD(proto_hdr,
> +
> VIRTCHNL_PROTO_HDR_IPV4_FRAG_PKID) &&
> +                 proto_hdr->type == VIRTCHNL_PROTO_HDR_IPV4_FRAG) {
> +                     *addl_hdrs |= ICE_FLOW_SEG_HDR_IPV_FRAG;
> +                     *addl_hdrs &= ~(ICE_FLOW_SEG_HDR_IPV_OTHER);
> +                     *hash_flds |=
> BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_ID);
> +                     VIRTCHNL_DEL_PROTO_HDR_FIELD(proto_hdr,
> +
> VIRTCHNL_PROTO_HDR_IPV4_FRAG_PKID);
> +             }
> +             if (VIRTCHNL_TEST_PROTO_HDR_FIELD(proto_hdr,
> +
> VIRTCHNL_PROTO_HDR_IPV6_EH_FRAG_PKID) &&
> +                 proto_hdr->type ==
> VIRTCHNL_PROTO_HDR_IPV6_EH_FRAG) {
> +                     *addl_hdrs |= ICE_FLOW_SEG_HDR_IPV_FRAG;
> +                     *addl_hdrs &= ~(ICE_FLOW_SEG_HDR_IPV_OTHER);
> +                     *hash_flds |=
> BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_ID);
> +                     VIRTCHNL_DEL_PROTO_HDR_FIELD(proto_hdr,
> +
> VIRTCHNL_PROTO_HDR_IPV6_EH_FRAG_PKID);
> +             }
> +     }
> +
> +     /* refine gtpu header if we take outer as input set for a no inner
> +      * ip gtpu flow.
> +      */
> +     if (hash_cfg->hdr_type == ICE_RSS_OUTER_HEADERS &&
> +         *addl_hdrs & ICE_FLOW_SEG_HDR_GTPU_IP) {
> +             *addl_hdrs &= ~(ICE_FLOW_SEG_HDR_GTPU_IP);
> +             *addl_hdrs |= ICE_FLOW_SEG_HDR_GTPU_NON_IP;
> +     }
> +
> +     /* refine hash field for esp and nat-t-esp. */
> +     if ((*addl_hdrs & ICE_FLOW_SEG_HDR_UDP) &&
> +         (*addl_hdrs & ICE_FLOW_SEG_HDR_ESP)) {
> +             *addl_hdrs &= ~(ICE_FLOW_SEG_HDR_ESP |
> ICE_FLOW_SEG_HDR_UDP);
> +             *addl_hdrs |= ICE_FLOW_SEG_HDR_NAT_T_ESP;
> +             *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_ESP_SPI));
> +             *hash_flds |=
> BIT_ULL(ICE_FLOW_FIELD_IDX_NAT_T_ESP_SPI);
>       }
> 
> +     /* refine hash hdrs for L4 udp/tcp/sctp. */
> +     if (*addl_hdrs & (ICE_FLOW_SEG_HDR_TCP |
> ICE_FLOW_SEG_HDR_UDP |
> +                       ICE_FLOW_SEG_HDR_SCTP) &&
> +         *addl_hdrs & ICE_FLOW_SEG_HDR_IPV_OTHER)
> +             *addl_hdrs &= ~ICE_FLOW_SEG_HDR_IPV_OTHER;
> +
>       return true;
>  }
> 
> @@ -336,6 +687,871 @@ static bool ice_vf_adv_rss_offload_ena(u32 caps)
>       return !!(caps & VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF);
>  }
> 
> +/**
> + * ice_is_hash_cfg_valid - Check whether an RSS hash context is valid
> + * @cfg: RSS hash configuration to test
> + *
> + * Return: true if both @cfg->hash_flds and @cfg->addl_hdrs are non-zero;
> false otherwise.
> + */
> +static bool ice_is_hash_cfg_valid(struct ice_rss_hash_cfg *cfg)
> +{
> +     return cfg->hash_flds && cfg->addl_hdrs;
> +}
> +
> +/**
> + * ice_hash_cfg_reset - Reset an RSS hash context
> + * @cfg: RSS hash configuration to reset
> + *
> + * Reset fields of @cfg that store the active rule information.
> + */
> +static void ice_hash_cfg_reset(struct ice_rss_hash_cfg *cfg)
> +{
> +     cfg->hash_flds = 0;
> +     cfg->addl_hdrs = 0;
> +     cfg->hdr_type = ICE_RSS_OUTER_HEADERS;
> +     cfg->symm = 0;
> +}
> +
> +/**
> + * ice_hash_cfg_record - Record an RSS hash context
> + * @ctx: destination (global) RSS hash configuration
> + * @cfg: source RSS hash configuration to record
> + *
> + * Copy the active rule information from @cfg into @ctx.
> + */
> +static void ice_hash_cfg_record(struct ice_rss_hash_cfg *ctx,
> +                             struct ice_rss_hash_cfg *cfg)
> +{
> +     ctx->hash_flds = cfg->hash_flds;
> +     ctx->addl_hdrs = cfg->addl_hdrs;
> +     ctx->hdr_type = cfg->hdr_type;
> +     ctx->symm = cfg->symm;
> +}
> +
> +/**
> + * ice_hash_moveout - Delete an RSS configuration (keep context)
> + * @vf: VF pointer
> + * @cfg: RSS hash configuration
> + *
> + * Return: 0 on success (including when already absent); -ENOENT if @cfg is
> + * invalid or VSI is missing; -EBUSY on hardware removal failure.
> + */
> +static int
> +ice_hash_moveout(struct ice_vf *vf, struct ice_rss_hash_cfg *cfg)
> +{
> +     struct device *dev = ice_pf_to_dev(vf->pf);
> +     struct ice_vsi *vsi = ice_get_vf_vsi(vf);
> +     struct ice_hw *hw = &vf->pf->hw;
> +     int ret;
> +
> +     if (!ice_is_hash_cfg_valid(cfg) || !vsi)
> +             return -ENOENT;
> +
> +     ret = ice_rem_rss_cfg(hw, vsi->idx, cfg);
> +     if (ret && ret != -ENOENT) {
> +             dev_err(dev, "ice_rem_rss_cfg failed for VF %d, VSI %d,
> error:%d\n",
> +                     vf->vf_id, vf->lan_vsi_idx, ret);
> +             return -EBUSY;
> +     }
> +
> +     return 0;
> +}
> +
> +/**
> + * ice_hash_moveback - Add an RSS hash configuration for a VF
> + * @vf: VF pointer
> + * @cfg: RSS hash configuration to apply
> + *
> + * Add @cfg to @vf if the context is valid and VSI exists; programs HW.
> + *
> + * Return:
> + * * 0 on success
> + * * -ENOENT if @cfg is invalid or VSI is missing
> + * * -EBUSY if hardware programming fails
> + */
> +static int
> +ice_hash_moveback(struct ice_vf *vf, struct ice_rss_hash_cfg *cfg)
> +{
> +     struct device *dev = ice_pf_to_dev(vf->pf);
> +     struct ice_vsi *vsi = ice_get_vf_vsi(vf);
> +     struct ice_hw *hw = &vf->pf->hw;
> +     int ret;
> +
> +     if (!ice_is_hash_cfg_valid(cfg) || !vsi)
> +             return -ENOENT;
> +
> +     ret = ice_add_rss_cfg(hw, vsi, cfg);
> +     if (ret) {
> +             dev_err(dev, "ice_add_rss_cfg failed for VF %d, VSI %d,
> error:%d\n",
> +                     vf->vf_id, vf->lan_vsi_idx, ret);
> +             return -EBUSY;
> +     }
> +
> +     return 0;
> +}
> +
> +/**
> + * ice_hash_remove - remove a RSS configuration
> + * @vf: pointer to the VF info
> + * @cfg: pointer to the RSS hash configuration
> + *
> + * This function will delete a RSS hash configuration and also delete the
> + * hash context which stores the rule info.
> + */
> +static int
> +ice_hash_remove(struct ice_vf *vf, struct ice_rss_hash_cfg *cfg)
> +{
> +     int ret;
> +
> +     ret = ice_hash_moveout(vf, cfg);
> +     if (ret && (ret != -ENOENT))
> +             return ret;
> +
> +     ice_hash_cfg_reset(cfg);
> +
> +     return 0;
> +}
> +
> +struct ice_gtpu_ctx_action {
> +     u32 ctx_idx;
> +     const u32 *remove_list;
> +     int remove_count;
> +     const u32 *moveout_list;
> +     int moveout_count;
> +};
> +
> +/**
> + * ice_add_rss_cfg_pre_gtpu - Pre-process the GTPU RSS configuration
> + * @vf: pointer to the VF info
> + * @ctx: pointer to the context of the GTPU hash
> + * @ctx_idx: index of the hash context
> + *
> + * Pre-processes the GTPU hash configuration before adding a new
> + * hash context. It removes or reorders existing hash configurations that may
> + * conflict with the new one. For example, if a GTPU_UP or GTPU_DWN rule is
> + * configured after a GTPU_EH rule, the GTPU_EH hash will be matched first
> due
> + * to TCAM write and match order (top-down). In such cases, the GTPU_EH
> rule
> + * must be moved after the GTPU_UP/DWN rule. Conversely, if a GTPU_EH
> rule is
> + * configured after a GTPU_UP/DWN rule, the UP/DWN rules should be
> removed to
> + * avoid conflict.
> + *
> + * Return: 0 on success or a negative error code on failure
> + */
> +static int ice_add_rss_cfg_pre_gtpu(struct ice_vf *vf,
> +                                 struct ice_vf_hash_gtpu_ctx *ctx,
> +                                 u32 ctx_idx)
> +{
> +     int ret, i;
> +
> +     static const u32 remove_eh_ip[] = {
> +             ICE_HASH_GTPU_CTX_EH_IP_UDP,
> ICE_HASH_GTPU_CTX_EH_IP_TCP,
> +             ICE_HASH_GTPU_CTX_UP_IP,
> ICE_HASH_GTPU_CTX_UP_IP_UDP,
> +             ICE_HASH_GTPU_CTX_UP_IP_TCP,
> ICE_HASH_GTPU_CTX_DW_IP,
> +             ICE_HASH_GTPU_CTX_DW_IP_UDP,
> ICE_HASH_GTPU_CTX_DW_IP_TCP,
> +     };
> +
> +     static const u32 remove_eh_ip_udp[] = {
> +             ICE_HASH_GTPU_CTX_UP_IP_UDP,
> +             ICE_HASH_GTPU_CTX_DW_IP_UDP,
> +     };
> +     static const u32 moveout_eh_ip_udp[] = {
> +             ICE_HASH_GTPU_CTX_UP_IP,
> +             ICE_HASH_GTPU_CTX_UP_IP_TCP,
> +             ICE_HASH_GTPU_CTX_DW_IP,
> +             ICE_HASH_GTPU_CTX_DW_IP_TCP,
> +     };
> +
> +     static const u32 remove_eh_ip_tcp[] = {
> +             ICE_HASH_GTPU_CTX_UP_IP_TCP,
> +             ICE_HASH_GTPU_CTX_DW_IP_TCP,
> +     };
> +     static const u32 moveout_eh_ip_tcp[] = {
> +             ICE_HASH_GTPU_CTX_UP_IP,
> +             ICE_HASH_GTPU_CTX_UP_IP_UDP,
> +             ICE_HASH_GTPU_CTX_DW_IP,
> +             ICE_HASH_GTPU_CTX_DW_IP_UDP,
> +     };
> +
> +     static const u32 remove_up_ip[] = {
> +             ICE_HASH_GTPU_CTX_UP_IP_UDP,
> +             ICE_HASH_GTPU_CTX_UP_IP_TCP,
> +     };
> +     static const u32 moveout_up_ip[] = {
> +             ICE_HASH_GTPU_CTX_EH_IP,
> +             ICE_HASH_GTPU_CTX_EH_IP_UDP,
> +             ICE_HASH_GTPU_CTX_EH_IP_TCP,
> +     };
> +
> +     static const u32 moveout_up_ip_udp_tcp[] = {
> +             ICE_HASH_GTPU_CTX_EH_IP,
> +             ICE_HASH_GTPU_CTX_EH_IP_UDP,
> +             ICE_HASH_GTPU_CTX_EH_IP_TCP,
> +     };
> +
> +     static const u32 remove_dw_ip[] = {
> +             ICE_HASH_GTPU_CTX_DW_IP_UDP,
> +             ICE_HASH_GTPU_CTX_DW_IP_TCP,
> +     };
> +     static const u32 moveout_dw_ip[] = {
> +             ICE_HASH_GTPU_CTX_EH_IP,
> +             ICE_HASH_GTPU_CTX_EH_IP_UDP,
> +             ICE_HASH_GTPU_CTX_EH_IP_TCP,
> +     };
> +
> +     static const struct ice_gtpu_ctx_action actions[] = {
> +             { ICE_HASH_GTPU_CTX_EH_IP, remove_eh_ip,
> +               ARRAY_SIZE(remove_eh_ip), NULL, 0 },
> +             { ICE_HASH_GTPU_CTX_EH_IP_UDP, remove_eh_ip_udp,
> +               ARRAY_SIZE(remove_eh_ip_udp), moveout_eh_ip_udp,
> +               ARRAY_SIZE(moveout_eh_ip_udp) },
> +             { ICE_HASH_GTPU_CTX_EH_IP_TCP, remove_eh_ip_tcp,
> +               ARRAY_SIZE(remove_eh_ip_tcp), moveout_eh_ip_tcp,
> +               ARRAY_SIZE(moveout_eh_ip_tcp) },
> +             { ICE_HASH_GTPU_CTX_UP_IP, remove_up_ip,
> +               ARRAY_SIZE(remove_up_ip), moveout_up_ip,
> +               ARRAY_SIZE(moveout_up_ip) },
> +             { ICE_HASH_GTPU_CTX_UP_IP_UDP, NULL, 0,
> moveout_up_ip_udp_tcp,
> +               ARRAY_SIZE(moveout_up_ip_udp_tcp) },
> +             { ICE_HASH_GTPU_CTX_UP_IP_TCP, NULL, 0,
> moveout_up_ip_udp_tcp,
> +               ARRAY_SIZE(moveout_up_ip_udp_tcp) },
> +             { ICE_HASH_GTPU_CTX_DW_IP, remove_dw_ip,
> +               ARRAY_SIZE(remove_dw_ip), moveout_dw_ip,
> +               ARRAY_SIZE(moveout_dw_ip) },
> +             { ICE_HASH_GTPU_CTX_DW_IP_UDP, NULL, 0,
> moveout_dw_ip,
> +               ARRAY_SIZE(moveout_dw_ip) },
> +             { ICE_HASH_GTPU_CTX_DW_IP_TCP, NULL, 0,
> moveout_dw_ip,
> +               ARRAY_SIZE(moveout_dw_ip) },
> +     };
> +
> +     for (i = 0; i < ARRAY_SIZE(actions); i++) {
> +             if (actions[i].ctx_idx != ctx_idx)
> +                     continue;
> +
> +             if (actions[i].remove_list) {
> +                     for (int j = 0; j < actions[i].remove_count; j++) {
> +                             u16 rm = actions[i].remove_list[j];
> +
> +                             ret = ice_hash_remove(vf, &ctx->ctx[rm]);
> +                             if (ret && ret != -ENOENT)
> +                                     return ret;
> +                     }
> +             }
> +
> +             if (actions[i].moveout_list) {
> +                     for (int j = 0; j < actions[i].moveout_count; j++) {
> +                             u16 mv = actions[i].moveout_list[j];
> +
> +                             ret = ice_hash_moveout(vf, &ctx->ctx[mv]);
> +                             if (ret && ret != -ENOENT)
> +                                     return ret;
> +                     }
> +             }
> +             break;
> +     }
> +
> +     return 0;
> +}
> +
> +/**
> + * ice_add_rss_cfg_pre_ip - Pre-process IP-layer RSS configuration
> + * @vf: VF pointer
> + * @ctx: IP L4 hash context (ESP/UDP-ESP/AH/PFCP and UDP/TCP/SCTP)
> + *
> + * Remove covered/recorded IP RSS configurations prior to adding a new
> one.
> + *
> + * Return: 0 on success; negative error code on failure.
> + */
> +static int
> +ice_add_rss_cfg_pre_ip(struct ice_vf *vf, struct ice_vf_hash_ip_ctx *ctx)
> +{
> +     int i, ret;
> +
> +     for (i = 1; i < ICE_HASH_IP_CTX_MAX; i++)
> +             if (ice_is_hash_cfg_valid(&ctx->ctx[i])) {
> +                     ret = ice_hash_remove(vf, &ctx->ctx[i]);
> +
> +                     if (ret)
> +                             return ret;
> +             }
> +
> +     return 0;
> +}
> +
> +/**
> + * ice_calc_gtpu_ctx_idx - Calculate GTPU hash context index
> + * @hdrs: Bitmask of protocol headers prefixed with ICE_FLOW_SEG_HDR_*
> + *
> + * Determine the GTPU hash context index based on the combination of
> + * encapsulation headers (GTPU_EH, GTPU_UP, GTPU_DWN) and transport
> + * protocols (UDP, TCP) within IPv4 or IPv6 flows.
> + *
> + * Return: A valid context index (0-8) if the header combination is 
> supported,
> + *         or ICE_HASH_GTPU_CTX_MAX if the combination is invalid.
> + */
> +static enum ice_hash_gtpu_ctx_type ice_calc_gtpu_ctx_idx(u32 hdrs)
> +{
> +     u32 eh_idx, ip_idx;
> +
> +     if (hdrs & ICE_FLOW_SEG_HDR_GTPU_EH)
> +             eh_idx = 0;
> +     else if (hdrs & ICE_FLOW_SEG_HDR_GTPU_UP)
> +             eh_idx = 1;
> +     else if (hdrs & ICE_FLOW_SEG_HDR_GTPU_DWN)
> +             eh_idx = 2;
> +     else
> +             return ICE_HASH_GTPU_CTX_MAX;
> +
> +     ip_idx = 0;
> +     if (hdrs & ICE_FLOW_SEG_HDR_UDP)
> +             ip_idx = 1;
> +     else if (hdrs & ICE_FLOW_SEG_HDR_TCP)
> +             ip_idx = 2;
> +
> +     if (hdrs & (ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV6))
> +             return eh_idx * 3 + ip_idx;
> +     else
> +             return ICE_HASH_GTPU_CTX_MAX;
> +}
> +
> +/**
> + * ice_map_ip_ctx_idx - map the index of the IP L4 hash context
> + * @hdrs: protocol headers prefix with ICE_FLOW_SEG_HDR_XXX.
> + *
> + * The IP L4 hash context use the index to classify for IPv4/IPv6 with
> + * ESP/UDP_ESP/AH/PFCP and non-tunnel UDP/TCP/SCTP
> + * this function map the index based on the protocol headers.
> + */
> +static u8 ice_map_ip_ctx_idx(u32 hdrs)
> +{
> +     u8 i;
> +
> +     static struct {
> +             u32 hdrs;
> +             u8 ctx_idx;
> +     } ip_ctx_idx_map[] = {
> +             { ICE_FLOW_SEG_HDR_IPV4 |
> ICE_FLOW_SEG_HDR_IPV_OTHER |
> +                     ICE_FLOW_SEG_HDR_ESP,
> +                     ICE_HASH_IP_CTX_IP_ESP },
> +             { ICE_FLOW_SEG_HDR_IPV4 |
> ICE_FLOW_SEG_HDR_IPV_OTHER |
> +                     ICE_FLOW_SEG_HDR_NAT_T_ESP,
> +                     ICE_HASH_IP_CTX_IP_UDP_ESP },
> +             { ICE_FLOW_SEG_HDR_IPV4 |
> ICE_FLOW_SEG_HDR_IPV_OTHER |
> +                     ICE_FLOW_SEG_HDR_AH,
> +                     ICE_HASH_IP_CTX_IP_AH },
> +             { ICE_FLOW_SEG_HDR_IPV4 |
> ICE_FLOW_SEG_HDR_IPV_OTHER |
> +                     ICE_FLOW_SEG_HDR_PFCP_SESSION,
> +                     ICE_HASH_IP_CTX_IP_PFCP },
> +             { ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN |
> +                     ICE_FLOW_SEG_HDR_IPV4 |
> ICE_FLOW_SEG_HDR_UDP,
> +                     ICE_HASH_IP_CTX_IP_UDP },
> +             { ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN |
> +                     ICE_FLOW_SEG_HDR_IPV4 |
> ICE_FLOW_SEG_HDR_TCP,
> +                     ICE_HASH_IP_CTX_IP_TCP },
> +             { ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN |
> +                     ICE_FLOW_SEG_HDR_IPV4 |
> ICE_FLOW_SEG_HDR_SCTP,
> +                     ICE_HASH_IP_CTX_IP_SCTP },
> +             { ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN |
> +                     ICE_FLOW_SEG_HDR_IPV4 |
> ICE_FLOW_SEG_HDR_IPV_OTHER,
> +                     ICE_HASH_IP_CTX_IP },
> +             { ICE_FLOW_SEG_HDR_IPV6 |
> ICE_FLOW_SEG_HDR_IPV_OTHER |
> +                     ICE_FLOW_SEG_HDR_ESP,
> +                     ICE_HASH_IP_CTX_IP_ESP },
> +             { ICE_FLOW_SEG_HDR_IPV6 |
> ICE_FLOW_SEG_HDR_IPV_OTHER |
> +                     ICE_FLOW_SEG_HDR_NAT_T_ESP,
> +                     ICE_HASH_IP_CTX_IP_UDP_ESP },
> +             { ICE_FLOW_SEG_HDR_IPV6 |
> ICE_FLOW_SEG_HDR_IPV_OTHER |
> +                     ICE_FLOW_SEG_HDR_AH,
> +                     ICE_HASH_IP_CTX_IP_AH },
> +             { ICE_FLOW_SEG_HDR_IPV6 |
> ICE_FLOW_SEG_HDR_IPV_OTHER |
> +                     ICE_FLOW_SEG_HDR_PFCP_SESSION,
> +                     ICE_HASH_IP_CTX_IP_PFCP },
> +             { ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN |
> +                     ICE_FLOW_SEG_HDR_IPV6 |
> ICE_FLOW_SEG_HDR_UDP,
> +                     ICE_HASH_IP_CTX_IP_UDP },
> +             { ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN |
> +                     ICE_FLOW_SEG_HDR_IPV6 |
> ICE_FLOW_SEG_HDR_TCP,
> +                     ICE_HASH_IP_CTX_IP_TCP },
> +             { ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN |
> +                     ICE_FLOW_SEG_HDR_IPV6 |
> ICE_FLOW_SEG_HDR_SCTP,
> +                     ICE_HASH_IP_CTX_IP_SCTP },
> +             { ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN |
> +                     ICE_FLOW_SEG_HDR_IPV6 |
> ICE_FLOW_SEG_HDR_IPV_OTHER,
> +                     ICE_HASH_IP_CTX_IP },
> +             /* the remaining mappings are used for default RSS */
> +             { ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_UDP,
> +                     ICE_HASH_IP_CTX_IP_UDP },
> +             { ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_TCP,
> +                     ICE_HASH_IP_CTX_IP_TCP },
> +             { ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_SCTP,
> +                     ICE_HASH_IP_CTX_IP_SCTP },
> +             { ICE_FLOW_SEG_HDR_IPV4 |
> ICE_FLOW_SEG_HDR_IPV_OTHER,
> +                     ICE_HASH_IP_CTX_IP },
> +             { ICE_FLOW_SEG_HDR_IPV6 | ICE_FLOW_SEG_HDR_UDP,
> +                     ICE_HASH_IP_CTX_IP_UDP },
> +             { ICE_FLOW_SEG_HDR_IPV6 | ICE_FLOW_SEG_HDR_TCP,
> +                     ICE_HASH_IP_CTX_IP_TCP },
> +             { ICE_FLOW_SEG_HDR_IPV6 | ICE_FLOW_SEG_HDR_SCTP,
> +                     ICE_HASH_IP_CTX_IP_SCTP },
> +             { ICE_FLOW_SEG_HDR_IPV6 |
> ICE_FLOW_SEG_HDR_IPV_OTHER,
> +                     ICE_HASH_IP_CTX_IP },
> +     };
> +
> +     for (i = 0; i < ARRAY_SIZE(ip_ctx_idx_map); i++) {
> +             if (hdrs == ip_ctx_idx_map[i].hdrs)
> +                     return ip_ctx_idx_map[i].ctx_idx;
> +     }
> +
> +     return ICE_HASH_IP_CTX_MAX;
> +}
> +
> +/**
> + * ice_add_rss_cfg_pre - Prepare RSS configuration context for a VF
> + * @vf: pointer to the VF structure
> + * @cfg: pointer to the RSS hash configuration
> + *
> + * Prepare the RSS hash context for a given VF based on the additional
> + * protocol headers specified in @cfg. This includes pre-configuration
> + * for IP and GTPU-based flows.
> + *
> + * If the configuration matches a known IP context, the function sets up
> + * the appropriate IP hash context. If the configuration includes GTPU
> + * headers, it prepares the GTPU-specific context accordingly.
> + *
> + * Return: 0 on success, or a negative error code on failure.
> + */
> +static int
> +ice_add_rss_cfg_pre(struct ice_vf *vf, struct ice_rss_hash_cfg *cfg)
> +{
> +     u32 ice_gtpu_ctx_idx = ice_calc_gtpu_ctx_idx(cfg->addl_hdrs);
> +     u8 ip_ctx_idx = ice_map_ip_ctx_idx(cfg->addl_hdrs);
> +
> +     if (ip_ctx_idx == ICE_HASH_IP_CTX_IP) {
> +             int ret = 0;
> +
> +             if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV4)
> +                     ret = ice_add_rss_cfg_pre_ip(vf, &vf->hash_ctx.v4);
> +             else if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV6)
> +                     ret = ice_add_rss_cfg_pre_ip(vf, &vf->hash_ctx.v6);
> +
> +             if (ret)
> +                     return ret;
> +     }
> +
> +     if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV4) {
> +             return ice_add_rss_cfg_pre_gtpu(vf, &vf->hash_ctx.ipv4,
> +                                             ice_gtpu_ctx_idx);
> +     } else if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV6) {
> +             return ice_add_rss_cfg_pre_gtpu(vf, &vf->hash_ctx.ipv6,
> +                                             ice_gtpu_ctx_idx);
> +     }
> +
> +     return 0;
> +}
> +
> +/**
> + * ice_add_rss_cfg_post_gtpu - Post-process GTPU RSS configuration
> + * @vf: pointer to the VF info
> + * @ctx: pointer to the context of the GTPU hash
> + * @cfg: pointer to the RSS hash configuration
> + * @ctx_idx: index of the hash context
> + *
> + * Post-processes the GTPU hash configuration after a new hash
> + * context has been successfully added. It updates the context with the new
> + * configuration and restores any previously removed hash contexts that
> need
> + * to be re-applied. This ensures proper TCAM rule ordering and avoids
> + * conflicts between overlapping GTPU rules.
> + *
> + * Return: 0 on success or a negative error code on failure
> + */
> +static int ice_add_rss_cfg_post_gtpu(struct ice_vf *vf,
> +                                  struct ice_vf_hash_gtpu_ctx *ctx,
> +                                  struct ice_rss_hash_cfg *cfg, u32 ctx_idx)
> +{
> +     /*
> +      * GTPU hash moveback lookup table indexed by context ID.
> +      * Each entry is a bitmap indicating which contexts need moveback
> +      * operations when the corresponding context index is processed.
> +      */
> +     static const unsigned long
> +             ice_gtpu_moveback_tbl[ICE_HASH_GTPU_CTX_MAX] = {
> +                     [ICE_HASH_GTPU_CTX_EH_IP] = 0,
> +                     [ICE_HASH_GTPU_CTX_EH_IP_UDP] =
> +                             BIT(ICE_HASH_GTPU_CTX_UP_IP) |
> +                             BIT(ICE_HASH_GTPU_CTX_UP_IP_TCP) |
> +                             BIT(ICE_HASH_GTPU_CTX_DW_IP) |
> +                             BIT(ICE_HASH_GTPU_CTX_DW_IP_TCP),
> +                     [ICE_HASH_GTPU_CTX_EH_IP_TCP] =
> +                             BIT(ICE_HASH_GTPU_CTX_UP_IP) |
> +                             BIT(ICE_HASH_GTPU_CTX_UP_IP_UDP) |
> +                             BIT(ICE_HASH_GTPU_CTX_DW_IP) |
> +                             BIT(ICE_HASH_GTPU_CTX_DW_IP_UDP),
> +                     [ICE_HASH_GTPU_CTX_UP_IP] =
> +                             BIT(ICE_HASH_GTPU_CTX_EH_IP) |
> +                             BIT(ICE_HASH_GTPU_CTX_EH_IP_UDP) |
> +                             BIT(ICE_HASH_GTPU_CTX_EH_IP_TCP),
> +                     [ICE_HASH_GTPU_CTX_UP_IP_UDP] =
> +                             BIT(ICE_HASH_GTPU_CTX_EH_IP) |
> +                             BIT(ICE_HASH_GTPU_CTX_EH_IP_UDP) |
> +                             BIT(ICE_HASH_GTPU_CTX_EH_IP_TCP),
> +                     [ICE_HASH_GTPU_CTX_UP_IP_TCP] =
> +                             BIT(ICE_HASH_GTPU_CTX_EH_IP) |
> +                             BIT(ICE_HASH_GTPU_CTX_EH_IP_UDP) |
> +                             BIT(ICE_HASH_GTPU_CTX_EH_IP_TCP),
> +                     [ICE_HASH_GTPU_CTX_DW_IP] =
> +                             BIT(ICE_HASH_GTPU_CTX_EH_IP) |
> +                             BIT(ICE_HASH_GTPU_CTX_EH_IP_UDP) |
> +                             BIT(ICE_HASH_GTPU_CTX_EH_IP_TCP),
> +                     [ICE_HASH_GTPU_CTX_DW_IP_UDP] =
> +                             BIT(ICE_HASH_GTPU_CTX_EH_IP) |
> +                             BIT(ICE_HASH_GTPU_CTX_EH_IP_UDP) |
> +                             BIT(ICE_HASH_GTPU_CTX_EH_IP_TCP),
> +                     [ICE_HASH_GTPU_CTX_DW_IP_TCP] =
> +                             BIT(ICE_HASH_GTPU_CTX_EH_IP) |
> +                             BIT(ICE_HASH_GTPU_CTX_EH_IP_UDP) |
> +                             BIT(ICE_HASH_GTPU_CTX_EH_IP_TCP),
> +             };
> +     unsigned long moveback_mask;
> +     int ret;
> +     int i;
> +
> +     if (unlikely(ctx_idx >= ICE_HASH_GTPU_CTX_MAX))
> +             return 0;
> +
> +     ctx->ctx[ctx_idx].addl_hdrs = cfg->addl_hdrs;
> +     ctx->ctx[ctx_idx].hash_flds = cfg->hash_flds;
> +     ctx->ctx[ctx_idx].hdr_type = cfg->hdr_type;
> +     ctx->ctx[ctx_idx].symm = cfg->symm;
> +
> +     moveback_mask = ice_gtpu_moveback_tbl[ctx_idx];
> +     for_each_set_bit(i, &moveback_mask, ICE_HASH_GTPU_CTX_MAX) {
> +             ret = ice_hash_moveback(vf, &ctx->ctx[i]);
> +             if (ret && ret != -ENOENT)
> +                     return ret;
> +     }
> +
> +     return 0;
> +}
> +
> +static int
> +ice_add_rss_cfg_post(struct ice_vf *vf, struct ice_rss_hash_cfg *cfg)
> +{
> +     u32 ice_gtpu_ctx_idx = ice_calc_gtpu_ctx_idx(cfg->addl_hdrs);
> +     u8 ip_ctx_idx = ice_map_ip_ctx_idx(cfg->addl_hdrs);
> +
> +     if (ip_ctx_idx && ip_ctx_idx < ICE_HASH_IP_CTX_MAX) {
> +             if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV4)
> +                     ice_hash_cfg_record(&vf->hash_ctx.v4.ctx[ip_ctx_idx],
> cfg);
> +             else if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV6)
> +                     ice_hash_cfg_record(&vf->hash_ctx.v6.ctx[ip_ctx_idx],
> cfg);
> +     }
> +
> +     if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV4) {
> +             return ice_add_rss_cfg_post_gtpu(vf, &vf->hash_ctx.ipv4,
> +                                              cfg, ice_gtpu_ctx_idx);
> +     } else if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV6) {
> +             return ice_add_rss_cfg_post_gtpu(vf, &vf->hash_ctx.ipv6,
> +                                              cfg, ice_gtpu_ctx_idx);
> +     }
> +
> +     return 0;
> +}
> +
> +/**
> + * ice_rem_rss_cfg_post - post-process the RSS configuration
> + * @vf: pointer to the VF info
> + * @cfg: pointer to the RSS hash configuration
> + *
> + * Post process the RSS hash configuration after deleting a hash
> + * config. Such as, it will reset the hash context for the GTPU hash.
> + */
> +static void
> +ice_rem_rss_cfg_post(struct ice_vf *vf, struct ice_rss_hash_cfg *cfg)
> +{
> +     u32 ice_gtpu_ctx_idx = ice_calc_gtpu_ctx_idx(cfg->addl_hdrs);
> +     u8 ip_ctx_idx = ice_map_ip_ctx_idx(cfg->addl_hdrs);
> +
> +     if (ip_ctx_idx && ip_ctx_idx < ICE_HASH_IP_CTX_MAX) {
> +             if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV4)
> +                     ice_hash_cfg_reset(&vf->hash_ctx.v4.ctx[ip_ctx_idx]);
> +             else if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV6)
> +                     ice_hash_cfg_reset(&vf->hash_ctx.v6.ctx[ip_ctx_idx]);
> +     }
> +
> +     if (ice_gtpu_ctx_idx >= ICE_HASH_GTPU_CTX_MAX)
> +             return;
> +
> +     if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV4)
> +             ice_hash_cfg_reset(&vf->hash_ctx.ipv4.ctx[ice_gtpu_ctx_idx]);
> +     else if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV6)
> +             ice_hash_cfg_reset(&vf->hash_ctx.ipv6.ctx[ice_gtpu_ctx_idx]);
> +}
> +
> +/**
> + * ice_rem_rss_cfg_wrap - Wrapper for deleting an RSS configuration
> + * @vf: pointer to the VF info
> + * @cfg: pointer to the RSS hash configuration
> + *
> + * Wrapper function to delete a flow profile base on an RSS configuration,
> + * and also post process the hash context base on the rollback mechanism
> + * which handle some rules conflict by ice_add_rss_cfg_wrap.
> + *
> + * Return: 0 on success; negative error code on failure.
> + */
> +static int
> +ice_rem_rss_cfg_wrap(struct ice_vf *vf, struct ice_rss_hash_cfg *cfg)
> +{
> +     struct device *dev = ice_pf_to_dev(vf->pf);
> +     struct ice_vsi *vsi = ice_get_vf_vsi(vf);
> +     struct ice_hw *hw = &vf->pf->hw;
> +     int ret;
> +
> +     ret = ice_rem_rss_cfg(hw, vsi->idx, cfg);
> +     /* We just ignore -ENOENT, because if two configurations share the
> same
> +      * profile remove one of them actually removes both, since the
> +      * profile is deleted.
> +      */
> +     if (ret && ret != -ENOENT) {
> +             dev_err(dev, "ice_rem_rss_cfg failed for VF %d, VSI %d,
> error:%d\n",
> +                     vf->vf_id, vf->lan_vsi_idx, ret);
> +             return ret;
> +     }
> +
> +     ice_rem_rss_cfg_post(vf, cfg);
> +
> +     return 0;
> +}
> +
> +/**
> + * ice_add_rss_cfg_wrap - Wrapper for adding an RSS configuration
> + * @vf: pointer to the VF info
> + * @cfg: pointer to the RSS hash configuration
> + *
> + * Add a flow profile based on an RSS configuration. Use a rollback
> + * mechanism to handle rule conflicts due to TCAM
> + * write sequence from top to down.
> + *
> + * Return: 0 on success; negative error code on failure.
> + */
> +static int
> +ice_add_rss_cfg_wrap(struct ice_vf *vf, struct ice_rss_hash_cfg *cfg)
> +{
> +     struct device *dev = ice_pf_to_dev(vf->pf);
> +     struct ice_vsi *vsi = ice_get_vf_vsi(vf);
> +     struct ice_hw *hw = &vf->pf->hw;
> +     int ret;
> +
> +     if (ice_add_rss_cfg_pre(vf, cfg))
> +             return -EINVAL;
> +
> +     ret = ice_add_rss_cfg(hw, vsi, cfg);
> +     if (ret) {
> +             dev_err(dev, "ice_add_rss_cfg failed for VF %d, VSI %d,
> error:%d\n",
> +                     vf->vf_id, vf->lan_vsi_idx, ret);
> +             return ret;
> +     }
> +
> +     if (ice_add_rss_cfg_post(vf, cfg))
> +             ret = -EINVAL;
> +
> +     return ret;
> +}
> +
> +/**
> + * ice_parse_raw_rss_pattern - Parse raw pattern spec and mask for RSS
> + * @vf: pointer to the VF info
> + * @proto: pointer to the virtchnl protocol header
> + * @raw_cfg: pointer to the RSS raw pattern configuration
> + *
> + * Parser function to get spec and mask from virtchnl message, and parse
> + * them to get the corresponding profile and offset. The profile is used
> + * to add RSS configuration.
> + *
> + * Return: 0 on success; negative error code on failure.
> + */
> +static int
> +ice_parse_raw_rss_pattern(struct ice_vf *vf, struct virtchnl_proto_hdrs
> *proto,
> +                       struct ice_rss_raw_cfg *raw_cfg)
> +{
> +     struct ice_parser_result pkt_parsed;
> +     struct ice_hw *hw = &vf->pf->hw;
> +     struct ice_parser_profile prof;
> +     u16 pkt_len;
> +     struct ice_parser *psr;
> +     u8 *pkt_buf, *msk_buf;
> +     int ret = 0;
> +
> +     pkt_len = proto->raw.pkt_len;
> +     if (!pkt_len)
> +             return -EINVAL;
> +     if (pkt_len > VIRTCHNL_MAX_SIZE_RAW_PACKET)
> +             pkt_len = VIRTCHNL_MAX_SIZE_RAW_PACKET;
> +
> +     pkt_buf = kzalloc(pkt_len, GFP_KERNEL);
> +     msk_buf = kzalloc(pkt_len, GFP_KERNEL);
> +     if (!pkt_buf || !msk_buf) {
> +             ret = -ENOMEM;
> +             goto free_alloc;
> +     }
> +
> +     memcpy(pkt_buf, proto->raw.spec, pkt_len);
> +     memcpy(msk_buf, proto->raw.mask, pkt_len);
> +
> +     psr = ice_parser_create(hw);
> +     if (IS_ERR(psr)) {
> +             ret = PTR_ERR(psr);
> +             goto parser_destroy;
> +     }
> +
> +     ret = ice_parser_run(psr, pkt_buf, pkt_len, &pkt_parsed);
> +     if (ret)
> +             goto parser_destroy;
> +
> +     ret = ice_parser_profile_init(&pkt_parsed, pkt_buf, msk_buf,
> +                                   pkt_len, ICE_BLK_RSS, &prof);
> +     if (ret)
> +             goto parser_destroy;
> +
> +     memcpy(&raw_cfg->prof, &prof, sizeof(prof));
> +
> +parser_destroy:
> +     ice_parser_destroy(psr);
> +free_alloc:
> +     kfree(pkt_buf);
> +     kfree(msk_buf);
> +     return ret;
> +}
> +
> +/**
> + * ice_add_raw_rss_cfg - add RSS configuration for raw pattern
> + * @vf: pointer to the VF info
> + * @cfg: pointer to the RSS raw pattern configuration
> + *
> + * This function adds the RSS configuration for raw pattern.
> + * Check if current profile is matched. If not, remove the old
> + * one and add the new profile to HW directly. Update the symmetric
> + * hash configuration as well.
> + *
> + * Return: 0 on success; negative error code on failure.
> + */
> +static int
> +ice_add_raw_rss_cfg(struct ice_vf *vf, struct ice_rss_raw_cfg *cfg)
> +{
> +     struct ice_parser_profile *prof = &cfg->prof;
> +     struct device *dev = ice_pf_to_dev(vf->pf);
> +     struct ice_rss_prof_info *rss_prof;
> +     struct ice_hw *hw = &vf->pf->hw;
> +     int i, ptg, ret = 0;
> +     u16 vsi_handle;
> +     u64 id;
> +
> +     vsi_handle = vf->lan_vsi_idx;
> +     id = find_first_bit(prof->ptypes, ICE_FLOW_PTYPE_MAX);
> +
> +     ptg = hw->blk[ICE_BLK_RSS].xlt1.t[id];
> +     rss_prof = &vf->rss_prof_info[ptg];
> +
> +     /* check if ptg already has a profile */
> +     if (rss_prof->prof.fv_num) {
> +             for (i = 0; i < ICE_MAX_FV_WORDS; i++) {
> +                     if (rss_prof->prof.fv[i].proto_id !=
> +                         prof->fv[i].proto_id ||
> +                         rss_prof->prof.fv[i].offset !=
> +                         prof->fv[i].offset)
> +                             break;
> +             }
> +
> +             /* current profile is matched, check symmetric hash */
> +             if (i == ICE_MAX_FV_WORDS) {
> +                     if (rss_prof->symm != cfg->symm)
> +                             goto update_symm;
> +                     return ret;
> +             }
> +
> +             /* current profile is not matched, remove it */
> +             ret =
> +             ice_rem_prof_id_flow(hw, ICE_BLK_RSS,
> +                                  ice_get_hw_vsi_num(hw, vsi_handle),
> +                                  id);
> +             if (ret) {
> +                     dev_err(dev, "remove RSS flow failed\n");
> +                     return ret;
> +             }
> +
> +             ret = ice_rem_prof(hw, ICE_BLK_RSS, id);
> +             if (ret) {
> +                     dev_err(dev, "remove RSS profile failed\n");
> +                     return ret;
> +             }
> +     }
> +
> +     /* add new profile */
> +     ret = ice_flow_set_parser_prof(hw, vsi_handle, 0, prof, ICE_BLK_RSS);
> +     if (ret) {
> +             dev_err(dev, "HW profile add failed\n");
> +             return ret;
> +     }
> +
> +     memcpy(&rss_prof->prof, prof, sizeof(struct ice_parser_profile));
> +
> +update_symm:
> +     rss_prof->symm = cfg->symm;
> +     ice_rss_update_raw_symm(hw, cfg, id);
> +     return ret;
> +}
> +
> +/**
> + * ice_rem_raw_rss_cfg - remove RSS configuration for raw pattern
> + * @vf: pointer to the VF info
> + * @cfg: pointer to the RSS raw pattern configuration
> + *
> + * This function removes the RSS configuration for raw pattern.
> + * Check if vsi group is already removed first. If not, remove the
> + * profile.
> + *
> + * Return: 0 on success; negative error code on failure.
> + */
> +static int
> +ice_rem_raw_rss_cfg(struct ice_vf *vf, struct ice_rss_raw_cfg *cfg)
> +{
> +     struct ice_parser_profile *prof = &cfg->prof;
> +     struct device *dev = ice_pf_to_dev(vf->pf);
> +     struct ice_hw *hw = &vf->pf->hw;
> +     int ptg, ret = 0;
> +     u16 vsig, vsi;
> +     u64 id;
> +
> +     id = find_first_bit(prof->ptypes, ICE_FLOW_PTYPE_MAX);
> +
> +     ptg = hw->blk[ICE_BLK_RSS].xlt1.t[id];
> +
> +     memset(&vf->rss_prof_info[ptg], 0,
> +            sizeof(struct ice_rss_prof_info));
> +
> +     /* check if vsig is already removed */
> +     vsi = ice_get_hw_vsi_num(hw, vf->lan_vsi_idx);
> +     if (vsi >= ICE_MAX_VSI) {
> +             ret = -EINVAL;
> +             goto err;
> +     }
> +
> +     vsig = hw->blk[ICE_BLK_RSS].xlt2.vsis[vsi].vsig;
> +     if (vsig) {
> +             ret = ice_rem_prof_id_flow(hw, ICE_BLK_RSS, vsi, id);
> +             if (ret)
> +                     goto err;
> +
> +             ret = ice_rem_prof(hw, ICE_BLK_RSS, id);
> +             if (ret)
> +                     goto err;
> +     }
> +
> +     return ret;
> +
> +err:
> +     dev_err(dev, "HW profile remove failed\n");
> +     return ret;
> +}
> +
>  /**
>   * ice_vc_handle_rss_cfg
>   * @vf: pointer to the VF info
> @@ -352,6 +1568,8 @@ int ice_vc_handle_rss_cfg(struct ice_vf *vf, u8 *msg,
> bool add)
>       struct device *dev = ice_pf_to_dev(vf->pf);
>       struct ice_hw *hw = &vf->pf->hw;
>       struct ice_vsi *vsi;
> +     u8 hash_type;
> +     bool symm;
> 
>       if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) {
>               dev_dbg(dev, "VF %d attempting to configure RSS, but RSS is
> not supported by the PF\n",
> @@ -387,49 +1605,40 @@ int ice_vc_handle_rss_cfg(struct ice_vf *vf, u8
> *msg, bool add)
>               goto error_param;
>       }
> 
> -     if (!ice_vc_validate_pattern(vf, &rss_cfg->proto_hdrs)) {
> -             v_ret = VIRTCHNL_STATUS_ERR_PARAM;
> +     if (rss_cfg->rss_algorithm == VIRTCHNL_RSS_ALG_R_ASYMMETRIC) {
> +             hash_type = add ? ICE_AQ_VSI_Q_OPT_RSS_HASH_XOR :
> +                               ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ;
> +
> +             v_ret = ice_vc_rss_hash_update(hw, vsi, hash_type);
>               goto error_param;
>       }
> 
> -     if (rss_cfg->rss_algorithm == VIRTCHNL_RSS_ALG_R_ASYMMETRIC) {
> -             struct ice_vsi_ctx *ctx;
> -             u8 lut_type, hash_type;
> -             int status;
> +     hash_type = add ? ICE_AQ_VSI_Q_OPT_RSS_HASH_SYM_TPLZ :
> +                       ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ;
> +     v_ret = ice_vc_rss_hash_update(hw, vsi, hash_type);
> +     if (v_ret)
> +             goto error_param;
> 
> -             lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_VSI;
> -             hash_type = add ? ICE_AQ_VSI_Q_OPT_RSS_HASH_XOR :
> -                             ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ;
> +     symm = rss_cfg->rss_algorithm ==
> VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC;
> +     /* Configure RSS hash for raw pattern */
> +     if (rss_cfg->proto_hdrs.tunnel_level == 0 &&
> +         rss_cfg->proto_hdrs.count == 0) {
> +             struct ice_rss_raw_cfg raw_cfg;
> 
> -             ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> -             if (!ctx) {
> -                     v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
> +             if (ice_parse_raw_rss_pattern(vf, &rss_cfg->proto_hdrs,
> +                                           &raw_cfg)) {
> +                     v_ret = VIRTCHNL_STATUS_ERR_PARAM;
>                       goto error_param;
>               }
> 
> -             ctx->info.q_opt_rss =
> -                     FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_LUT_M,
> lut_type) |
> -                     FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_HASH_M,
> hash_type);
> -
> -             /* Preserve existing queueing option setting */
> -             ctx->info.q_opt_rss |= (vsi->info.q_opt_rss &
> -
> ICE_AQ_VSI_Q_OPT_RSS_GBL_LUT_M);
> -             ctx->info.q_opt_tc = vsi->info.q_opt_tc;
> -             ctx->info.q_opt_flags = vsi->info.q_opt_rss;
> -
> -             ctx->info.valid_sections =
> -
>       cpu_to_le16(ICE_AQ_VSI_PROP_Q_OPT_VALID);
> -
> -             status = ice_update_vsi(hw, vsi->idx, ctx, NULL);
> -             if (status) {
> -                     dev_err(dev, "update VSI for RSS failed, err %d aq_err
> %s\n",
> -                             status, libie_aq_str(hw-
> >adminq.sq_last_status));
> -                     v_ret = VIRTCHNL_STATUS_ERR_PARAM;
> +             if (add) {
> +                     raw_cfg.symm = symm;
> +                     if (ice_add_raw_rss_cfg(vf, &raw_cfg))
> +                             v_ret = VIRTCHNL_STATUS_ERR_PARAM;
>               } else {
> -                     vsi->info.q_opt_rss = ctx->info.q_opt_rss;
> +                     if (ice_rem_raw_rss_cfg(vf, &raw_cfg))
> +                             v_ret = VIRTCHNL_STATUS_ERR_PARAM;
>               }
> -
> -             kfree(ctx);
>       } else {
>               struct ice_rss_hash_cfg cfg;
> 
> @@ -448,24 +1657,12 @@ int ice_vc_handle_rss_cfg(struct ice_vf *vf, u8
> *msg, bool add)
>               }
> 
>               if (add) {
> -                     if (ice_add_rss_cfg(hw, vsi, &cfg)) {
> +                     cfg.symm = symm;
> +                     if (ice_add_rss_cfg_wrap(vf, &cfg))
>                               v_ret = VIRTCHNL_STATUS_ERR_PARAM;
> -                             dev_err(dev, "ice_add_rss_cfg failed for vsi =
> %d, v_ret = %d\n",
> -                                     vsi->vsi_num, v_ret);
> -                     }
>               } else {
> -                     int status;
> -
> -                     status = ice_rem_rss_cfg(hw, vsi->idx, &cfg);
> -                     /* We just ignore -ENOENT, because if two
> configurations
> -                      * share the same profile remove one of them actually
> -                      * removes both, since the profile is deleted.
> -                      */
> -                     if (status && status != -ENOENT) {
> +                     if (ice_rem_rss_cfg_wrap(vf, &cfg))
>                               v_ret = VIRTCHNL_STATUS_ERR_PARAM;
> -                             dev_err(dev, "ice_rem_rss_cfg failed for VF
> ID:%d, error:%d\n",
> -                                     vf->vf_id, status);
> -                     }
>               }
>       }
> 
> diff --git a/include/linux/avf/virtchnl.h b/include/linux/avf/virtchnl.h
> index 5be1881..11bdab5 100644
> --- a/include/linux/avf/virtchnl.h
> +++ b/include/linux/avf/virtchnl.h
> @@ -1253,6 +1253,17 @@ enum virtchnl_proto_hdr_type {
>       VIRTCHNL_PROTO_HDR_ESP,
>       VIRTCHNL_PROTO_HDR_AH,
>       VIRTCHNL_PROTO_HDR_PFCP,
> +     VIRTCHNL_PROTO_HDR_GTPC,
> +     VIRTCHNL_PROTO_HDR_ECPRI,
> +     VIRTCHNL_PROTO_HDR_L2TPV2,
> +     VIRTCHNL_PROTO_HDR_PPP,
> +     /* IPv4 and IPv6 Fragment header types are only associated to
> +      * VIRTCHNL_PROTO_HDR_IPV4 and VIRTCHNL_PROTO_HDR_IPV6
> respectively,
> +      * cannot be used independently.
> +      */
> +     VIRTCHNL_PROTO_HDR_IPV4_FRAG,
> +     VIRTCHNL_PROTO_HDR_IPV6_EH_FRAG,
> +     VIRTCHNL_PROTO_HDR_GRE,
>  };
> 
>  /* Protocol header field within a protocol header. */
> @@ -1275,6 +1286,7 @@ enum virtchnl_proto_hdr_field {
>       VIRTCHNL_PROTO_HDR_IPV4_DSCP,
>       VIRTCHNL_PROTO_HDR_IPV4_TTL,
>       VIRTCHNL_PROTO_HDR_IPV4_PROT,
> +     VIRTCHNL_PROTO_HDR_IPV4_CHKSUM,
>       /* IPV6 */
>       VIRTCHNL_PROTO_HDR_IPV6_SRC =
>               PROTO_HDR_FIELD_START(VIRTCHNL_PROTO_HDR_IPV6),
> @@ -1282,18 +1294,34 @@ enum virtchnl_proto_hdr_field {
>       VIRTCHNL_PROTO_HDR_IPV6_TC,
>       VIRTCHNL_PROTO_HDR_IPV6_HOP_LIMIT,
>       VIRTCHNL_PROTO_HDR_IPV6_PROT,
> +     /* IPV6 Prefix */
> +     VIRTCHNL_PROTO_HDR_IPV6_PREFIX32_SRC,
> +     VIRTCHNL_PROTO_HDR_IPV6_PREFIX32_DST,
> +     VIRTCHNL_PROTO_HDR_IPV6_PREFIX40_SRC,
> +     VIRTCHNL_PROTO_HDR_IPV6_PREFIX40_DST,
> +     VIRTCHNL_PROTO_HDR_IPV6_PREFIX48_SRC,
> +     VIRTCHNL_PROTO_HDR_IPV6_PREFIX48_DST,
> +     VIRTCHNL_PROTO_HDR_IPV6_PREFIX56_SRC,
> +     VIRTCHNL_PROTO_HDR_IPV6_PREFIX56_DST,
> +     VIRTCHNL_PROTO_HDR_IPV6_PREFIX64_SRC,
> +     VIRTCHNL_PROTO_HDR_IPV6_PREFIX64_DST,
> +     VIRTCHNL_PROTO_HDR_IPV6_PREFIX96_SRC,
> +     VIRTCHNL_PROTO_HDR_IPV6_PREFIX96_DST,
>       /* TCP */
>       VIRTCHNL_PROTO_HDR_TCP_SRC_PORT =
>               PROTO_HDR_FIELD_START(VIRTCHNL_PROTO_HDR_TCP),
>       VIRTCHNL_PROTO_HDR_TCP_DST_PORT,
> +     VIRTCHNL_PROTO_HDR_TCP_CHKSUM,
>       /* UDP */
>       VIRTCHNL_PROTO_HDR_UDP_SRC_PORT =
>               PROTO_HDR_FIELD_START(VIRTCHNL_PROTO_HDR_UDP),
>       VIRTCHNL_PROTO_HDR_UDP_DST_PORT,
> +     VIRTCHNL_PROTO_HDR_UDP_CHKSUM,
>       /* SCTP */
>       VIRTCHNL_PROTO_HDR_SCTP_SRC_PORT =
>               PROTO_HDR_FIELD_START(VIRTCHNL_PROTO_HDR_SCTP),
>       VIRTCHNL_PROTO_HDR_SCTP_DST_PORT,
> +     VIRTCHNL_PROTO_HDR_SCTP_CHKSUM,
>       /* GTPU_IP */
>       VIRTCHNL_PROTO_HDR_GTPU_IP_TEID =
> 
>       PROTO_HDR_FIELD_START(VIRTCHNL_PROTO_HDR_GTPU_IP),
> @@ -1317,6 +1345,28 @@ enum virtchnl_proto_hdr_field {
>       VIRTCHNL_PROTO_HDR_PFCP_S_FIELD =
>               PROTO_HDR_FIELD_START(VIRTCHNL_PROTO_HDR_PFCP),
>       VIRTCHNL_PROTO_HDR_PFCP_SEID,
> +     /* GTPC */
> +     VIRTCHNL_PROTO_HDR_GTPC_TEID =
> +             PROTO_HDR_FIELD_START(VIRTCHNL_PROTO_HDR_GTPC),
> +     /* ECPRI */
> +     VIRTCHNL_PROTO_HDR_ECPRI_MSG_TYPE =
> +             PROTO_HDR_FIELD_START(VIRTCHNL_PROTO_HDR_ECPRI),
> +     VIRTCHNL_PROTO_HDR_ECPRI_PC_RTC_ID,
> +     /* IPv4 Dummy Fragment */
> +     VIRTCHNL_PROTO_HDR_IPV4_FRAG_PKID =
> +
>       PROTO_HDR_FIELD_START(VIRTCHNL_PROTO_HDR_IPV4_FRAG),
> +     /* IPv6 Extension Fragment */
> +     VIRTCHNL_PROTO_HDR_IPV6_EH_FRAG_PKID =
> +
>       PROTO_HDR_FIELD_START(VIRTCHNL_PROTO_HDR_IPV6_EH_FRAG),
> +     /* GTPU_DWN/UP */
> +     VIRTCHNL_PROTO_HDR_GTPU_DWN_QFI =
> +
>       PROTO_HDR_FIELD_START(VIRTCHNL_PROTO_HDR_GTPU_EH_PDU_
> DWN),
> +     VIRTCHNL_PROTO_HDR_GTPU_UP_QFI =
> +
>       PROTO_HDR_FIELD_START(VIRTCHNL_PROTO_HDR_GTPU_EH_PDU_
> UP),
> +     /* L2TPv2 */
> +     VIRTCHNL_PROTO_HDR_L2TPV2_SESS_ID =
> +             PROTO_HDR_FIELD_START(VIRTCHNL_PROTO_HDR_L2TPV2),
> +     VIRTCHNL_PROTO_HDR_L2TPV2_LEN_SESS_ID,
>  };
> 
>  struct virtchnl_proto_hdr {
> --
> 2.47.1


Tested-by: Rafal Romanowski <[email protected]>


Reply via email to