xref: /netbsd/sys/net/lagg/if_laggproto.h (revision 7a004fb3)
1 /*	$NetBSD: if_laggproto.h,v 1.18 2022/06/26 17:55:24 riastradh 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 	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 described 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 
219 static inline const void *
lagg_m_extract(struct mbuf * m,size_t off,size_t reqlen,size_t align,void * buf)220 lagg_m_extract(struct mbuf *m, size_t off, size_t reqlen, size_t align,
221     void *buf)
222 {
223 	ssize_t len;
224 	const void *rv;
225 
226 	KASSERT(ISSET(m->m_flags, M_PKTHDR));
227 	len = off + reqlen;
228 
229 	if (m->m_pkthdr.len < len) {
230 		return NULL;
231 	}
232 
233 	if (m->m_len >= len &&
234 	    ((uintptr_t)(mtod(m, uint8_t *) + off) % align) == 0) {
235 		rv = mtod(m, uint8_t *) + off;
236 	} else {
237 		m_copydata(m, off, reqlen, buf);
238 		rv = buf;
239 	}
240 
241 	return rv;
242 }
243 
244 static inline int
lagg_port_xmit(struct lagg_port * lp,struct mbuf * m)245 lagg_port_xmit(struct lagg_port *lp, struct mbuf *m)
246 {
247 
248 	return if_transmit_lock(lp->lp_ifp, m);
249 }
250 
251 static inline bool
lagg_portactive(struct lagg_port * lp)252 lagg_portactive(struct lagg_port *lp)
253 {
254 	struct ifnet *ifp;
255 
256 	ifp = lp->lp_ifp;
257 
258 	if (ifp->if_link_state != LINK_STATE_DOWN &&
259 	    ISSET(ifp->if_flags, IFF_UP)) {
260 		return true;
261 	}
262 
263 	return false;
264 }
265 
266 static inline bool
lagg_debug_enable(struct lagg_softc * sc)267 lagg_debug_enable(struct lagg_softc *sc)
268 {
269 	if (__predict_false(ISSET(sc->sc_if.if_flags, IFF_DEBUG)))
270 		return true;
271 
272 	return false;
273 }
274 
275 #define LAGG_LOG(_sc, _lvl, _fmt, _arg...) do {		\
276 	if ((_lvl) == LOG_DEBUG && 			\
277 	    !lagg_debug_enable(_sc))			\
278 		break;					\
279 							\
280 	log((_lvl), "%s: ", (_sc)->sc_if.if_xname);	\
281 	addlog((_fmt), ##_arg);				\
282 } while(0)
283 
284 void		lagg_port_getref(struct lagg_port *, struct psref *);
285 void		lagg_port_putref(struct lagg_port *, struct psref *);
286 void		lagg_output(struct lagg_softc *,
287 		    struct lagg_port *, struct mbuf *);
288 uint32_t	lagg_hashmbuf(struct lagg_softc *, struct mbuf *);
289 
290 void		lagg_common_detach(struct lagg_proto_softc *);
291 int		lagg_common_allocport(struct lagg_proto_softc *,
292 		    struct lagg_port *);
293 void		lagg_common_freeport(struct lagg_proto_softc *,
294 		    struct lagg_port *);
295 void		lagg_common_startport(struct lagg_proto_softc *,
296 		    struct lagg_port *);
297 void		lagg_common_stopport(struct lagg_proto_softc *,
298 		    struct lagg_port *);
299 void		lagg_common_linkstate(struct lagg_proto_softc *,
300 		    struct lagg_port *);
301 
302 int		lagg_none_attach(struct lagg_softc *,
303 		    struct lagg_proto_softc **);
304 
305 int		lagg_fail_attach(struct lagg_softc *,
306 		    struct lagg_proto_softc **);
307 int		lagg_fail_transmit(struct lagg_proto_softc *, struct mbuf *);
308 struct mbuf *	lagg_fail_input(struct lagg_proto_softc *, struct lagg_port *,
309 		   struct mbuf *);
310 void		lagg_fail_portstat(struct lagg_proto_softc *,
311 		    struct lagg_port *, struct laggreqport *);
312 int		lagg_fail_ioctl(struct lagg_proto_softc *,
313 		    struct laggreqproto *);
314 
315 int		lagg_lb_attach(struct lagg_softc *, struct lagg_proto_softc **);
316 void		lagg_lb_startport(struct lagg_proto_softc *,
317 		    struct lagg_port *);
318 void		lagg_lb_stopport(struct lagg_proto_softc *, struct lagg_port *);
319 int		lagg_lb_transmit(struct lagg_proto_softc *, struct mbuf *);
320 struct mbuf *	lagg_lb_input(struct lagg_proto_softc *, struct lagg_port *,
321 		    struct mbuf *);
322 void		lagg_lb_portstat(struct lagg_proto_softc *,
323 		    struct lagg_port *, struct laggreqport *);
324 
325 int		lacp_attach(struct lagg_softc *, struct lagg_proto_softc **);
326 void		lacp_detach(struct lagg_proto_softc *);
327 int		lacp_up(struct lagg_proto_softc *);
328 void		lacp_down(struct lagg_proto_softc *);
329 int		lacp_transmit(struct lagg_proto_softc *, struct mbuf *);
330 struct mbuf *	lacp_input(struct lagg_proto_softc *, struct lagg_port *,
331 		    struct mbuf *);
332 int		lacp_allocport(struct lagg_proto_softc *, struct lagg_port *);
333 void		lacp_freeport(struct lagg_proto_softc *, struct lagg_port *);
334 void		lacp_startport(struct lagg_proto_softc *, struct lagg_port *);
335 void		lacp_stopport(struct lagg_proto_softc *, struct lagg_port *);
336 void		lacp_protostat(struct lagg_proto_softc *,
337 		    struct laggreqproto *);
338 void		lacp_portstat(struct lagg_proto_softc *, struct lagg_port *,
339 		    struct laggreqport *);
340 void		lacp_linkstate_ifnet_locked(struct lagg_proto_softc *, struct lagg_port *);
341 int		lacp_ioctl(struct lagg_proto_softc *, struct laggreqproto *);
342 #endif
343