Author: arybchik
Date: Fri Nov 23 09:03:20 2018
New Revision: 340803
URL: https://svnweb.freebsd.org/changeset/base/340803

Log:
  sfxge(4): support filters for encapsulated packets
  
  This supports filters which match all unicast or multicast
  inner frames in VXLAN, GENEVE, or NVGRE packets.
  (Additional fields to match on can be added easily.)
  
  Submitted by:   Mark Spender <mspender at solarflare.com>
  Sponsored by:   Solarflare Communications, Inc.
  Differential Revision:  https://reviews.freebsd.org/D18073

Modified:
  head/sys/dev/sfxge/common/ef10_filter.c
  head/sys/dev/sfxge/common/efx.h
  head/sys/dev/sfxge/common/efx_filter.c

Modified: head/sys/dev/sfxge/common/ef10_filter.c
==============================================================================
--- head/sys/dev/sfxge/common/ef10_filter.c     Fri Nov 23 09:03:09 2018        
(r340802)
+++ head/sys/dev/sfxge/common/ef10_filter.c     Fri Nov 23 09:03:20 2018        
(r340803)
@@ -145,6 +145,10 @@ ef10_filter_init(
            MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_OUTER_VLAN));
        EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IP_PROTO ==
            MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IP_PROTO));
+       EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST ==
+           MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_MCAST_DST));
+       EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST ==
+           MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_UCAST_DST));
        EFX_STATIC_ASSERT(EFX_FILTER_MATCH_UNKNOWN_MCAST_DST ==
            MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_MCAST_DST));
        EFX_STATIC_ASSERT((uint32_t)EFX_FILTER_MATCH_UNKNOWN_UCAST_DST ==
@@ -274,18 +278,47 @@ efx_mcdi_filter_op_add(
                memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_DST_IP),
                    &spec->efs_loc_host.eo_byte[0],
                    MC_CMD_FILTER_OP_EXT_IN_DST_IP_LEN);
+
+               /*
+                * On Medford, filters for encapsulated packets match based on
+                * the ether type and IP protocol in the outer frame.  In
+                * addition we need to fill in the VNI or VSID type field.
+                */
+               switch (spec->efs_encap_type) {
+               case EFX_TUNNEL_PROTOCOL_NONE:
+                       break;
+               case EFX_TUNNEL_PROTOCOL_VXLAN:
+               case EFX_TUNNEL_PROTOCOL_GENEVE:
+                       MCDI_IN_POPULATE_DWORD_1(req,
+                           FILTER_OP_EXT_IN_VNI_OR_VSID,
+                           FILTER_OP_EXT_IN_VNI_TYPE,
+                           spec->efs_encap_type == EFX_TUNNEL_PROTOCOL_VXLAN ?
+                                   MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_VXLAN :
+                                   MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_GENEVE);
+                       break;
+               case EFX_TUNNEL_PROTOCOL_NVGRE:
+                       MCDI_IN_POPULATE_DWORD_1(req,
+                           FILTER_OP_EXT_IN_VNI_OR_VSID,
+                           FILTER_OP_EXT_IN_VSID_TYPE,
+                           MC_CMD_FILTER_OP_EXT_IN_VSID_TYPE_NVGRE);
+                       break;
+               default:
+                       EFSYS_ASSERT(0);
+                       rc = EINVAL;
+                       goto fail2;
+               }
        }
 
        efx_mcdi_execute(enp, &req);
 
        if (req.emr_rc != 0) {
                rc = req.emr_rc;
-               goto fail2;
+               goto fail3;
        }
 
        if (req.emr_out_length_used < MC_CMD_FILTER_OP_EXT_OUT_LEN) {
                rc = EMSGSIZE;
-               goto fail3;
+               goto fail4;
        }
 
        handle->efh_lo = MCDI_OUT_DWORD(req, FILTER_OP_EXT_OUT_HANDLE_LO);
