return ESP_V6_FLOW;
        case IAVF_FDIR_FLOW_IPV6_OTHER:
                return IPV6_USER_FLOW;
+       case IAVF_FDIR_FLOW_NON_IP_L2:
+               return ETHER_FLOW;
        default:
                /* 0 is undefined ethtool flow */
                return 0;
                return IAVF_FDIR_FLOW_IPV6_ESP;
        case IPV6_USER_FLOW:
                return IAVF_FDIR_FLOW_IPV6_OTHER;
+       case ETHER_FLOW:
+               return IAVF_FDIR_FLOW_NON_IP_L2;
        default:
                return IAVF_FDIR_FLOW_NONE;
        }
                fsp->m_u.usr_ip6_spec.tclass = rule->ip_mask.tclass;
                fsp->m_u.usr_ip6_spec.l4_proto = rule->ip_mask.proto;
                break;
+       case ETHER_FLOW:
+               fsp->h_u.ether_spec.h_proto = rule->eth_data.etype;
+               fsp->m_u.ether_spec.h_proto = rule->eth_mask.etype;
+               break;
        default:
                ret = -EINVAL;
                break;
                fltr->ip_mask.tclass = fsp->m_u.usr_ip6_spec.tclass;
                fltr->ip_mask.proto = fsp->m_u.usr_ip6_spec.l4_proto;
                break;
+       case ETHER_FLOW:
+               fltr->eth_data.etype = fsp->h_u.ether_spec.h_proto;
+               fltr->eth_mask.etype = fsp->m_u.ether_spec.h_proto;
+               break;
        default:
                /* not doing un-parsed flow types */
                return -EINVAL;
 
                       struct virtchnl_proto_hdrs *proto_hdrs)
 {
        struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
+       struct ethhdr *ehdr = (struct ethhdr *)hdr->buffer;
 
        VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ETH);
 
+       if (fltr->eth_mask.etype == htons(U16_MAX)) {
+               if (fltr->eth_data.etype == htons(ETH_P_IP) ||
+                   fltr->eth_data.etype == htons(ETH_P_IPV6))
+                       return -EOPNOTSUPP;
+
+               ehdr->h_proto = fltr->eth_data.etype;
+               VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ETH, ETHERTYPE);
+       }
+
        return 0;
 }
 
                err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
                      iavf_fill_fdir_l4_hdr(fltr, proto_hdrs);
                break;
+       case IAVF_FDIR_FLOW_NON_IP_L2:
+               break;
        default:
                err = -EINVAL;
                break;
        case IAVF_FDIR_FLOW_IPV4_OTHER:
        case IAVF_FDIR_FLOW_IPV6_OTHER:
                return "Other";
+       case IAVF_FDIR_FLOW_NON_IP_L2:
+               return "Ethernet";
        default:
                return NULL;
        }
                         fltr->ip_data.proto,
                         ntohl(fltr->ip_data.l4_header));
                break;
+       case IAVF_FDIR_FLOW_NON_IP_L2:
+               dev_info(&adapter->pdev->dev, "Rule ID: %u eth_type: 0x%x\n",
+                        fltr->loc,
+                        ntohs(fltr->eth_data.etype));
+               break;
        default:
                break;
        }
                if (tmp->flow_type != fltr->flow_type)
                        continue;
 
-               if (!memcmp(&tmp->ip_data, &fltr->ip_data,
+               if (!memcmp(&tmp->eth_data, &fltr->eth_data,
+                           sizeof(fltr->eth_data)) &&
+                   !memcmp(&tmp->ip_data, &fltr->ip_data,
                            sizeof(fltr->ip_data))) {
                        ret = true;
                        break;
 
        IAVF_FDIR_FLOW_IPV6_AH,
        IAVF_FDIR_FLOW_IPV6_ESP,
        IAVF_FDIR_FLOW_IPV6_OTHER,
+       IAVF_FDIR_FLOW_NON_IP_L2,
        /* MAX - this must be last and add anything new just above it */
        IAVF_FDIR_FLOW_PTYPE_MAX,
 };
        struct in6_addr dst_ip;
 };
 
+struct iavf_fdir_eth {
+       __be16 etype;
+};
+
 struct iavf_fdir_ip {
        union {
                struct iavf_ipv4_addrs v4_addrs;
 
        enum iavf_fdir_flow_type flow_type;
 
+       struct iavf_fdir_eth eth_data;
+       struct iavf_fdir_eth eth_mask;
+
        struct iavf_fdir_ip ip_data;
        struct iavf_fdir_ip ip_mask;