net/sfc/base: import filters support
[dpdk.git] / drivers / net / sfc / base / efx_filter.c
1 /*
2  * Copyright (c) 2007-2016 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  */
30
31 #include "efx.h"
32 #include "efx_impl.h"
33
34
35 #if EFSYS_OPT_FILTER
36
37         __checkReturn   efx_rc_t
38 efx_filter_insert(
39         __in            efx_nic_t *enp,
40         __inout         efx_filter_spec_t *spec)
41 {
42         const efx_filter_ops_t *efop = enp->en_efop;
43
44         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
45         EFSYS_ASSERT3P(spec, !=, NULL);
46         EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
47
48         return (efop->efo_add(enp, spec, B_FALSE));
49 }
50
51         __checkReturn   efx_rc_t
52 efx_filter_remove(
53         __in            efx_nic_t *enp,
54         __inout         efx_filter_spec_t *spec)
55 {
56         const efx_filter_ops_t *efop = enp->en_efop;
57
58         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
59         EFSYS_ASSERT3P(spec, !=, NULL);
60         EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
61
62         return (efop->efo_delete(enp, spec));
63 }
64
65         __checkReturn   efx_rc_t
66 efx_filter_restore(
67         __in            efx_nic_t *enp)
68 {
69         efx_rc_t rc;
70
71         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
72
73         if ((rc = enp->en_efop->efo_restore(enp)) != 0)
74                 goto fail1;
75
76         return (0);
77
78 fail1:
79         EFSYS_PROBE1(fail1, efx_rc_t, rc);
80
81         return (rc);
82 }
83
84         __checkReturn   efx_rc_t
85 efx_filter_init(
86         __in            efx_nic_t *enp)
87 {
88         const efx_filter_ops_t *efop;
89         efx_rc_t rc;
90
91         /* Check that efx_filter_spec_t is 64 bytes. */
92         EFX_STATIC_ASSERT(sizeof (efx_filter_spec_t) == 64);
93
94         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
95         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
96         EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER));
97
98         switch (enp->en_family) {
99
100         default:
101                 EFSYS_ASSERT(0);
102                 rc = ENOTSUP;
103                 goto fail1;
104         }
105
106         if ((rc = efop->efo_init(enp)) != 0)
107                 goto fail2;
108
109         enp->en_efop = efop;
110         enp->en_mod_flags |= EFX_MOD_FILTER;
111         return (0);
112
113 fail2:
114         EFSYS_PROBE(fail2);
115 fail1:
116         EFSYS_PROBE1(fail1, efx_rc_t, rc);
117
118         enp->en_efop = NULL;
119         enp->en_mod_flags &= ~EFX_MOD_FILTER;
120         return (rc);
121 }
122
123                         void
124 efx_filter_fini(
125         __in            efx_nic_t *enp)
126 {
127         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
128         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
129         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
130
131         enp->en_efop->efo_fini(enp);
132
133         enp->en_efop = NULL;
134         enp->en_mod_flags &= ~EFX_MOD_FILTER;
135 }
136
137         __checkReturn   efx_rc_t
138 efx_filter_supported_filters(
139         __in            efx_nic_t *enp,
140         __out           uint32_t *list,
141         __out           size_t *length)
142 {
143         efx_rc_t rc;
144
145         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
146         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
147         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
148         EFSYS_ASSERT(enp->en_efop->efo_supported_filters != NULL);
149
150         if ((rc = enp->en_efop->efo_supported_filters(enp, list, length)) != 0)
151                 goto fail1;
152
153         return (0);
154
155 fail1:
156         EFSYS_PROBE1(fail1, efx_rc_t, rc);
157
158         return (rc);
159 }
160
161         __checkReturn   efx_rc_t
162 efx_filter_reconfigure(
163         __in                            efx_nic_t *enp,
164         __in_ecount(6)                  uint8_t const *mac_addr,
165         __in                            boolean_t all_unicst,
166         __in                            boolean_t mulcst,
167         __in                            boolean_t all_mulcst,
168         __in                            boolean_t brdcst,
169         __in_ecount(6*count)            uint8_t const *addrs,
170         __in                            uint32_t count)
171 {
172         efx_rc_t rc;
173
174         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
175         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
176         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
177
178         if (enp->en_efop->efo_reconfigure != NULL) {
179                 if ((rc = enp->en_efop->efo_reconfigure(enp, mac_addr,
180                                                         all_unicst, mulcst,
181                                                         all_mulcst, brdcst,
182                                                         addrs, count)) != 0)
183                         goto fail1;
184         }
185
186         return (0);
187
188 fail1:
189         EFSYS_PROBE1(fail1, efx_rc_t, rc);
190
191         return (rc);
192 }
193
194                 void
195 efx_filter_spec_init_rx(
196         __out           efx_filter_spec_t *spec,
197         __in            efx_filter_priority_t priority,
198         __in            efx_filter_flags_t flags,
199         __in            efx_rxq_t *erp)
200 {
201         EFSYS_ASSERT3P(spec, !=, NULL);
202         EFSYS_ASSERT3P(erp, !=, NULL);
203         EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
204                                 EFX_FILTER_FLAG_RX_SCATTER)) == 0);
205
206         memset(spec, 0, sizeof (*spec));
207         spec->efs_priority = priority;
208         spec->efs_flags = EFX_FILTER_FLAG_RX | flags;
209         spec->efs_rss_context = EFX_FILTER_SPEC_RSS_CONTEXT_DEFAULT;
210         spec->efs_dmaq_id = (uint16_t)erp->er_index;
211 }
212
213                 void
214 efx_filter_spec_init_tx(
215         __out           efx_filter_spec_t *spec,
216         __in            efx_txq_t *etp)
217 {
218         EFSYS_ASSERT3P(spec, !=, NULL);
219         EFSYS_ASSERT3P(etp, !=, NULL);
220
221         memset(spec, 0, sizeof (*spec));
222         spec->efs_priority = EFX_FILTER_PRI_REQUIRED;
223         spec->efs_flags = EFX_FILTER_FLAG_TX;
224         spec->efs_dmaq_id = (uint16_t)etp->et_index;
225 }
226
227
228 /*
229  *  Specify IPv4 host, transport protocol and port in a filter specification
230  */
231 __checkReturn           efx_rc_t
232 efx_filter_spec_set_ipv4_local(
233         __inout         efx_filter_spec_t *spec,
234         __in            uint8_t proto,
235         __in            uint32_t host,
236         __in            uint16_t port)
237 {
238         EFSYS_ASSERT3P(spec, !=, NULL);
239
240         spec->efs_match_flags |=
241                 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
242                 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
243         spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
244         spec->efs_ip_proto = proto;
245         spec->efs_loc_host.eo_u32[0] = host;
246         spec->efs_loc_port = port;
247         return (0);
248 }
249
250 /*
251  * Specify IPv4 hosts, transport protocol and ports in a filter specification
252  */
253 __checkReturn           efx_rc_t
254 efx_filter_spec_set_ipv4_full(
255         __inout         efx_filter_spec_t *spec,
256         __in            uint8_t proto,
257         __in            uint32_t lhost,
258         __in            uint16_t lport,
259         __in            uint32_t rhost,
260         __in            uint16_t rport)
261 {
262         EFSYS_ASSERT3P(spec, !=, NULL);
263
264         spec->efs_match_flags |=
265                 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
266                 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
267                 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
268         spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
269         spec->efs_ip_proto = proto;
270         spec->efs_loc_host.eo_u32[0] = lhost;
271         spec->efs_loc_port = lport;
272         spec->efs_rem_host.eo_u32[0] = rhost;
273         spec->efs_rem_port = rport;
274         return (0);
275 }
276
277 /*
278  * Specify local Ethernet address and/or VID in filter specification
279  */
280 __checkReturn           efx_rc_t
281 efx_filter_spec_set_eth_local(
282         __inout         efx_filter_spec_t *spec,
283         __in            uint16_t vid,
284         __in            const uint8_t *addr)
285 {
286         EFSYS_ASSERT3P(spec, !=, NULL);
287         EFSYS_ASSERT3P(addr, !=, NULL);
288
289         if (vid == EFX_FILTER_SPEC_VID_UNSPEC && addr == NULL)
290                 return (EINVAL);
291
292         if (vid != EFX_FILTER_SPEC_VID_UNSPEC) {
293                 spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID;
294                 spec->efs_outer_vid = vid;
295         }
296         if (addr != NULL) {
297                 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
298                 memcpy(spec->efs_loc_mac, addr, EFX_MAC_ADDR_LEN);
299         }
300         return (0);
301 }
302
303 /*
304  * Specify matching otherwise-unmatched unicast in a filter specification
305  */
306 __checkReturn           efx_rc_t
307 efx_filter_spec_set_uc_def(
308         __inout         efx_filter_spec_t *spec)
309 {
310         EFSYS_ASSERT3P(spec, !=, NULL);
311
312         spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
313         return (0);
314 }
315
316 /*
317  * Specify matching otherwise-unmatched multicast in a filter specification
318  */
319 __checkReturn           efx_rc_t
320 efx_filter_spec_set_mc_def(
321         __inout         efx_filter_spec_t *spec)
322 {
323         EFSYS_ASSERT3P(spec, !=, NULL);
324
325         spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
326         spec->efs_loc_mac[0] = 1;
327         return (0);
328 }
329
330
331
332 #endif /* EFSYS_OPT_FILTER */