1 /* $NetBSD: if_laggproto.h,v 1.20 2023/11/28 05:28:37 yamaguchi Exp $ */
2
3 /*
4 * Copyright (c) 2021 Internet Initiative Japan Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #ifndef _NET_LAGG_IF_LAGGPROTO_H_
30 #define _NET_LAGG_IF_LAGGPROTO_H_
31
32 struct lagg_softc;
33 struct lagg_proto_softc;
34
35 #define LAGG_MAX_PORTS 32
36 #define LAGG_PORT_PRIO 0x8000U
37
38 enum lagg_work_state {
39 LAGG_WORK_IDLE,
40 LAGG_WORK_ENQUEUED,
41 LAGG_WORK_STOPPING
42 };
43 struct lagg_work {
44 struct work lw_cookie;
45 void (*lw_func)(struct lagg_work *, void *);
46 void *lw_arg;
47 int lw_state;
48 };
49
50 static inline void
lagg_work_set(struct lagg_work * w,void (* func)(struct lagg_work *,void *),void * arg)51 lagg_work_set(struct lagg_work *w,
52 void (*func)(struct lagg_work *, void *), void *arg)
53 {
54
55 w->lw_func = func;
56 w->lw_arg = arg;
57 }
58
59 struct workqueue *
60 lagg_workq_create(const char *, pri_t, int, int);
61 void lagg_workq_destroy(struct workqueue *);
62 void lagg_workq_add(struct workqueue *, struct lagg_work *);
63 void lagg_workq_wait(struct workqueue *, struct lagg_work *);
64
65 struct lagg_port {
66 struct psref_target lp_psref;
67 struct ifnet *lp_ifp; /* physical interface */
68 struct lagg_softc *lp_softc; /* parent lagg */
69 void *lp_proto_ctx;
70 bool lp_ifdetaching;
71 bool lp_promisc;
72 void *lp_linkstate_hook;
73 void *lp_ifdetach_hook;
74
75 uint32_t lp_prio; /* port priority */
76 uint32_t lp_flags; /* port flags */
77
78 u_char lp_iftype;
79 uint8_t lp_lladdr[ETHER_ADDR_LEN];
80 int lp_eccapenable;
81 uint64_t lp_ifcapenable;
82 uint64_t lp_mtu;
83
84 int (*lp_ioctl)(struct ifnet *, u_long, void *);
85 void (*lp_input)(struct ifnet *, struct mbuf *);
86 int (*lp_output)(struct ifnet *, struct mbuf *,
87 const struct sockaddr *,
88 const struct rtentry *);
89
90 SIMPLEQ_ENTRY(lagg_port)
91 lp_entry;
92 };
93
94 struct lagg_proto {
95 lagg_proto pr_num;
96 void (*pr_init)(void);
97 void (*pr_fini)(void);
98 int (*pr_attach)(struct lagg_softc *,
99 struct lagg_proto_softc **);
100 void (*pr_detach)(struct lagg_proto_softc *);
101 int (*pr_up)(struct lagg_proto_softc *);
102 void (*pr_down)(struct lagg_proto_softc *);
103 int (*pr_transmit)(struct lagg_proto_softc *,
104 struct mbuf *);
105 struct mbuf * (*pr_input)(struct lagg_proto_softc *,
106 struct lagg_port *, struct mbuf *);
107 int (*pr_allocport)(struct lagg_proto_softc *,
108 struct lagg_port *);
109 void (*pr_freeport)(struct lagg_proto_softc *,
110 struct lagg_port *);
111 void (*pr_startport)(struct lagg_proto_softc *,
112 struct lagg_port *);
113 void (*pr_stopport)(struct lagg_proto_softc *,
114 struct lagg_port *);
115 void (*pr_protostat)(struct lagg_proto_softc *,
116 struct laggreqproto *);
117 void (*pr_portstat)(struct lagg_proto_softc *,
118 struct lagg_port *, struct laggreqport *);
119 void (*pr_linkstate)(struct lagg_proto_softc *,
120 struct lagg_port *);
121 int (*pr_ioctl)(struct lagg_proto_softc *,
122 struct laggreqproto *);
123 };
124
125 struct lagg_variant {
126 lagg_proto lv_proto;
127 struct lagg_proto_softc
128 *lv_psc;
129
130 struct psref_target lv_psref;
131 };
132
133 struct lagg_mc_entry {
134 LIST_ENTRY(lagg_mc_entry)
135 mc_entry;
136 struct ether_multi *mc_enm;
137 struct sockaddr_storage mc_addr;
138 };
139
140 struct lagg_vlantag {
141 uint16_t lvt_vtag;
142 TAILQ_ENTRY(lagg_vlantag)
143 lvt_entry;
144 };
145
146 struct lagg_softc {
147 kmutex_t sc_lock;
148 struct ifmedia sc_media;
149 uint64_t sc_media_active;
150 u_char sc_iftype;
151
152 /* interface link-layer address */
153 uint8_t sc_lladdr[ETHER_ADDR_LEN];
154 /* generated random lladdr */
155 uint8_t sc_lladdr_rand[ETHER_ADDR_LEN];
156
157 LIST_HEAD(, lagg_mc_entry)
158 sc_mclist;
159 TAILQ_HEAD(, lagg_vlantag)
160 sc_vtags;
161 pserialize_t sc_psz;
162 struct lagg_variant *sc_var;
163 SIMPLEQ_HEAD(, lagg_port)
164 sc_ports;
165 size_t sc_nports;
166 char sc_evgroup[16];
167 struct evcnt sc_novar;
168
169 struct sysctllog *sc_sysctllog;
170 const struct sysctlnode *sc_sysctlnode;
171 bool sc_hash_mac;
172 bool sc_hash_ipaddr;
173 bool sc_hash_ip6addr;
174 bool sc_hash_tcp;
175 bool sc_hash_udp;
176
177 /*
178 * storage size of sc_if is a variable-length,
179 * should be the last
180 */
181 struct ifnet sc_if;
182 };
183
184 /*
185 * Locking notes:
186 * - sc_lock(LAGG_LOCK()) is an adaptive mutex and protects items
187 * of struct lagg_softc
188 * - a lock in struct lagg_proto_softc, for example LACP_LOCK(), is
189 * an adaptive mutex and protects member contained in the struct
190 * - sc_var is protected by both pselialize (sc_psz) and psref (lv_psref)
191 * - Updates of sc_var is serialized by sc_lock
192 * - Items in sc_ports is protected by both psref (lp_psref) and
193 * pserialize contained in struct lagg_proto_softc
194 * - details are described in if_laggport.c and if_lagg_lacp.c
195 * - Updates of items in sc_ports are serialized by sc_lock
196 * - an instance referenced by lp_proto_ctx in struct lagg_port is
197 * protected by a lock in struct lagg_proto_softc
198 *
199 * Locking order:
200 * - IFNET_LOCK(sc_if) -> LAGG_LOCK -> ETHER_LOCK(sc_if) -> a lock in
201 * struct lagg_port_softc
202 * - IFNET_LOCK(sc_if) -> LAGG_LOCK -> IFNET_LOCK(lp_ifp)
203 * - IFNET_LOCK(lp_ifp) -> a lock in struct lagg_proto_softc
204 * - Currently, there is no combination of following locks
205 * - IFNET_LOCK(lp_ifp) and ETHER_LOCK(sc_if)
206 */
207 #define LAGG_LOCK(_sc) mutex_enter(&(_sc)->sc_lock)
208 #define LAGG_UNLOCK(_sc) mutex_exit(&(_sc)->sc_lock)
209 #define LAGG_LOCKED(_sc) mutex_owned(&(_sc)->sc_lock)
210 #define LAGG_CLLADDR(_sc) CLLADDR((_sc)->sc_if.if_sadl)
211
212 #define LAGG_PORTS_FOREACH(_sc, _lp) \
213 SIMPLEQ_FOREACH((_lp), &(_sc)->sc_ports, lp_entry)
214 #define LAGG_PORTS_FIRST(_sc) SIMPLEQ_FIRST(&(_sc)->sc_ports)
215 #define LAGG_PORTS_EMPTY(_sc) SIMPLEQ_EMPTY(&(_sc)->sc_ports)
216 #define LAGG_PORT_IOCTL(_lp, _cmd, _data) \
217 (_lp)->lp_ioctl == NULL ? ENOTTY : \
218 (_lp)->lp_ioctl((_lp)->lp_ifp, (_cmd), (_data))
219
220 static inline const void *
lagg_m_extract(struct mbuf * m,size_t off,size_t reqlen,size_t align,void * buf)221 lagg_m_extract(struct mbuf *m, size_t off, size_t reqlen, size_t align,
222 void *buf)
223 {
224 ssize_t len;
225 const void *rv;
226
227 KASSERT(ISSET(m->m_flags, M_PKTHDR));
228 len = off + reqlen;
229
230 if (m->m_pkthdr.len < len) {
231 return NULL;
232 }
233
234 if (m->m_len >= len &&
235 ((uintptr_t)(mtod(m, uint8_t *) + off) % align) == 0) {
236 rv = mtod(m, uint8_t *) + off;
237 } else {
238 m_copydata(m, off, reqlen, buf);
239 rv = buf;
240 }
241
242 return rv;
243 }
244
245 static inline int
lagg_port_xmit(struct lagg_port * lp,struct mbuf * m)246 lagg_port_xmit(struct lagg_port *lp, struct mbuf *m)
247 {
248
249 return if_transmit_lock(lp->lp_ifp, m);
250 }
251
252 static inline bool
lagg_portactive(struct lagg_port * lp)253 lagg_portactive(struct lagg_port *lp)
254 {
255 struct ifnet *ifp;
256
257 ifp = lp->lp_ifp;
258
259 if (ifp->if_link_state != LINK_STATE_DOWN &&
260 ISSET(ifp->if_flags, IFF_UP)) {
261 return true;
262 }
263
264 return false;
265 }
266
267 static inline bool
lagg_debug_enable(struct lagg_softc * sc)268 lagg_debug_enable(struct lagg_softc *sc)
269 {
270 if (__predict_false(ISSET(sc->sc_if.if_flags, IFF_DEBUG)))
271 return true;
272
273 return false;
274 }
275
276 #define LAGG_LOG(_sc, _lvl, _fmt, _arg...) do { \
277 if ((_lvl) == LOG_DEBUG && \
278 !lagg_debug_enable(_sc)) \
279 break; \
280 \
281 log((_lvl), "%s: ", (_sc)->sc_if.if_xname); \
282 addlog((_fmt), ##_arg); \
283 } while(0)
284
285 void lagg_port_getref(struct lagg_port *, struct psref *);
286 void lagg_port_putref(struct lagg_port *, struct psref *);
287 void lagg_output(struct lagg_softc *,
288 struct lagg_port *, struct mbuf *);
289 uint32_t lagg_hashmbuf(struct lagg_softc *, struct mbuf *);
290 void lagg_set_linkspeed(struct lagg_softc *, uint64_t);
291
292 void lagg_common_detach(struct lagg_proto_softc *);
293 int lagg_common_allocport(struct lagg_proto_softc *,
294 struct lagg_port *);
295 void lagg_common_freeport(struct lagg_proto_softc *,
296 struct lagg_port *);
297 void lagg_common_startport(struct lagg_proto_softc *,
298 struct lagg_port *);
299 void lagg_common_stopport(struct lagg_proto_softc *,
300 struct lagg_port *);
301 void lagg_common_linkstate_ifnet_locked(struct lagg_proto_softc *,
302 struct lagg_port *);
303
304 int lagg_none_attach(struct lagg_softc *,
305 struct lagg_proto_softc **);
306
307 int lagg_fail_attach(struct lagg_softc *,
308 struct lagg_proto_softc **);
309 int lagg_fail_transmit(struct lagg_proto_softc *, struct mbuf *);
310 struct mbuf * lagg_fail_input(struct lagg_proto_softc *, struct lagg_port *,
311 struct mbuf *);
312 void lagg_fail_portstat(struct lagg_proto_softc *,
313 struct lagg_port *, struct laggreqport *);
314 int lagg_fail_ioctl(struct lagg_proto_softc *,
315 struct laggreqproto *);
316
317 int lagg_lb_attach(struct lagg_softc *, struct lagg_proto_softc **);
318 void lagg_lb_startport(struct lagg_proto_softc *,
319 struct lagg_port *);
320 void lagg_lb_stopport(struct lagg_proto_softc *, struct lagg_port *);
321 int lagg_lb_transmit(struct lagg_proto_softc *, struct mbuf *);
322 struct mbuf * lagg_lb_input(struct lagg_proto_softc *, struct lagg_port *,
323 struct mbuf *);
324 void lagg_lb_portstat(struct lagg_proto_softc *,
325 struct lagg_port *, struct laggreqport *);
326
327 int lacp_attach(struct lagg_softc *, struct lagg_proto_softc **);
328 void lacp_detach(struct lagg_proto_softc *);
329 int lacp_up(struct lagg_proto_softc *);
330 void lacp_down(struct lagg_proto_softc *);
331 int lacp_transmit(struct lagg_proto_softc *, struct mbuf *);
332 struct mbuf * lacp_input(struct lagg_proto_softc *, struct lagg_port *,
333 struct mbuf *);
334 int lacp_allocport(struct lagg_proto_softc *, struct lagg_port *);
335 void lacp_freeport(struct lagg_proto_softc *, struct lagg_port *);
336 void lacp_startport(struct lagg_proto_softc *, struct lagg_port *);
337 void lacp_stopport(struct lagg_proto_softc *, struct lagg_port *);
338 void lacp_protostat(struct lagg_proto_softc *,
339 struct laggreqproto *);
340 void lacp_portstat(struct lagg_proto_softc *, struct lagg_port *,
341 struct laggreqport *);
342 void lacp_linkstate_ifnet_locked(struct lagg_proto_softc *, struct lagg_port *);
343 int lacp_ioctl(struct lagg_proto_softc *, struct laggreqproto *);
344 #endif
345