Home | History | Annotate | Line # | Download | only in lagg
      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
     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 *
    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
    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
    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
    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