if_trunk.c 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635
  1. /* $OpenBSD: if_trunk.c,v 1.109 2015/07/17 23:32:18 mpi Exp $ */
  2. /*
  3. * Copyright (c) 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <sys/param.h>
  18. #include <sys/kernel.h>
  19. #include <sys/malloc.h>
  20. #include <sys/mbuf.h>
  21. #include <sys/queue.h>
  22. #include <sys/socket.h>
  23. #include <sys/sockio.h>
  24. #include <sys/systm.h>
  25. #include <sys/timeout.h>
  26. #include <crypto/siphash.h>
  27. #include <net/if.h>
  28. #include <net/if_dl.h>
  29. #include <net/if_media.h>
  30. #include <net/if_types.h>
  31. #include <netinet/in.h>
  32. #include <netinet/if_ether.h>
  33. #include <netinet/ip.h>
  34. #ifdef INET6
  35. #include <netinet/ip6.h>
  36. #endif
  37. #include <net/if_vlan_var.h>
  38. #include <net/if_trunk.h>
  39. #include <net/trunklacp.h>
  40. #include "bpfilter.h"
  41. #if NBPFILTER > 0
  42. #include <net/bpf.h>
  43. #endif
  44. SLIST_HEAD(__trhead, trunk_softc) trunk_list; /* list of trunks */
  45. void trunkattach(int);
  46. int trunk_clone_create(struct if_clone *, int);
  47. int trunk_clone_destroy(struct ifnet *);
  48. void trunk_lladdr(struct arpcom *, u_int8_t *);
  49. int trunk_capabilities(struct trunk_softc *);
  50. void trunk_port_lladdr(struct trunk_port *, u_int8_t *);
  51. int trunk_port_create(struct trunk_softc *, struct ifnet *);
  52. int trunk_port_destroy(struct trunk_port *);
  53. void trunk_port_watchdog(struct ifnet *);
  54. void trunk_port_state(void *);
  55. void trunk_port_ifdetach(void *);
  56. int trunk_port_ioctl(struct ifnet *, u_long, caddr_t);
  57. int trunk_port_output(struct ifnet *, struct mbuf *, struct sockaddr *,
  58. struct rtentry *);
  59. struct trunk_port *trunk_port_get(struct trunk_softc *, struct ifnet *);
  60. int trunk_port_checkstacking(struct trunk_softc *);
  61. void trunk_port2req(struct trunk_port *, struct trunk_reqport *);
  62. int trunk_ioctl(struct ifnet *, u_long, caddr_t);
  63. int trunk_ether_addmulti(struct trunk_softc *, struct ifreq *);
  64. int trunk_ether_delmulti(struct trunk_softc *, struct ifreq *);
  65. void trunk_ether_purgemulti(struct trunk_softc *);
  66. int trunk_ether_cmdmulti(struct trunk_port *, u_long);
  67. int trunk_ioctl_allports(struct trunk_softc *, u_long, caddr_t);
  68. int trunk_input(struct ifnet *, struct mbuf *);
  69. void trunk_start(struct ifnet *);
  70. void trunk_init(struct ifnet *);
  71. void trunk_stop(struct ifnet *);
  72. void trunk_watchdog(struct ifnet *);
  73. int trunk_media_change(struct ifnet *);
  74. void trunk_media_status(struct ifnet *, struct ifmediareq *);
  75. struct trunk_port *trunk_link_active(struct trunk_softc *,
  76. struct trunk_port *);
  77. const void *trunk_gethdr(struct mbuf *, u_int, u_int, void *);
  78. struct if_clone trunk_cloner =
  79. IF_CLONE_INITIALIZER("trunk", trunk_clone_create, trunk_clone_destroy);
  80. /* Simple round robin */
  81. int trunk_rr_attach(struct trunk_softc *);
  82. int trunk_rr_detach(struct trunk_softc *);
  83. void trunk_rr_port_destroy(struct trunk_port *);
  84. int trunk_rr_start(struct trunk_softc *, struct mbuf *);
  85. int trunk_rr_input(struct trunk_softc *, struct trunk_port *,
  86. struct mbuf *);
  87. /* Active failover */
  88. int trunk_fail_attach(struct trunk_softc *);
  89. int trunk_fail_detach(struct trunk_softc *);
  90. int trunk_fail_start(struct trunk_softc *, struct mbuf *);
  91. int trunk_fail_input(struct trunk_softc *, struct trunk_port *,
  92. struct mbuf *);
  93. /* Loadbalancing */
  94. int trunk_lb_attach(struct trunk_softc *);
  95. int trunk_lb_detach(struct trunk_softc *);
  96. int trunk_lb_port_create(struct trunk_port *);
  97. void trunk_lb_port_destroy(struct trunk_port *);
  98. int trunk_lb_start(struct trunk_softc *, struct mbuf *);
  99. int trunk_lb_input(struct trunk_softc *, struct trunk_port *,
  100. struct mbuf *);
  101. int trunk_lb_porttable(struct trunk_softc *, struct trunk_port *);
  102. /* Broadcast mode */
  103. int trunk_bcast_attach(struct trunk_softc *);
  104. int trunk_bcast_detach(struct trunk_softc *);
  105. int trunk_bcast_start(struct trunk_softc *, struct mbuf *);
  106. int trunk_bcast_input(struct trunk_softc *, struct trunk_port *,
  107. struct mbuf *);
  108. /* 802.3ad LACP */
  109. int trunk_lacp_attach(struct trunk_softc *);
  110. int trunk_lacp_detach(struct trunk_softc *);
  111. int trunk_lacp_start(struct trunk_softc *, struct mbuf *);
  112. int trunk_lacp_input(struct trunk_softc *, struct trunk_port *,
  113. struct mbuf *);
  114. /* Trunk protocol table */
  115. static const struct {
  116. enum trunk_proto ti_proto;
  117. int (*ti_attach)(struct trunk_softc *);
  118. } trunk_protos[] = {
  119. { TRUNK_PROTO_ROUNDROBIN, trunk_rr_attach },
  120. { TRUNK_PROTO_FAILOVER, trunk_fail_attach },
  121. { TRUNK_PROTO_LOADBALANCE, trunk_lb_attach },
  122. { TRUNK_PROTO_BROADCAST, trunk_bcast_attach },
  123. { TRUNK_PROTO_LACP, trunk_lacp_attach },
  124. { TRUNK_PROTO_NONE, NULL }
  125. };
  126. void
  127. trunkattach(int count)
  128. {
  129. SLIST_INIT(&trunk_list);
  130. if_clone_attach(&trunk_cloner);
  131. }
  132. int
  133. trunk_clone_create(struct if_clone *ifc, int unit)
  134. {
  135. struct trunk_softc *tr;
  136. struct ifnet *ifp;
  137. int i, error = 0;
  138. if ((tr = malloc(sizeof(struct trunk_softc),
  139. M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
  140. return (ENOMEM);
  141. tr->tr_unit = unit;
  142. tr->tr_proto = TRUNK_PROTO_NONE;
  143. for (i = 0; trunk_protos[i].ti_proto != TRUNK_PROTO_NONE; i++) {
  144. if (trunk_protos[i].ti_proto == TRUNK_PROTO_DEFAULT) {
  145. tr->tr_proto = trunk_protos[i].ti_proto;
  146. if ((error = trunk_protos[i].ti_attach(tr)) != 0) {
  147. free(tr, M_DEVBUF, 0);
  148. return (error);
  149. }
  150. break;
  151. }
  152. }
  153. SLIST_INIT(&tr->tr_ports);
  154. /* Initialise pseudo media types */
  155. ifmedia_init(&tr->tr_media, 0, trunk_media_change,
  156. trunk_media_status);
  157. ifmedia_add(&tr->tr_media, IFM_ETHER | IFM_AUTO, 0, NULL);
  158. ifmedia_set(&tr->tr_media, IFM_ETHER | IFM_AUTO);
  159. ifp = &tr->tr_ac.ac_if;
  160. ifp->if_softc = tr;
  161. ifp->if_start = trunk_start;
  162. ifp->if_watchdog = trunk_watchdog;
  163. ifp->if_ioctl = trunk_ioctl;
  164. ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
  165. ifp->if_capabilities = trunk_capabilities(tr);
  166. IFQ_SET_MAXLEN(&ifp->if_snd, 1);
  167. IFQ_SET_READY(&ifp->if_snd);
  168. snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d",
  169. ifc->ifc_name, unit);
  170. /*
  171. * Attach as an ordinary ethernet device, children will be attached
  172. * as special device IFT_IEEE8023ADLAG.
  173. */
  174. if_attach(ifp);
  175. ether_ifattach(ifp);
  176. /* Insert into the global list of trunks */
  177. SLIST_INSERT_HEAD(&trunk_list, tr, tr_entries);
  178. return (0);
  179. }
  180. int
  181. trunk_clone_destroy(struct ifnet *ifp)
  182. {
  183. struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
  184. struct trunk_port *tp;
  185. int error, s;
  186. /* Remove any multicast groups that we may have joined. */
  187. trunk_ether_purgemulti(tr);
  188. s = splnet();
  189. /* Shutdown and remove trunk ports, return on error */
  190. while ((tp = SLIST_FIRST(&tr->tr_ports)) != NULL) {
  191. if ((error = trunk_port_destroy(tp)) != 0) {
  192. splx(s);
  193. return (error);
  194. }
  195. }
  196. ifmedia_delete_instance(&tr->tr_media, IFM_INST_ANY);
  197. ether_ifdetach(ifp);
  198. if_detach(ifp);
  199. SLIST_REMOVE(&trunk_list, tr, trunk_softc, tr_entries);
  200. free(tr, M_DEVBUF, 0);
  201. splx(s);
  202. return (0);
  203. }
  204. void
  205. trunk_lladdr(struct arpcom *ac, u_int8_t *lladdr)
  206. {
  207. struct ifnet *ifp = &ac->ac_if;
  208. struct sockaddr_dl *sdl;
  209. sdl = ifp->if_sadl;
  210. sdl->sdl_type = IFT_ETHER;
  211. sdl->sdl_alen = ETHER_ADDR_LEN;
  212. bcopy(lladdr, LLADDR(sdl), ETHER_ADDR_LEN);
  213. bcopy(lladdr, ac->ac_enaddr, ETHER_ADDR_LEN);
  214. }
  215. int
  216. trunk_capabilities(struct trunk_softc *tr)
  217. {
  218. struct trunk_port *tp;
  219. int cap = ~0, priv;
  220. /* Preserve private capabilities */
  221. priv = tr->tr_capabilities & IFCAP_TRUNK_MASK;
  222. /* Get capabilities from the trunk ports */
  223. SLIST_FOREACH(tp, &tr->tr_ports, tp_entries)
  224. cap &= tp->tp_capabilities;
  225. if (tr->tr_ifflags & IFF_DEBUG) {
  226. printf("%s: capabilities 0x%08x\n",
  227. tr->tr_ifname, cap == ~0 ? priv : (cap | priv));
  228. }
  229. return (cap == ~0 ? priv : (cap | priv));
  230. }
  231. void
  232. trunk_port_lladdr(struct trunk_port *tp, u_int8_t *lladdr)
  233. {
  234. struct ifnet *ifp = tp->tp_if;
  235. /* Set the link layer address */
  236. trunk_lladdr((struct arpcom *)ifp, lladdr);
  237. /* Reset the port to update the lladdr */
  238. ifnewlladdr(ifp);
  239. }
  240. int
  241. trunk_port_create(struct trunk_softc *tr, struct ifnet *ifp)
  242. {
  243. struct trunk_softc *tr_ptr;
  244. struct trunk_port *tp;
  245. int error = 0;
  246. /* Limit the maximal number of trunk ports */
  247. if (tr->tr_count >= TRUNK_MAX_PORTS)
  248. return (ENOSPC);
  249. /* New trunk port has to be in an idle state */
  250. if (ifp->if_flags & IFF_OACTIVE)
  251. return (EBUSY);
  252. /* Check if port has already been associated to a trunk */
  253. if (trunk_port_get(NULL, ifp) != NULL)
  254. return (EBUSY);
  255. /* XXX Disallow non-ethernet interfaces (this should be any of 802) */
  256. if (ifp->if_type != IFT_ETHER)
  257. return (EPROTONOSUPPORT);
  258. /* Take MTU from the first member port */
  259. if (SLIST_EMPTY(&tr->tr_ports)) {
  260. if (tr->tr_ifflags & IFF_DEBUG)
  261. printf("%s: first port, setting trunk mtu %u\n",
  262. tr->tr_ifname, ifp->if_mtu);
  263. tr->tr_ac.ac_if.if_mtu = ifp->if_mtu;
  264. tr->tr_ac.ac_if.if_hardmtu = ifp->if_mtu;
  265. } else if (tr->tr_ac.ac_if.if_mtu != ifp->if_mtu) {
  266. printf("%s: adding %s failed, MTU %u != %u\n", tr->tr_ifname,
  267. ifp->if_xname, ifp->if_mtu, tr->tr_ac.ac_if.if_mtu);
  268. return (EINVAL);
  269. }
  270. if ((error = ifpromisc(ifp, 1)) != 0)
  271. return (error);
  272. if ((tp = malloc(sizeof(struct trunk_port),
  273. M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
  274. return (ENOMEM);
  275. /* Check if port is a stacked trunk */
  276. SLIST_FOREACH(tr_ptr, &trunk_list, tr_entries) {
  277. if (ifp == &tr_ptr->tr_ac.ac_if) {
  278. tp->tp_flags |= TRUNK_PORT_STACK;
  279. if (trunk_port_checkstacking(tr_ptr) >=
  280. TRUNK_MAX_STACKING) {
  281. free(tp, M_DEVBUF, 0);
  282. return (E2BIG);
  283. }
  284. }
  285. }
  286. /* Change the interface type */
  287. tp->tp_iftype = ifp->if_type;
  288. ifp->if_type = IFT_IEEE8023ADLAG;
  289. /* Change input handler of the physical interface. */
  290. tp->tp_ifih.ifih_input = trunk_input;
  291. SLIST_INSERT_HEAD(&ifp->if_inputs, &tp->tp_ifih, ifih_next);
  292. ifp->if_tp = (caddr_t)tp;
  293. tp->tp_ioctl = ifp->if_ioctl;
  294. ifp->if_ioctl = trunk_port_ioctl;
  295. timeout_del(ifp->if_slowtimo);
  296. tp->tp_watchdog = ifp->if_watchdog;
  297. ifp->if_watchdog = trunk_port_watchdog;
  298. tp->tp_output = ifp->if_output;
  299. ifp->if_output = trunk_port_output;
  300. tp->tp_if = ifp;
  301. tp->tp_trunk = tr;
  302. /* Save port link layer address */
  303. bcopy(((struct arpcom *)ifp)->ac_enaddr, tp->tp_lladdr, ETHER_ADDR_LEN);
  304. if (SLIST_EMPTY(&tr->tr_ports)) {
  305. tr->tr_primary = tp;
  306. tp->tp_flags |= TRUNK_PORT_MASTER;
  307. trunk_lladdr(&tr->tr_ac, tp->tp_lladdr);
  308. }
  309. /* Update link layer address for this port */
  310. trunk_port_lladdr(tp,
  311. ((struct arpcom *)(tr->tr_primary->tp_if))->ac_enaddr);
  312. /* Insert into the list of ports */
  313. SLIST_INSERT_HEAD(&tr->tr_ports, tp, tp_entries);
  314. tr->tr_count++;
  315. /* Update trunk capabilities */
  316. tr->tr_capabilities = trunk_capabilities(tr);
  317. /* Add multicast addresses to this port */
  318. trunk_ether_cmdmulti(tp, SIOCADDMULTI);
  319. /* Register callback for physical link state changes */
  320. tp->lh_cookie = hook_establish(ifp->if_linkstatehooks, 1,
  321. trunk_port_state, tp);
  322. /* Register callback if parent wants to unregister */
  323. tp->dh_cookie = hook_establish(ifp->if_detachhooks, 0,
  324. trunk_port_ifdetach, tp);
  325. if (tr->tr_port_create != NULL)
  326. error = (*tr->tr_port_create)(tp);
  327. return (error);
  328. }
  329. int
  330. trunk_port_checkstacking(struct trunk_softc *tr)
  331. {
  332. struct trunk_softc *tr_ptr;
  333. struct trunk_port *tp;
  334. int m = 0;
  335. SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
  336. if (tp->tp_flags & TRUNK_PORT_STACK) {
  337. tr_ptr = (struct trunk_softc *)tp->tp_if->if_softc;
  338. m = MAX(m, trunk_port_checkstacking(tr_ptr));
  339. }
  340. }
  341. return (m + 1);
  342. }
  343. int
  344. trunk_port_destroy(struct trunk_port *tp)
  345. {
  346. struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
  347. struct trunk_port *tp_ptr;
  348. struct ifnet *ifp = tp->tp_if;
  349. if (tr->tr_port_destroy != NULL)
  350. (*tr->tr_port_destroy)(tp);
  351. /* Remove multicast addresses from this port */
  352. trunk_ether_cmdmulti(tp, SIOCDELMULTI);
  353. /* Port has to be down */
  354. if (ifp->if_flags & IFF_UP)
  355. if_down(ifp);
  356. ifpromisc(ifp, 0);
  357. /* Restore interface type. */
  358. ifp->if_type = tp->tp_iftype;
  359. /* Restore previous input handler. */
  360. SLIST_REMOVE(&ifp->if_inputs, &tp->tp_ifih, ifih, ifih_next);
  361. ifp->if_watchdog = tp->tp_watchdog;
  362. ifp->if_ioctl = tp->tp_ioctl;
  363. ifp->if_output = tp->tp_output;
  364. ifp->if_tp = NULL;
  365. hook_disestablish(ifp->if_linkstatehooks, tp->lh_cookie);
  366. hook_disestablish(ifp->if_detachhooks, tp->dh_cookie);
  367. /* Finally, remove the port from the trunk */
  368. SLIST_REMOVE(&tr->tr_ports, tp, trunk_port, tp_entries);
  369. tr->tr_count--;
  370. /* Update the primary interface */
  371. if (tp == tr->tr_primary) {
  372. u_int8_t lladdr[ETHER_ADDR_LEN];
  373. if ((tp_ptr = SLIST_FIRST(&tr->tr_ports)) == NULL) {
  374. bzero(&lladdr, ETHER_ADDR_LEN);
  375. } else {
  376. bcopy(((struct arpcom *)tp_ptr->tp_if)->ac_enaddr,
  377. lladdr, ETHER_ADDR_LEN);
  378. tp_ptr->tp_flags = TRUNK_PORT_MASTER;
  379. }
  380. trunk_lladdr(&tr->tr_ac, lladdr);
  381. tr->tr_primary = tp_ptr;
  382. /* Update link layer address for each port */
  383. SLIST_FOREACH(tp_ptr, &tr->tr_ports, tp_entries)
  384. trunk_port_lladdr(tp_ptr, lladdr);
  385. }
  386. /* Reset the port lladdr */
  387. trunk_port_lladdr(tp, tp->tp_lladdr);
  388. free(tp, M_DEVBUF, 0);
  389. /* Update trunk capabilities */
  390. tr->tr_capabilities = trunk_capabilities(tr);
  391. /* Reestablish watchdog timeout */
  392. if_slowtimo(ifp);
  393. return (0);
  394. }
  395. void
  396. trunk_port_watchdog(struct ifnet *ifp)
  397. {
  398. struct trunk_port *tp;
  399. /* Should be checked by the caller */
  400. if (ifp->if_type != IFT_IEEE8023ADLAG)
  401. return;
  402. if ((tp = (struct trunk_port *)ifp->if_tp) == NULL ||
  403. tp->tp_trunk == NULL)
  404. return;
  405. if (tp->tp_watchdog != NULL)
  406. (*tp->tp_watchdog)(ifp);
  407. }
  408. int
  409. trunk_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  410. {
  411. struct trunk_reqport *rp = (struct trunk_reqport *)data;
  412. struct trunk_softc *tr;
  413. struct trunk_port *tp = NULL;
  414. int s, error = 0;
  415. s = splnet();
  416. /* Should be checked by the caller */
  417. if (ifp->if_type != IFT_IEEE8023ADLAG ||
  418. (tp = (struct trunk_port *)ifp->if_tp) == NULL ||
  419. (tr = (struct trunk_softc *)tp->tp_trunk) == NULL) {
  420. error = EINVAL;
  421. goto fallback;
  422. }
  423. switch (cmd) {
  424. case SIOCGTRUNKPORT:
  425. if (rp->rp_portname[0] == '\0' ||
  426. ifunit(rp->rp_portname) != ifp) {
  427. error = EINVAL;
  428. break;
  429. }
  430. /* Search in all trunks if the global flag is set */
  431. if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ?
  432. NULL : tr, ifp)) == NULL) {
  433. error = ENOENT;
  434. break;
  435. }
  436. trunk_port2req(tp, rp);
  437. break;
  438. case SIOCSIFMTU:
  439. /* Do not allow the MTU to be changed once joined */
  440. error = EINVAL;
  441. break;
  442. default:
  443. error = ENOTTY;
  444. goto fallback;
  445. }
  446. splx(s);
  447. return (error);
  448. fallback:
  449. splx(s);
  450. if (tp != NULL)
  451. error = (*tp->tp_ioctl)(ifp, cmd, data);
  452. return (error);
  453. }
  454. int
  455. trunk_port_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
  456. struct rtentry *rt)
  457. {
  458. /* restrict transmission on trunk members to bpf only */
  459. if (ifp->if_type == IFT_IEEE8023ADLAG &&
  460. (m_tag_find(m, PACKET_TAG_DLT, NULL) == NULL)) {
  461. m_freem(m);
  462. return (EBUSY);
  463. }
  464. return (ether_output(ifp, m, dst, rt));
  465. }
  466. void
  467. trunk_port_ifdetach(void *arg)
  468. {
  469. struct trunk_port *tp = (struct trunk_port *)arg;
  470. trunk_port_destroy(tp);
  471. }
  472. struct trunk_port *
  473. trunk_port_get(struct trunk_softc *tr, struct ifnet *ifp)
  474. {
  475. struct trunk_port *tp;
  476. struct trunk_softc *tr_ptr;
  477. if (tr != NULL) {
  478. /* Search port in specified trunk */
  479. SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
  480. if (tp->tp_if == ifp)
  481. return (tp);
  482. }
  483. } else {
  484. /* Search all trunks for the selected port */
  485. SLIST_FOREACH(tr_ptr, &trunk_list, tr_entries) {
  486. SLIST_FOREACH(tp, &tr_ptr->tr_ports, tp_entries) {
  487. if (tp->tp_if == ifp)
  488. return (tp);
  489. }
  490. }
  491. }
  492. return (NULL);
  493. }
  494. void
  495. trunk_port2req(struct trunk_port *tp, struct trunk_reqport *rp)
  496. {
  497. struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
  498. strlcpy(rp->rp_ifname, tr->tr_ifname, sizeof(rp->rp_ifname));
  499. strlcpy(rp->rp_portname, tp->tp_if->if_xname, sizeof(rp->rp_portname));
  500. rp->rp_prio = tp->tp_prio;
  501. if (tr->tr_portreq != NULL)
  502. (*tr->tr_portreq)(tp, (caddr_t)&rp->rp_psc);
  503. /* Add protocol specific flags */
  504. switch (tr->tr_proto) {
  505. case TRUNK_PROTO_FAILOVER:
  506. rp->rp_flags = tp->tp_flags;
  507. if (tp == trunk_link_active(tr, tr->tr_primary))
  508. rp->rp_flags |= TRUNK_PORT_ACTIVE;
  509. break;
  510. case TRUNK_PROTO_ROUNDROBIN:
  511. case TRUNK_PROTO_LOADBALANCE:
  512. case TRUNK_PROTO_BROADCAST:
  513. rp->rp_flags = tp->tp_flags;
  514. if (TRUNK_PORTACTIVE(tp))
  515. rp->rp_flags |= TRUNK_PORT_ACTIVE;
  516. break;
  517. case TRUNK_PROTO_LACP:
  518. /* LACP has a different definition of active */
  519. rp->rp_flags = lacp_port_status(tp);
  520. break;
  521. default:
  522. break;
  523. }
  524. }
  525. int
  526. trunk_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  527. {
  528. struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
  529. struct trunk_reqall *ra = (struct trunk_reqall *)data;
  530. struct trunk_reqport *rp = (struct trunk_reqport *)data, rpbuf;
  531. struct ifreq *ifr = (struct ifreq *)data;
  532. struct ifaddr *ifa = (struct ifaddr *)data;
  533. struct trunk_port *tp;
  534. struct ifnet *tpif;
  535. int s, i, error = 0;
  536. s = splnet();
  537. bzero(&rpbuf, sizeof(rpbuf));
  538. switch (cmd) {
  539. case SIOCGTRUNK:
  540. ra->ra_proto = tr->tr_proto;
  541. if (tr->tr_req != NULL)
  542. (*tr->tr_req)(tr, (caddr_t)&ra->ra_psc);
  543. ra->ra_ports = i = 0;
  544. tp = SLIST_FIRST(&tr->tr_ports);
  545. while (tp && ra->ra_size >=
  546. i + sizeof(struct trunk_reqport)) {
  547. trunk_port2req(tp, &rpbuf);
  548. error = copyout(&rpbuf, (caddr_t)ra->ra_port + i,
  549. sizeof(struct trunk_reqport));
  550. if (error)
  551. break;
  552. i += sizeof(struct trunk_reqport);
  553. ra->ra_ports++;
  554. tp = SLIST_NEXT(tp, tp_entries);
  555. }
  556. break;
  557. case SIOCSTRUNK:
  558. if ((error = suser(curproc, 0)) != 0) {
  559. error = EPERM;
  560. break;
  561. }
  562. if (ra->ra_proto >= TRUNK_PROTO_MAX) {
  563. error = EPROTONOSUPPORT;
  564. break;
  565. }
  566. if (tr->tr_proto != TRUNK_PROTO_NONE)
  567. error = tr->tr_detach(tr);
  568. if (error != 0)
  569. break;
  570. for (i = 0; i < (sizeof(trunk_protos) /
  571. sizeof(trunk_protos[0])); i++) {
  572. if (trunk_protos[i].ti_proto == ra->ra_proto) {
  573. if (tr->tr_ifflags & IFF_DEBUG)
  574. printf("%s: using proto %u\n",
  575. tr->tr_ifname,
  576. trunk_protos[i].ti_proto);
  577. tr->tr_proto = trunk_protos[i].ti_proto;
  578. if (tr->tr_proto != TRUNK_PROTO_NONE)
  579. error = trunk_protos[i].ti_attach(tr);
  580. goto out;
  581. }
  582. }
  583. error = EPROTONOSUPPORT;
  584. break;
  585. case SIOCGTRUNKPORT:
  586. if (rp->rp_portname[0] == '\0' ||
  587. (tpif = ifunit(rp->rp_portname)) == NULL) {
  588. error = EINVAL;
  589. break;
  590. }
  591. /* Search in all trunks if the global flag is set */
  592. if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ?
  593. NULL : tr, tpif)) == NULL) {
  594. error = ENOENT;
  595. break;
  596. }
  597. trunk_port2req(tp, rp);
  598. break;
  599. case SIOCSTRUNKPORT:
  600. if ((error = suser(curproc, 0)) != 0) {
  601. error = EPERM;
  602. break;
  603. }
  604. if (rp->rp_portname[0] == '\0' ||
  605. (tpif = ifunit(rp->rp_portname)) == NULL) {
  606. error = EINVAL;
  607. break;
  608. }
  609. error = trunk_port_create(tr, tpif);
  610. break;
  611. case SIOCSTRUNKDELPORT:
  612. if ((error = suser(curproc, 0)) != 0) {
  613. error = EPERM;
  614. break;
  615. }
  616. if (rp->rp_portname[0] == '\0' ||
  617. (tpif = ifunit(rp->rp_portname)) == NULL) {
  618. error = EINVAL;
  619. break;
  620. }
  621. /* Search in all trunks if the global flag is set */
  622. if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ?
  623. NULL : tr, tpif)) == NULL) {
  624. error = ENOENT;
  625. break;
  626. }
  627. error = trunk_port_destroy(tp);
  628. break;
  629. case SIOCSIFADDR:
  630. ifp->if_flags |= IFF_UP;
  631. if (ifa->ifa_addr->sa_family == AF_INET)
  632. arp_ifinit(&tr->tr_ac, ifa);
  633. error = ENETRESET;
  634. break;
  635. case SIOCSIFFLAGS:
  636. error = ENETRESET;
  637. break;
  638. case SIOCADDMULTI:
  639. error = trunk_ether_addmulti(tr, ifr);
  640. break;
  641. case SIOCDELMULTI:
  642. error = trunk_ether_delmulti(tr, ifr);
  643. break;
  644. case SIOCSIFMEDIA:
  645. case SIOCGIFMEDIA:
  646. error = ifmedia_ioctl(ifp, ifr, &tr->tr_media, cmd);
  647. break;
  648. case SIOCSIFLLADDR:
  649. /* Update the port lladdrs as well */
  650. SLIST_FOREACH(tp, &tr->tr_ports, tp_entries)
  651. trunk_port_lladdr(tp, ifr->ifr_addr.sa_data);
  652. error = ENETRESET;
  653. break;
  654. default:
  655. error = ether_ioctl(ifp, &tr->tr_ac, cmd, data);
  656. }
  657. if (error == ENETRESET) {
  658. if (ifp->if_flags & IFF_UP) {
  659. if ((ifp->if_flags & IFF_RUNNING) == 0)
  660. trunk_init(ifp);
  661. } else {
  662. if (ifp->if_flags & IFF_RUNNING)
  663. trunk_stop(ifp);
  664. }
  665. error = 0;
  666. }
  667. out:
  668. splx(s);
  669. return (error);
  670. }
  671. int
  672. trunk_ether_addmulti(struct trunk_softc *tr, struct ifreq *ifr)
  673. {
  674. struct trunk_mc *mc;
  675. u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
  676. int error;
  677. /* Ignore ENETRESET error code */
  678. if ((error = ether_addmulti(ifr, &tr->tr_ac)) != ENETRESET)
  679. return (error);
  680. if ((mc = malloc(sizeof(*mc), M_DEVBUF, M_NOWAIT)) == NULL) {
  681. error = ENOMEM;
  682. goto failed;
  683. }
  684. ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
  685. ETHER_LOOKUP_MULTI(addrlo, addrhi, &tr->tr_ac, mc->mc_enm);
  686. bcopy(&ifr->ifr_addr, &mc->mc_addr, ifr->ifr_addr.sa_len);
  687. SLIST_INSERT_HEAD(&tr->tr_mc_head, mc, mc_entries);
  688. if ((error = trunk_ioctl_allports(tr, SIOCADDMULTI,
  689. (caddr_t)ifr)) != 0) {
  690. trunk_ether_delmulti(tr, ifr);
  691. return (error);
  692. }
  693. return (error);
  694. failed:
  695. ether_delmulti(ifr, &tr->tr_ac);
  696. return (error);
  697. }
  698. int
  699. trunk_ether_delmulti(struct trunk_softc *tr, struct ifreq *ifr)
  700. {
  701. struct ether_multi *enm;
  702. struct trunk_mc *mc;
  703. u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
  704. int error;
  705. if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0)
  706. return (error);
  707. ETHER_LOOKUP_MULTI(addrlo, addrhi, &tr->tr_ac, enm);
  708. if (enm == NULL)
  709. return (EINVAL);
  710. SLIST_FOREACH(mc, &tr->tr_mc_head, mc_entries)
  711. if (mc->mc_enm == enm)
  712. break;
  713. /* We won't delete entries we didn't add */
  714. if (mc == NULL)
  715. return (EINVAL);
  716. if ((error = ether_delmulti(ifr, &tr->tr_ac)) != ENETRESET)
  717. return (error);
  718. /* We no longer use this multicast address. Tell parent so. */
  719. error = trunk_ioctl_allports(tr, SIOCDELMULTI, (caddr_t)ifr);
  720. if (error == 0) {
  721. SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries);
  722. free(mc, M_DEVBUF, sizeof(*mc));
  723. } else {
  724. /* XXX At least one port failed to remove the address */
  725. if (tr->tr_ifflags & IFF_DEBUG) {
  726. printf("%s: failed to remove multicast address "
  727. "on all ports (%d)\n", tr->tr_ifname, error);
  728. }
  729. (void)ether_addmulti(ifr, &tr->tr_ac);
  730. }
  731. return (0);
  732. }
  733. void
  734. trunk_ether_purgemulti(struct trunk_softc *tr)
  735. {
  736. struct trunk_mc *mc;
  737. struct trunk_ifreq ifs;
  738. struct ifreq *ifr = &ifs.ifreq.ifreq;
  739. while ((mc = SLIST_FIRST(&tr->tr_mc_head)) != NULL) {
  740. bcopy(&mc->mc_addr, &ifr->ifr_addr, mc->mc_addr.ss_len);
  741. /* Try to remove multicast address on all ports */
  742. trunk_ioctl_allports(tr, SIOCDELMULTI, (caddr_t)ifr);
  743. SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries);
  744. free(mc, M_DEVBUF, sizeof(*mc));
  745. }
  746. }
  747. int
  748. trunk_ether_cmdmulti(struct trunk_port *tp, u_long cmd)
  749. {
  750. struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
  751. struct trunk_mc *mc;
  752. struct trunk_ifreq ifs;
  753. struct ifreq *ifr = &ifs.ifreq.ifreq;
  754. int ret, error = 0;
  755. bcopy(tp->tp_ifname, ifr->ifr_name, IFNAMSIZ);
  756. SLIST_FOREACH(mc, &tr->tr_mc_head, mc_entries) {
  757. bcopy(&mc->mc_addr, &ifr->ifr_addr, mc->mc_addr.ss_len);
  758. if ((ret = tp->tp_ioctl(tp->tp_if, cmd, (caddr_t)ifr)) != 0) {
  759. if (tr->tr_ifflags & IFF_DEBUG) {
  760. printf("%s: ioctl %lu failed on %s: %d\n",
  761. tr->tr_ifname, cmd, tp->tp_ifname, ret);
  762. }
  763. /* Store last known error and continue */
  764. error = ret;
  765. }
  766. }
  767. return (error);
  768. }
  769. int
  770. trunk_ioctl_allports(struct trunk_softc *tr, u_long cmd, caddr_t data)
  771. {
  772. struct ifreq *ifr = (struct ifreq *)data;
  773. struct trunk_port *tp;
  774. int ret, error = 0;
  775. SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
  776. bcopy(tp->tp_ifname, ifr->ifr_name, IFNAMSIZ);
  777. if ((ret = tp->tp_ioctl(tp->tp_if, cmd, data)) != 0) {
  778. if (tr->tr_ifflags & IFF_DEBUG) {
  779. printf("%s: ioctl %lu failed on %s: %d\n",
  780. tr->tr_ifname, cmd, tp->tp_ifname, ret);
  781. }
  782. /* Store last known error and continue */
  783. error = ret;
  784. }
  785. }
  786. return (error);
  787. }
  788. void
  789. trunk_start(struct ifnet *ifp)
  790. {
  791. struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
  792. struct mbuf *m;
  793. int error;
  794. for (;;) {
  795. IFQ_DEQUEUE(&ifp->if_snd, m);
  796. if (m == NULL)
  797. break;
  798. #if NBPFILTER > 0
  799. if (ifp->if_bpf)
  800. bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT);
  801. #endif
  802. if (tr->tr_proto != TRUNK_PROTO_NONE && tr->tr_count) {
  803. error = (*tr->tr_start)(tr, m);
  804. if (error == 0)
  805. ifp->if_opackets++;
  806. else
  807. ifp->if_oerrors++;
  808. } else {
  809. m_freem(m);
  810. if (tr->tr_proto != TRUNK_PROTO_NONE)
  811. ifp->if_oerrors++;
  812. }
  813. }
  814. }
  815. u_int32_t
  816. trunk_hashmbuf(struct mbuf *m, SIPHASH_KEY *key)
  817. {
  818. u_int16_t etype, ether_vtag;
  819. u_int32_t p = 0;
  820. u_int16_t *vlan, vlanbuf[2];
  821. int off;
  822. struct ether_header *eh;
  823. struct ip *ip, ipbuf;
  824. #ifdef INET6
  825. u_int32_t flow;
  826. struct ip6_hdr *ip6, ip6buf;
  827. #endif
  828. SIPHASH_CTX ctx;
  829. SipHash24_Init(&ctx, key);
  830. off = sizeof(*eh);
  831. if (m->m_len < off)
  832. goto done;
  833. eh = mtod(m, struct ether_header *);
  834. etype = ntohs(eh->ether_type);
  835. SipHash24_Update(&ctx, &eh->ether_shost, ETHER_ADDR_LEN);
  836. SipHash24_Update(&ctx, &eh->ether_dhost, ETHER_ADDR_LEN);
  837. /* Special handling for encapsulating VLAN frames */
  838. if (m->m_flags & M_VLANTAG) {
  839. ether_vtag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
  840. SipHash24_Update(&ctx, &ether_vtag, sizeof(ether_vtag));
  841. } else if (etype == ETHERTYPE_VLAN) {
  842. if ((vlan = (u_int16_t *)
  843. trunk_gethdr(m, off, EVL_ENCAPLEN, &vlanbuf)) == NULL)
  844. return (p);
  845. ether_vtag = EVL_VLANOFTAG(*vlan);
  846. SipHash24_Update(&ctx, &ether_vtag, sizeof(ether_vtag));
  847. etype = ntohs(vlan[1]);
  848. off += EVL_ENCAPLEN;
  849. }
  850. switch (etype) {
  851. case ETHERTYPE_IP:
  852. if ((ip = (struct ip *)
  853. trunk_gethdr(m, off, sizeof(*ip), &ipbuf)) == NULL)
  854. return (p);
  855. SipHash24_Update(&ctx, &ip->ip_src, sizeof(struct in_addr));
  856. SipHash24_Update(&ctx, &ip->ip_dst, sizeof(struct in_addr));
  857. break;
  858. #ifdef INET6
  859. case ETHERTYPE_IPV6:
  860. if ((ip6 = (struct ip6_hdr *)
  861. trunk_gethdr(m, off, sizeof(*ip6), &ip6buf)) == NULL)
  862. return (p);
  863. SipHash24_Update(&ctx, &ip6->ip6_src, sizeof(struct in6_addr));
  864. SipHash24_Update(&ctx, &ip6->ip6_dst, sizeof(struct in6_addr));
  865. flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK;
  866. SipHash24_Update(&ctx, &flow, sizeof(flow)); /* IPv6 flow label */
  867. break;
  868. #endif
  869. }
  870. done:
  871. return SipHash24_End(&ctx);
  872. }
  873. void
  874. trunk_init(struct ifnet *ifp)
  875. {
  876. struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
  877. int s;
  878. s = splnet();
  879. ifp->if_flags |= IFF_RUNNING;
  880. ifp->if_flags &= ~IFF_OACTIVE;
  881. if (tr->tr_init != NULL)
  882. (*tr->tr_init)(tr);
  883. splx(s);
  884. }
  885. void
  886. trunk_stop(struct ifnet *ifp)
  887. {
  888. struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
  889. int s;
  890. s = splnet();
  891. ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
  892. if (tr->tr_stop != NULL)
  893. (*tr->tr_stop)(tr);
  894. splx(s);
  895. }
  896. void
  897. trunk_watchdog(struct ifnet *ifp)
  898. {
  899. struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
  900. if (tr->tr_proto != TRUNK_PROTO_NONE &&
  901. (*tr->tr_watchdog)(tr) != 0) {
  902. ifp->if_oerrors++;
  903. }
  904. }
  905. int
  906. trunk_input(struct ifnet *ifp, struct mbuf *m)
  907. {
  908. struct trunk_softc *tr;
  909. struct trunk_port *tp;
  910. struct ifnet *trifp = NULL;
  911. struct ether_header *eh;
  912. struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  913. eh = mtod(m, struct ether_header *);
  914. if (ETHER_IS_MULTICAST(eh->ether_dhost))
  915. ifp->if_imcasts++;
  916. /* Should be checked by the caller */
  917. if (ifp->if_type != IFT_IEEE8023ADLAG)
  918. goto bad;
  919. if ((tp = (struct trunk_port *)ifp->if_tp) == NULL ||
  920. (tr = (struct trunk_softc *)tp->tp_trunk) == NULL)
  921. goto bad;
  922. trifp = &tr->tr_ac.ac_if;
  923. if (tr->tr_proto == TRUNK_PROTO_NONE)
  924. goto bad;
  925. if ((*tr->tr_input)(tr, tp, m)) {
  926. /*
  927. * We stop here if the packet has been consumed
  928. * by the protocol routine.
  929. */
  930. m_freem(m);
  931. return (1);
  932. }
  933. if ((trifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
  934. goto bad;
  935. /*
  936. * Drop promiscuously received packets if we are not in
  937. * promiscuous mode.
  938. */
  939. if (!ETHER_IS_MULTICAST(eh->ether_dhost) &&
  940. (ifp->if_flags & IFF_PROMISC) &&
  941. (trifp->if_flags & IFF_PROMISC) == 0) {
  942. if (bcmp(&tr->tr_ac.ac_enaddr, eh->ether_dhost,
  943. ETHER_ADDR_LEN)) {
  944. m_freem(m);
  945. return (1);
  946. }
  947. }
  948. ml_enqueue(&ml, m);
  949. if_input(trifp, &ml);
  950. return (1);
  951. bad:
  952. if (trifp != NULL)
  953. trifp->if_ierrors++;
  954. m_freem(m);
  955. return (1);
  956. }
  957. int
  958. trunk_media_change(struct ifnet *ifp)
  959. {
  960. struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
  961. if (tr->tr_ifflags & IFF_DEBUG)
  962. printf("%s\n", __func__);
  963. /* Ignore */
  964. return (0);
  965. }
  966. void
  967. trunk_media_status(struct ifnet *ifp, struct ifmediareq *imr)
  968. {
  969. struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
  970. struct trunk_port *tp;
  971. imr->ifm_status = IFM_AVALID;
  972. imr->ifm_active = IFM_ETHER | IFM_AUTO;
  973. SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
  974. if (TRUNK_PORTACTIVE(tp))
  975. imr->ifm_status |= IFM_ACTIVE;
  976. }
  977. }
  978. void
  979. trunk_port_state(void *arg)
  980. {
  981. struct trunk_port *tp = (struct trunk_port *)arg;
  982. struct trunk_softc *tr = NULL;
  983. if (tp != NULL)
  984. tr = (struct trunk_softc *)tp->tp_trunk;
  985. if (tr == NULL)
  986. return;
  987. if (tr->tr_linkstate != NULL)
  988. (*tr->tr_linkstate)(tp);
  989. trunk_link_active(tr, tp);
  990. }
  991. struct trunk_port *
  992. trunk_link_active(struct trunk_softc *tr, struct trunk_port *tp)
  993. {
  994. struct trunk_port *tp_next, *rval = NULL;
  995. int new_link = LINK_STATE_DOWN;
  996. /*
  997. * Search a port which reports an active link state.
  998. */
  999. if (tp == NULL)
  1000. goto search;
  1001. if (TRUNK_PORTACTIVE(tp)) {
  1002. rval = tp;
  1003. goto found;
  1004. }
  1005. if ((tp_next = SLIST_NEXT(tp, tp_entries)) != NULL &&
  1006. TRUNK_PORTACTIVE(tp_next)) {
  1007. rval = tp_next;
  1008. goto found;
  1009. }
  1010. search:
  1011. SLIST_FOREACH(tp_next, &tr->tr_ports, tp_entries) {
  1012. if (TRUNK_PORTACTIVE(tp_next)) {
  1013. rval = tp_next;
  1014. goto found;
  1015. }
  1016. }
  1017. found:
  1018. if (rval != NULL) {
  1019. /*
  1020. * The IEEE 802.1D standard assumes that a trunk with
  1021. * multiple ports is always full duplex. This is valid
  1022. * for load sharing trunks and if at least two links
  1023. * are active. Unfortunately, checking the latter would
  1024. * be too expensive at this point.
  1025. */
  1026. if ((tr->tr_capabilities & IFCAP_TRUNK_FULLDUPLEX) &&
  1027. (tr->tr_count > 1))
  1028. new_link = LINK_STATE_FULL_DUPLEX;
  1029. else
  1030. new_link = rval->tp_link_state;
  1031. }
  1032. if (tr->tr_ac.ac_if.if_link_state != new_link) {
  1033. tr->tr_ac.ac_if.if_link_state = new_link;
  1034. if_link_state_change(&tr->tr_ac.ac_if);
  1035. }
  1036. return (rval);
  1037. }
  1038. const void *
  1039. trunk_gethdr(struct mbuf *m, u_int off, u_int len, void *buf)
  1040. {
  1041. if (m->m_pkthdr.len < (off + len))
  1042. return (NULL);
  1043. else if (m->m_len < (off + len)) {
  1044. m_copydata(m, off, len, buf);
  1045. return (buf);
  1046. }
  1047. return (mtod(m, caddr_t) + off);
  1048. }
  1049. /*
  1050. * Simple round robin trunking
  1051. */
  1052. int
  1053. trunk_rr_attach(struct trunk_softc *tr)
  1054. {
  1055. struct trunk_port *tp;
  1056. tr->tr_detach = trunk_rr_detach;
  1057. tr->tr_start = trunk_rr_start;
  1058. tr->tr_input = trunk_rr_input;
  1059. tr->tr_init = NULL;
  1060. tr->tr_stop = NULL;
  1061. tr->tr_linkstate = NULL;
  1062. tr->tr_port_create = NULL;
  1063. tr->tr_port_destroy = trunk_rr_port_destroy;
  1064. tr->tr_capabilities = IFCAP_TRUNK_FULLDUPLEX;
  1065. tr->tr_req = NULL;
  1066. tr->tr_portreq = NULL;
  1067. tp = SLIST_FIRST(&tr->tr_ports);
  1068. tr->tr_psc = (caddr_t)tp;
  1069. return (0);
  1070. }
  1071. int
  1072. trunk_rr_detach(struct trunk_softc *tr)
  1073. {
  1074. tr->tr_psc = NULL;
  1075. return (0);
  1076. }
  1077. void
  1078. trunk_rr_port_destroy(struct trunk_port *tp)
  1079. {
  1080. struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
  1081. if (tp == (struct trunk_port *)tr->tr_psc)
  1082. tr->tr_psc = NULL;
  1083. }
  1084. int
  1085. trunk_rr_start(struct trunk_softc *tr, struct mbuf *m)
  1086. {
  1087. struct trunk_port *tp = (struct trunk_port *)tr->tr_psc, *tp_next;
  1088. int error = 0;
  1089. if (tp == NULL && (tp = trunk_link_active(tr, NULL)) == NULL) {
  1090. m_freem(m);
  1091. return (ENOENT);
  1092. }
  1093. if ((error = if_enqueue(tp->tp_if, m)) != 0)
  1094. return (error);
  1095. /* Get next active port */
  1096. tp_next = trunk_link_active(tr, SLIST_NEXT(tp, tp_entries));
  1097. tr->tr_psc = (caddr_t)tp_next;
  1098. return (0);
  1099. }
  1100. int
  1101. trunk_rr_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m)
  1102. {
  1103. /* Just pass in the packet to our trunk device */
  1104. return (0);
  1105. }
  1106. /*
  1107. * Active failover
  1108. */
  1109. int
  1110. trunk_fail_attach(struct trunk_softc *tr)
  1111. {
  1112. tr->tr_detach = trunk_fail_detach;
  1113. tr->tr_start = trunk_fail_start;
  1114. tr->tr_input = trunk_fail_input;
  1115. tr->tr_init = NULL;
  1116. tr->tr_stop = NULL;
  1117. tr->tr_port_create = NULL;
  1118. tr->tr_port_destroy = NULL;
  1119. tr->tr_linkstate = NULL;
  1120. tr->tr_req = NULL;
  1121. tr->tr_portreq = NULL;
  1122. return (0);
  1123. }
  1124. int
  1125. trunk_fail_detach(struct trunk_softc *tr)
  1126. {
  1127. return (0);
  1128. }
  1129. int
  1130. trunk_fail_start(struct trunk_softc *tr, struct mbuf *m)
  1131. {
  1132. struct trunk_port *tp;
  1133. /* Use the master port if active or the next available port */
  1134. if ((tp = trunk_link_active(tr, tr->tr_primary)) == NULL) {
  1135. m_freem(m);
  1136. return (ENOENT);
  1137. }
  1138. return (if_enqueue(tp->tp_if, m));
  1139. }
  1140. int
  1141. trunk_fail_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m)
  1142. {
  1143. struct trunk_port *tmp_tp;
  1144. int accept = 0;
  1145. if (tp == tr->tr_primary) {
  1146. accept = 1;
  1147. } else if (tr->tr_primary->tp_link_state == LINK_STATE_DOWN) {
  1148. tmp_tp = trunk_link_active(tr, NULL);
  1149. /*
  1150. * If tmp_tp is null, we've received a packet when all
  1151. * our links are down. Weird, but process it anyways.
  1152. */
  1153. if ((tmp_tp == NULL || tmp_tp == tp))
  1154. accept = 1;
  1155. }
  1156. if (!accept)
  1157. return (-1);
  1158. return (0);
  1159. }
  1160. /*
  1161. * Loadbalancing
  1162. */
  1163. int
  1164. trunk_lb_attach(struct trunk_softc *tr)
  1165. {
  1166. struct trunk_lb *lb;
  1167. if ((lb = malloc(sizeof(*lb), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
  1168. return (ENOMEM);
  1169. tr->tr_detach = trunk_lb_detach;
  1170. tr->tr_start = trunk_lb_start;
  1171. tr->tr_input = trunk_lb_input;
  1172. tr->tr_port_create = trunk_lb_port_create;
  1173. tr->tr_port_destroy = trunk_lb_port_destroy;
  1174. tr->tr_linkstate = NULL;
  1175. tr->tr_capabilities = IFCAP_TRUNK_FULLDUPLEX;
  1176. tr->tr_req = NULL;
  1177. tr->tr_portreq = NULL;
  1178. tr->tr_init = NULL;
  1179. tr->tr_stop = NULL;
  1180. arc4random_buf(&lb->lb_key, sizeof(lb->lb_key));
  1181. tr->tr_psc = (caddr_t)lb;
  1182. return (0);
  1183. }
  1184. int
  1185. trunk_lb_detach(struct trunk_softc *tr)
  1186. {
  1187. struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc;
  1188. if (lb != NULL)
  1189. free(lb, M_DEVBUF, 0);
  1190. return (0);
  1191. }
  1192. int
  1193. trunk_lb_porttable(struct trunk_softc *tr, struct trunk_port *tp)
  1194. {
  1195. struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc;
  1196. struct trunk_port *tp_next;
  1197. int i = 0;
  1198. bzero(&lb->lb_ports, sizeof(lb->lb_ports));
  1199. SLIST_FOREACH(tp_next, &tr->tr_ports, tp_entries) {
  1200. if (tp_next == tp)
  1201. continue;
  1202. if (i >= TRUNK_MAX_PORTS)
  1203. return (EINVAL);
  1204. if (tr->tr_ifflags & IFF_DEBUG)
  1205. printf("%s: port %s at index %d\n",
  1206. tr->tr_ifname, tp_next->tp_ifname, i);
  1207. lb->lb_ports[i++] = tp_next;
  1208. }
  1209. return (0);
  1210. }
  1211. int
  1212. trunk_lb_port_create(struct trunk_port *tp)
  1213. {
  1214. struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
  1215. return (trunk_lb_porttable(tr, NULL));
  1216. }
  1217. void
  1218. trunk_lb_port_destroy(struct trunk_port *tp)
  1219. {
  1220. struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
  1221. trunk_lb_porttable(tr, tp);
  1222. }
  1223. int
  1224. trunk_lb_start(struct trunk_softc *tr, struct mbuf *m)
  1225. {
  1226. struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc;
  1227. struct trunk_port *tp = NULL;
  1228. u_int32_t p = 0;
  1229. p = trunk_hashmbuf(m, &lb->lb_key);
  1230. p %= tr->tr_count;
  1231. tp = lb->lb_ports[p];
  1232. /*
  1233. * Check the port's link state. This will return the next active
  1234. * port if the link is down or the port is NULL.
  1235. */
  1236. if ((tp = trunk_link_active(tr, tp)) == NULL) {
  1237. m_freem(m);
  1238. return (ENOENT);
  1239. }
  1240. return (if_enqueue(tp->tp_if, m));
  1241. }
  1242. int
  1243. trunk_lb_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m)
  1244. {
  1245. /* Just pass in the packet to our trunk device */
  1246. return (0);
  1247. }
  1248. /*
  1249. * Broadcast mode
  1250. */
  1251. int
  1252. trunk_bcast_attach(struct trunk_softc *tr)
  1253. {
  1254. tr->tr_detach = trunk_bcast_detach;
  1255. tr->tr_start = trunk_bcast_start;
  1256. tr->tr_input = trunk_bcast_input;
  1257. tr->tr_init = NULL;
  1258. tr->tr_stop = NULL;
  1259. tr->tr_port_create = NULL;
  1260. tr->tr_port_destroy = NULL;
  1261. tr->tr_linkstate = NULL;
  1262. tr->tr_req = NULL;
  1263. tr->tr_portreq = NULL;
  1264. return (0);
  1265. }
  1266. int
  1267. trunk_bcast_detach(struct trunk_softc *tr)
  1268. {
  1269. return (0);
  1270. }
  1271. int
  1272. trunk_bcast_start(struct trunk_softc *tr, struct mbuf *m0)
  1273. {
  1274. int active_ports = 0;
  1275. int errors = 0;
  1276. int ret;
  1277. struct trunk_port *tp, *last = NULL;
  1278. struct mbuf *m;
  1279. SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
  1280. if (!TRUNK_PORTACTIVE(tp))
  1281. continue;
  1282. active_ports++;
  1283. if (last != NULL) {
  1284. m = m_copym(m0, 0, M_COPYALL, M_DONTWAIT);
  1285. if (m == NULL) {
  1286. ret = ENOBUFS;
  1287. errors++;
  1288. break;
  1289. }
  1290. ret = if_enqueue(last->tp_if, m);
  1291. if (ret != 0)
  1292. errors++;
  1293. }
  1294. last = tp;
  1295. }
  1296. if (last == NULL) {
  1297. m_freem(m0);
  1298. return (ENOENT);
  1299. }
  1300. ret = if_enqueue(last->tp_if, m0);
  1301. if (ret != 0)
  1302. errors++;
  1303. if (errors == active_ports)
  1304. return (ret);
  1305. return (0);
  1306. }
  1307. int
  1308. trunk_bcast_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m)
  1309. {
  1310. return (0);
  1311. }
  1312. /*
  1313. * 802.3ad LACP
  1314. */
  1315. int
  1316. trunk_lacp_attach(struct trunk_softc *tr)
  1317. {
  1318. struct trunk_port *tp;
  1319. int error;
  1320. tr->tr_detach = trunk_lacp_detach;
  1321. tr->tr_port_create = lacp_port_create;
  1322. tr->tr_port_destroy = lacp_port_destroy;
  1323. tr->tr_linkstate = lacp_linkstate;
  1324. tr->tr_start = trunk_lacp_start;
  1325. tr->tr_input = trunk_lacp_input;
  1326. tr->tr_init = lacp_init;
  1327. tr->tr_stop = lacp_stop;
  1328. tr->tr_req = lacp_req;
  1329. tr->tr_portreq = lacp_portreq;
  1330. error = lacp_attach(tr);
  1331. if (error)
  1332. return (error);
  1333. SLIST_FOREACH(tp, &tr->tr_ports, tp_entries)
  1334. lacp_port_create(tp);
  1335. return (error);
  1336. }
  1337. int
  1338. trunk_lacp_detach(struct trunk_softc *tr)
  1339. {
  1340. struct trunk_port *tp;
  1341. int error;
  1342. SLIST_FOREACH(tp, &tr->tr_ports, tp_entries)
  1343. lacp_port_destroy(tp);
  1344. /* unlocking is safe here */
  1345. error = lacp_detach(tr);
  1346. return (error);
  1347. }
  1348. int
  1349. trunk_lacp_start(struct trunk_softc *tr, struct mbuf *m)
  1350. {
  1351. struct trunk_port *tp;
  1352. tp = lacp_select_tx_port(tr, m);
  1353. if (tp == NULL) {
  1354. m_freem(m);
  1355. return (EBUSY);
  1356. }
  1357. return (if_enqueue(tp->tp_if, m));
  1358. }
  1359. int
  1360. trunk_lacp_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m)
  1361. {
  1362. return (lacp_input(tp, m));
  1363. }