if_laggproto.h revision 1.20
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 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 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 220static inline const void * 221lagg_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 245static inline int 246lagg_port_xmit(struct lagg_port *lp, struct mbuf *m) 247{ 248 249 return if_transmit_lock(lp->lp_ifp, m); 250} 251 252static inline bool 253lagg_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 267static inline bool 268lagg_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 285void lagg_port_getref(struct lagg_port *, struct psref *); 286void lagg_port_putref(struct lagg_port *, struct psref *); 287void lagg_output(struct lagg_softc *, 288 struct lagg_port *, struct mbuf *); 289uint32_t lagg_hashmbuf(struct lagg_softc *, struct mbuf *); 290void lagg_set_linkspeed(struct lagg_softc *, uint64_t); 291 292void lagg_common_detach(struct lagg_proto_softc *); 293int lagg_common_allocport(struct lagg_proto_softc *, 294 struct lagg_port *); 295void lagg_common_freeport(struct lagg_proto_softc *, 296 struct lagg_port *); 297void lagg_common_startport(struct lagg_proto_softc *, 298 struct lagg_port *); 299void lagg_common_stopport(struct lagg_proto_softc *, 300 struct lagg_port *); 301void lagg_common_linkstate_ifnet_locked(struct lagg_proto_softc *, 302 struct lagg_port *); 303 304int lagg_none_attach(struct lagg_softc *, 305 struct lagg_proto_softc **); 306 307int lagg_fail_attach(struct lagg_softc *, 308 struct lagg_proto_softc **); 309int lagg_fail_transmit(struct lagg_proto_softc *, struct mbuf *); 310struct mbuf * lagg_fail_input(struct lagg_proto_softc *, struct lagg_port *, 311 struct mbuf *); 312void lagg_fail_portstat(struct lagg_proto_softc *, 313 struct lagg_port *, struct laggreqport *); 314int lagg_fail_ioctl(struct lagg_proto_softc *, 315 struct laggreqproto *); 316 317int lagg_lb_attach(struct lagg_softc *, struct lagg_proto_softc **); 318void lagg_lb_startport(struct lagg_proto_softc *, 319 struct lagg_port *); 320void lagg_lb_stopport(struct lagg_proto_softc *, struct lagg_port *); 321int lagg_lb_transmit(struct lagg_proto_softc *, struct mbuf *); 322struct mbuf * lagg_lb_input(struct lagg_proto_softc *, struct lagg_port *, 323 struct mbuf *); 324void lagg_lb_portstat(struct lagg_proto_softc *, 325 struct lagg_port *, struct laggreqport *); 326 327int lacp_attach(struct lagg_softc *, struct lagg_proto_softc **); 328void lacp_detach(struct lagg_proto_softc *); 329int lacp_up(struct lagg_proto_softc *); 330void lacp_down(struct lagg_proto_softc *); 331int lacp_transmit(struct lagg_proto_softc *, struct mbuf *); 332struct mbuf * lacp_input(struct lagg_proto_softc *, struct lagg_port *, 333 struct mbuf *); 334int lacp_allocport(struct lagg_proto_softc *, struct lagg_port *); 335void lacp_freeport(struct lagg_proto_softc *, struct lagg_port *); 336void lacp_startport(struct lagg_proto_softc *, struct lagg_port *); 337void lacp_stopport(struct lagg_proto_softc *, struct lagg_port *); 338void lacp_protostat(struct lagg_proto_softc *, 339 struct laggreqproto *); 340void lacp_portstat(struct lagg_proto_softc *, struct lagg_port *, 341 struct laggreqport *); 342void lacp_linkstate_ifnet_locked(struct lagg_proto_softc *, struct lagg_port *); 343int lacp_ioctl(struct lagg_proto_softc *, struct laggreqproto *); 344#endif 345