@@ -293,6 +326,8 @@ efx_mcdi_filter_op_add(
 
        return (0);
 
+fail4:
+       EFSYS_PROBE(fail4);
 fail3:
        EFSYS_PROBE(fail3);
 fail2:
@@ -392,6 +427,8 @@ ef10_filter_equal(
        if (left->efs_ether_type != right->efs_ether_type)
                return (B_FALSE);
        if (left->efs_ip_proto != right->efs_ip_proto)
+               return (B_FALSE);
+       if (left->efs_encap_type != right->efs_encap_type)
                return (B_FALSE);
 
        return (B_TRUE);

Modified: head/sys/dev/sfxge/common/efx.h
==============================================================================
--- head/sys/dev/sfxge/common/efx.h     Fri Nov 23 09:03:09 2018        
(r340802)
+++ head/sys/dev/sfxge/common/efx.h     Fri Nov 23 09:03:20 2018        
(r340803)
@@ -2230,6 +2230,7 @@ efx_tx_qdestroy(
 
 #define        EFX_IPPROTO_TCP 6
 #define        EFX_IPPROTO_UDP 17
+#define        EFX_IPPROTO_GRE 47
 
 /* Use RSS to spread across multiple queues */
 #define        EFX_FILTER_FLAG_RX_RSS          0x01
@@ -2248,6 +2249,10 @@ efx_tx_qdestroy(
 
 typedef unsigned int efx_filter_flags_t;
 
+/*
+ * Flags which specify the fields to match on. The values are the same as in 
the
+ * MC_CMD_FILTER_OP/MC_CMD_FILTER_OP_EXT commands.
+ */
 typedef enum efx_filter_match_flags_e {
        EFX_FILTER_MATCH_REM_HOST = 0x0001,     /* Match by remote IP host
                                                 * address */
@@ -2262,6 +2267,10 @@ typedef enum efx_filter_match_flags_e {
        EFX_FILTER_MATCH_OUTER_VID = 0x0100,    /* Match by outer VLAN ID */
        EFX_FILTER_MATCH_IP_PROTO = 0x0200,     /* Match by IP transport
                                                 * protocol */
+       /* For encapsulated packets, match all multicast inner frames */
+       EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST = 0x01000000,
+       /* For encapsulated packets, match all unicast inner frames */
+       EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST = 0x02000000,
        /* Match otherwise-unmatched multicast and broadcast packets */
        EFX_FILTER_MATCH_UNKNOWN_MCAST_DST = 0x40000000,
        /* Match otherwise-unmatched unicast packets */
@@ -2287,21 +2296,22 @@ typedef enum efx_filter_priority_s {
  */
 
 typedef struct efx_filter_spec_s {
-       uint32_t        efs_match_flags;
-       uint32_t        efs_priority:2;
-       uint32_t        efs_flags:6;
-       uint32_t        efs_dmaq_id:12;
-       uint32_t        efs_rss_context;
-       uint16_t        efs_outer_vid;
-       uint16_t        efs_inner_vid;
-       uint8_t         efs_loc_mac[EFX_MAC_ADDR_LEN];
-       uint8_t         efs_rem_mac[EFX_MAC_ADDR_LEN];
-       uint16_t        efs_ether_type;
-       uint8_t         efs_ip_proto;
-       uint16_t        efs_loc_port;
-       uint16_t        efs_rem_port;
-       efx_oword_t     efs_rem_host;
-       efx_oword_t     efs_loc_host;
+       uint32_t                efs_match_flags;
+       uint32_t                efs_priority:2;
+       uint32_t                efs_flags:6;
+       uint32_t                efs_dmaq_id:12;
+       uint32_t                efs_rss_context;
+       uint16_t                efs_outer_vid;
+       uint16_t                efs_inner_vid;
+       uint8_t                 efs_loc_mac[EFX_MAC_ADDR_LEN];
+       uint8_t                 efs_rem_mac[EFX_MAC_ADDR_LEN];
+       uint16_t                efs_ether_type;
+       uint8_t                 efs_ip_proto;
+       efx_tunnel_protocol_t   efs_encap_type;
+       uint16_t                efs_loc_port;
+       uint16_t                efs_rem_port;
+       efx_oword_t             efs_rem_host;
+       efx_oword_t             efs_loc_host;
 } efx_filter_spec_t;
 
 
@@ -2373,6 +2383,11 @@ efx_filter_spec_set_eth_local(
        __in            uint16_t vid,
        __in            const uint8_t *addr);
 
+extern                 void
+efx_filter_spec_set_ether_type(
+       __inout         efx_filter_spec_t *spec,
+       __in            uint16_t ether_type);
+
 extern __checkReturn   efx_rc_t
 efx_filter_spec_set_uc_def(
        __inout         efx_filter_spec_t *spec);
@@ -2380,6 +2395,19 @@ efx_filter_spec_set_uc_def(
 extern __checkReturn   efx_rc_t
 efx_filter_spec_set_mc_def(
        __inout         efx_filter_spec_t *spec);
+
+typedef enum efx_filter_inner_frame_match_e {
+       EFX_FILTER_INNER_FRAME_MATCH_OTHER = 0,
+       EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_MCAST_DST,
+       EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_UCAST_DST
+} efx_filter_inner_frame_match_t;
+
+extern __checkReturn   efx_rc_t
+efx_filter_spec_set_encap_type(
+       __inout         efx_filter_spec_t *spec,
+       __in            efx_tunnel_protocol_t encap_type,
+       __in            efx_filter_inner_frame_match_t inner_frame_match);
+
 
 #endif /* EFSYS_OPT_FILTER */
 

Modified: head/sys/dev/sfxge/common/efx_filter.c
==============================================================================
--- head/sys/dev/sfxge/common/efx_filter.c      Fri Nov 23 09:03:09 2018        
(r340802)
+++ head/sys/dev/sfxge/common/efx_filter.c      Fri Nov 23 09:03:20 2018        
(r340803)
@@ -401,6 +401,17 @@ efx_filter_spec_set_eth_local(
        return (0);
 }
 
+                       void
+efx_filter_spec_set_ether_type(
+       __inout         efx_filter_spec_t *spec,
+       __in            uint16_t ether_type)
+{
+       EFSYS_ASSERT3P(spec, !=, NULL);
+
+       spec->efs_ether_type = ether_type;
+       spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
+}
+
 /*
  * Specify matching otherwise-unmatched unicast in a filter specification
  */
@@ -425,6 +436,63 @@ efx_filter_spec_set_mc_def(
 
        spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
        return (0);
+}
+
+
+__checkReturn          efx_rc_t
+efx_filter_spec_set_encap_type(
+       __inout         efx_filter_spec_t *spec,
+       __in            efx_tunnel_protocol_t encap_type,
+       __in            efx_filter_inner_frame_match_t inner_frame_match)
+{
+       uint32_t match_flags = 0;
+       uint8_t ip_proto;
+       efx_rc_t rc;
+
+       EFSYS_ASSERT3P(spec, !=, NULL);
+
+       switch (encap_type) {
+       case EFX_TUNNEL_PROTOCOL_VXLAN:
+       case EFX_TUNNEL_PROTOCOL_GENEVE:
+               ip_proto = EFX_IPPROTO_UDP;
+               break;
+       case EFX_TUNNEL_PROTOCOL_NVGRE:
+               ip_proto = EFX_IPPROTO_GRE;
+               break;
+       default:
+               EFSYS_ASSERT(0);
+               rc = EINVAL;
+               goto fail1;
+       }
+
+       switch (inner_frame_match) {
+       case EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_MCAST_DST:
+               match_flags |= EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST;
+               break;
+       case EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_UCAST_DST:
+               match_flags |= EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST;
+               break;
+       case EFX_FILTER_INNER_FRAME_MATCH_OTHER:
+               /* This is for when specific inner frames are to be matched. */
+               break;
+       default:
+               EFSYS_ASSERT(0);
+               rc = EINVAL;
+               goto fail2;
+       }
+
+       spec->efs_encap_type = encap_type;
+       spec->efs_ip_proto = ip_proto;
+       spec->efs_match_flags |= (match_flags | EFX_FILTER_MATCH_IP_PROTO);
+
+       return (0);
+
+fail2:
+       EFSYS_PROBE(fail2);
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+       return (rc);
 }
 
 
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to