if_laggproto.h revision 1.16
1/*	$NetBSD: if_laggproto.h,v 1.16 2022/04/04 06:10:00 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
32struct lagg_softc;
33struct lagg_proto_softc;
34
35#define LAGG_MAX_PORTS	32
36#define LAGG_PORT_PRIO	0x8000U
37
38enum lagg_work_state {
39	LAGG_WORK_IDLE,
40	LAGG_WORK_ENQUEUED,
41	LAGG_WORK_STOPPING
42};
43struct 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
50static inline void
51lagg_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
59struct workqueue *
60		lagg_workq_create(const char *, pri_t, int, int);
61void		lagg_workq_destroy(struct workqueue *);
62void		lagg_workq_add(struct workqueue *, struct lagg_work *);
63void		lagg_workq_wait(struct workqueue *, struct lagg_work *);
64
65struct 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
94struct 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
125struct lagg_variant {
126	lagg_proto	 lv_proto;
127	struct lagg_proto_softc
128			*lv_psc;
129
130	struct psref_target	lv_psref;
131};
132
133struct 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
140struct lagg_vlantag {
141	uint16_t	 lvt_vtag;
142	TAILQ_ENTRY(lagg_vlantag)
143			 lvt_entry;
144};
145
146struct lagg_softc {
147	kmutex_t		 sc_lock;
148	struct ifmedia		 sc_media;
149	u_char			 sc_iftype;
150
151	/* interface link-layer address */
152	uint8_t			 sc_lladdr[ETHER_ADDR_LEN];
153	/* generated random lladdr */
154	uint8_t			 sc_lladdr_rand[ETHER_ADDR_LEN];
155
156	LIST_HEAD(, lagg_mc_entry)
157				 sc_mclist;
158	TAILQ_HEAD(, lagg_vlantag)
159				 sc_vtags;
160	pserialize_t		 sc_psz;
161	struct lagg_variant	*sc_var;
162	SIMPLEQ_HEAD(, lagg_port)
163				 sc_ports;
164	size_t			 sc_nports;
165	char			 sc_evgroup[16];
166	struct evcnt		 sc_novar;
167
168	struct sysctllog	*sc_sysctllog;
169	const struct sysctlnode	*sc_sysctlnode;
170	bool			 sc_hash_mac;
171	bool			 sc_hash_ipaddr;
172	bool			 sc_hash_ip6addr;
173	bool			 sc_hash_tcp;
174	bool			 sc_hash_udp;
175
176	/*
177	 * storage size of sc_if is a variable-length,
178	 * should be the last
179	 */
180	struct ifnet		 sc_if;
181};
182
183/*
184 * Locking notes:
185 * - sc_lock(LAGG_LOCK()) is an adaptive mutex and protects items
186 *   of struct lagg_softc
187 * - a lock in struct lagg_proto_softc, for example LACP_LOCK(), is
188 *   an adaptive mutex and protects member contained in the struct
189 * - sc_var is protected by both pselialize (sc_psz) and psref (lv_psref)
190 *    - Updates of sc_var is serialized by sc_lock
191 * - Items in sc_ports is protected by both psref (lp_psref) and
192 *   pserialize contained in struct lagg_proto_softc
193 *   - details are discribed in if_laggport.c and if_lagg_lacp.c
194 *   - Updates of items in sc_ports are serialized by sc_lock
195 * - an instance referenced by lp_proto_ctx in struct lagg_port is
196 *   protected by a lock in struct lagg_proto_softc
197 *
198 * Locking order:
199 * - IFNET_LOCK(sc_if) -> LAGG_LOCK -> ETHER_LOCK(sc_if) -> a lock in
200 *   struct lagg_port_softc
201 * - IFNET_LOCK(sc_if) -> LAGG_LOCK -> IFNET_LOCK(lp_ifp)
202 * - IFNET_LOCK(lp_ifp) -> a lock in struct lagg_proto_softc
203 * - Currently, there is no combination of following locks
204 *   - IFNET_LOCK(lp_ifp) and ETHER_LOCK(sc_if)
205 */
206#define LAGG_LOCK(_sc)		mutex_enter(&(_sc)->sc_lock)
207#define LAGG_UNLOCK(_sc)	mutex_exit(&(_sc)->sc_lock)
208#define LAGG_LOCKED(_sc)	mutex_owned(&(_sc)->sc_lock)
209#define LAGG_CLLADDR(_sc)	CLLADDR((_sc)->sc_if.if_sadl)
210
211#define LAGG_PORTS_FOREACH(_sc, _lp)	\
212    SIMPLEQ_FOREACH((_lp), &(_sc)->sc_ports, lp_entry)
213#define LAGG_PORTS_FIRST(_sc)	SIMPLEQ_FIRST(&(_sc)->sc_ports)
214#define LAGG_PORTS_EMPTY(_sc)	SIMPLEQ_EMPTY(&(_sc)->sc_ports)
215#define LAGG_PORT_IOCTL(_lp, _cmd, _data)	\
216	(_lp)->lp_ioctl == NULL ? ENOTTY :	\
217	(_lp)->lp_ioctl((_lp)->lp_ifp, (_cmd), (_data))
218
219static inline const void *
220lagg_m_extract(struct mbuf *m, size_t off, size_t reqlen, void *buf)
221{
222	ssize_t len;
223	const void *rv;
224
225	KASSERT(ISSET(m->m_flags, M_PKTHDR));
226	len = off + reqlen;
227
228	if (m->m_pkthdr.len < len) {
229		return NULL;
230	}
231
232	if (m->m_len >= len) {
233		rv = mtod(m, uint8_t *) + off;
234	} else {
235		m_copydata(m, off, reqlen, buf);
236		rv = buf;
237	}
238
239	return rv;
240}
241
242static inline int
243lagg_port_xmit(struct lagg_port *lp, struct mbuf *m)
244{
245
246	return if_transmit_lock(lp->lp_ifp, m);
247}
248
249static inline bool
250lagg_portactive(struct lagg_port *lp)
251{
252	struct ifnet *ifp;
253
254	ifp = lp->lp_ifp;
255
256	if (ifp->if_link_state != LINK_STATE_DOWN &&
257	    ISSET(ifp->if_flags, IFF_UP)) {
258		return true;
259	}
260
261	return false;
262}
263
264static inline bool
265lagg_debug_enable(struct lagg_softc *sc)
266{
267	if (__predict_false(ISSET(sc->sc_if.if_flags, IFF_DEBUG)))
268		return true;
269
270	return false;
271}
272
273#define LAGG_LOG(_sc, _lvl, _fmt, _arg...) do {		\
274	if ((_lvl) == LOG_DEBUG && 			\
275	    !lagg_debug_enable(_sc))			\
276		break;					\
277							\
278	log((_lvl), "%s: ", (_sc)->sc_if.if_xname);	\
279	addlog((_fmt), ##_arg);				\
280} while(0)
281
282void		lagg_port_getref(struct lagg_port *, struct psref *);
283void		lagg_port_putref(struct lagg_port *, struct psref *);
284void		lagg_output(struct lagg_softc *,
285		    struct lagg_port *, struct mbuf *);
286uint32_t	lagg_hashmbuf(struct lagg_softc *, struct mbuf *);
287
288void		lagg_common_detach(struct lagg_proto_softc *);
289int		lagg_common_allocport(struct lagg_proto_softc *,
290		    struct lagg_port *);
291void		lagg_common_freeport(struct lagg_proto_softc *,
292		    struct lagg_port *);
293void		lagg_common_startport(struct lagg_proto_softc *,
294		    struct lagg_port *);
295void		lagg_common_stopport(struct lagg_proto_softc *,
296		    struct lagg_port *);
297void		lagg_common_linkstate(struct lagg_proto_softc *,
298		    struct lagg_port *);
299
300int		lagg_none_attach(struct lagg_softc *,
301		    struct lagg_proto_softc **);
302
303int		lagg_fail_attach(struct lagg_softc *,
304		    struct lagg_proto_softc **);
305int		lagg_fail_transmit(struct lagg_proto_softc *, struct mbuf *);
306struct mbuf *	lagg_fail_input(struct lagg_proto_softc *, struct lagg_port *,
307		   struct mbuf *);
308void		lagg_fail_portstat(struct lagg_proto_softc *,
309		    struct lagg_port *, struct laggreqport *);
310int		lagg_fail_ioctl(struct lagg_proto_softc *,
311		    struct laggreqproto *);
312
313int		lagg_lb_attach(struct lagg_softc *, struct lagg_proto_softc **);
314void		lagg_lb_startport(struct lagg_proto_softc *,
315		    struct lagg_port *);
316void		lagg_lb_stopport(struct lagg_proto_softc *, struct lagg_port *);
317int		lagg_lb_transmit(struct lagg_proto_softc *, struct mbuf *);
318struct mbuf *	lagg_lb_input(struct lagg_proto_softc *, struct lagg_port *,
319		    struct mbuf *);
320void		lagg_lb_portstat(struct lagg_proto_softc *,
321		    struct lagg_port *, struct laggreqport *);
322
323int		lacp_attach(struct lagg_softc *, struct lagg_proto_softc **);
324void		lacp_detach(struct lagg_proto_softc *);
325int		lacp_up(struct lagg_proto_softc *);
326void		lacp_down(struct lagg_proto_softc *);
327int		lacp_transmit(struct lagg_proto_softc *, struct mbuf *);
328struct mbuf *	lacp_input(struct lagg_proto_softc *, struct lagg_port *,
329		    struct mbuf *);
330int		lacp_allocport(struct lagg_proto_softc *, struct lagg_port *);
331void		lacp_freeport(struct lagg_proto_softc *, struct lagg_port *);
332void		lacp_startport(struct lagg_proto_softc *, struct lagg_port *);
333void		lacp_stopport(struct lagg_proto_softc *, struct lagg_port *);
334void		lacp_protostat(struct lagg_proto_softc *,
335		    struct laggreqproto *);
336void		lacp_portstat(struct lagg_proto_softc *, struct lagg_port *,
337		    struct laggreqport *);
338void		lacp_linkstate_ifnet_locked(struct lagg_proto_softc *, struct lagg_port *);
339int		lacp_ioctl(struct lagg_proto_softc *, struct laggreqproto *);
340#endif
341