ICE_PKT_GTP_NOPAY       = BIT(8),
        ICE_PKT_KMALLOC         = BIT(9),
        ICE_PKT_PPPOE           = BIT(10),
+       ICE_PKT_L2TPV3          = BIT(11),
 };
 
 struct ice_dummy_pkt_offsets {
        0x00, 0x00,             /* 2 bytes for 4 bytes alignment */
 };
 
+ICE_DECLARE_PKT_OFFSETS(ipv4_l2tpv3) = {
+       { ICE_MAC_OFOS,         0 },
+       { ICE_ETYPE_OL,         12 },
+       { ICE_IPV4_OFOS,        14 },
+       { ICE_L2TPV3,           34 },
+       { ICE_PROTOCOL_LAST,    0 },
+};
+
+ICE_DECLARE_PKT_TEMPLATE(ipv4_l2tpv3) = {
+       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, 0x20, /* ICE_IPV4_IL 14 */
+       0x00, 0x00, 0x40, 0x00,
+       0x40, 0x73, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x00, 0x00, 0x00, 0x00, /* ICE_L2TPV3 34 */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00,             /* 2 bytes for 4 bytes alignment */
+};
+
+ICE_DECLARE_PKT_OFFSETS(ipv6_l2tpv3) = {
+       { ICE_MAC_OFOS,         0 },
+       { ICE_ETYPE_OL,         12 },
+       { ICE_IPV6_OFOS,        14 },
+       { ICE_L2TPV3,           54 },
+       { ICE_PROTOCOL_LAST,    0 },
+};
+
+ICE_DECLARE_PKT_TEMPLATE(ipv6_l2tpv3) = {
+       0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x86, 0xDD,             /* ICE_ETYPE_OL 12 */
+
+       0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_IL 14 */
+       0x00, 0x0c, 0x73, 0x40,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x00, 0x00, 0x00, 0x00, /* ICE_L2TPV3 54 */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00,             /* 2 bytes for 4 bytes alignment */
+};
+
 static const struct ice_dummy_pkt_profile ice_dummy_pkt_profiles[] = {
        ICE_PKT_PROFILE(ipv6_gtp, ICE_PKT_TUN_GTPU | ICE_PKT_OUTER_IPV6 |
                                  ICE_PKT_GTP_NOPAY),
        ICE_PKT_PROFILE(udp_tun_ipv6_tcp, ICE_PKT_TUN_UDP |
                                          ICE_PKT_INNER_IPV6 |
                                          ICE_PKT_INNER_TCP),
+       ICE_PKT_PROFILE(ipv6_l2tpv3, ICE_PKT_L2TPV3 | ICE_PKT_OUTER_IPV6),
+       ICE_PKT_PROFILE(ipv4_l2tpv3, ICE_PKT_L2TPV3),
        ICE_PKT_PROFILE(udp_tun_tcp, ICE_PKT_TUN_UDP | ICE_PKT_INNER_TCP),
        ICE_PKT_PROFILE(udp_tun_ipv6_udp, ICE_PKT_TUN_UDP |
                                          ICE_PKT_INNER_IPV6),
        { ICE_GTP,              { 8, 10, 12, 14, 16, 18, 20, 22 } },
        { ICE_GTP_NO_PAY,       { 8, 10, 12, 14 } },
        { ICE_PPPOE,            { 0, 2, 4, 6 } },
+       { ICE_L2TPV3,           { 0, 2, 4, 6, 8, 10 } },
        { ICE_VLAN_EX,          { 2, 0 } },
        { ICE_VLAN_IN,          { 2, 0 } },
 };
        { ICE_GTP,              ICE_UDP_OF_HW },
        { ICE_GTP_NO_PAY,       ICE_UDP_ILOS_HW },
        { ICE_PPPOE,            ICE_PPPOE_HW },
+       { ICE_L2TPV3,           ICE_L2TPV3_HW },
        { ICE_VLAN_EX,          ICE_VLAN_OF_HW },
        { ICE_VLAN_IN,          ICE_VLAN_OL_HW },
 };
                        if (lkups[i].h_u.pppoe_hdr.ppp_prot_id ==
                            htons(PPP_IPV6))
                                match |= ICE_PKT_OUTER_IPV6;
-               }
+               } else if (lkups[i].type == ICE_L2TPV3)
+                       match |= ICE_PKT_L2TPV3;
        }
 
        while (ret->match && (match & ret->match) != ret->match)
                case ICE_PPPOE:
                        len = sizeof(struct ice_pppoe_hdr);
                        break;
+               case ICE_L2TPV3:
+                       len = sizeof(struct ice_l2tpv3_sess_hdr);
+                       break;
                default:
                        return -EINVAL;
                }
 
        if (flags & (ICE_TC_FLWR_FIELD_IP_TOS | ICE_TC_FLWR_FIELD_IP_TTL))
                lkups_cnt++;
 
+       /* are L2TPv3 options specified? */
+       if (flags & ICE_TC_FLWR_FIELD_L2TPV3_SESSID)
+               lkups_cnt++;
+
        /* is L4 (TCP/UDP/any other L4 protocol fields) specified? */
        if (flags & (ICE_TC_FLWR_FIELD_DEST_L4_PORT |
                     ICE_TC_FLWR_FIELD_SRC_L4_PORT))
                i++;
        }
 
+       if (flags & ICE_TC_FLWR_FIELD_L2TPV3_SESSID) {
+               list[i].type = ICE_L2TPV3;
+
+               list[i].h_u.l2tpv3_sess_hdr.session_id =
+                       headers->l2tpv3_hdr.session_id;
+               list[i].m_u.l2tpv3_sess_hdr.session_id =
+                       cpu_to_be32(0xFFFFFFFF);
+
+               i++;
+       }
+
        /* copy L4 (src, dest) port */
        if (flags & (ICE_TC_FLWR_FIELD_DEST_L4_PORT |
                     ICE_TC_FLWR_FIELD_SRC_L4_PORT)) {
              BIT(FLOW_DISSECTOR_KEY_IP) |
              BIT(FLOW_DISSECTOR_KEY_ENC_IP) |
              BIT(FLOW_DISSECTOR_KEY_PORTS) |
-             BIT(FLOW_DISSECTOR_KEY_PPPOE))) {
+             BIT(FLOW_DISSECTOR_KEY_PPPOE) |
+             BIT(FLOW_DISSECTOR_KEY_L2TPV3))) {
                NL_SET_ERR_MSG_MOD(fltr->extack, "Unsupported key used");
                return -EOPNOTSUPP;
        }
                ice_tc_set_tos_ttl(&match, fltr, headers, false);
        }
 
+       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_L2TPV3)) {
+               struct flow_match_l2tpv3 match;
+
+               flow_rule_match_l2tpv3(rule, &match);
+
+               fltr->flags |= ICE_TC_FLWR_FIELD_L2TPV3_SESSID;
+               headers->l2tpv3_hdr.session_id = match.key->session_id;
+       }
+
        if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
                struct flow_match_ports match;