ng_fec.c revision 152032
1/* 2 * ng_fec.c 3 */ 4 5/*- 6 * Copyright (c) 2001 Berkeley Software Design, Inc. 7 * Copyright (c) 2000, 2001 8 * Bill Paul <wpaul@osd.bsdi.com>. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by Bill Paul. 21 * 4. Neither the name of the author nor the names of any co-contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 35 * THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * $FreeBSD: head/sys/netgraph/ng_fec.c 152032 2005-11-04 16:29:51Z ru $ 38 */ 39/*- 40 * Copyright (c) 1996-1999 Whistle Communications, Inc. 41 * All rights reserved. 42 * 43 * Subject to the following obligations and disclaimer of warranty, use and 44 * redistribution of this software, in source or object code forms, with or 45 * without modifications are expressly permitted by Whistle Communications; 46 * provided, however, that: 47 * 1. Any and all reproductions of the source or object code must include the 48 * copyright notice above and the following disclaimer of warranties; and 49 * 2. No rights are granted, in any manner or form, to use Whistle 50 * Communications, Inc. trademarks, including the mark "WHISTLE 51 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 52 * such appears in the above copyright notice or in the software. 53 * 54 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 55 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 56 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 57 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 58 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 59 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 60 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 61 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 62 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 63 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 64 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 65 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 66 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 67 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 68 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 69 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 70 * OF SUCH DAMAGE. 71 * 72 * Author: Archie Cobbs <archie@freebsd.org> 73 * 74 * $Whistle: ng_fec.c,v 1.33 1999/11/01 09:24:51 julian Exp $ 75 */ 76 77/* 78 * This module implements ethernet channel bonding using the Cisco 79 * Fast EtherChannel mechanism. Two or four ports may be combined 80 * into a single aggregate interface. 81 * 82 * Interfaces are named fec0, fec1, etc. New nodes take the 83 * first available interface name. 84 * 85 * This node also includes Berkeley packet filter support. 86 * 87 * Note that this node doesn't need to connect to any other 88 * netgraph nodes in order to do its work. 89 */ 90 91#include <sys/param.h> 92#include <sys/systm.h> 93#include <sys/errno.h> 94#include <sys/kernel.h> 95#include <sys/malloc.h> 96#include <sys/mbuf.h> 97#include <sys/errno.h> 98#include <sys/sockio.h> 99#include <sys/socket.h> 100#include <sys/syslog.h> 101#include <sys/libkern.h> 102#include <sys/queue.h> 103 104#include <net/if.h> 105#include <net/if_types.h> 106#include <net/if_arp.h> 107#include <net/if_media.h> 108#include <net/bpf.h> 109#include <net/ethernet.h> 110 111#include "opt_inet.h" 112#include "opt_inet6.h" 113 114#include <netinet/in.h> 115#ifdef INET 116#include <netinet/in_systm.h> 117#include <netinet/ip.h> 118#endif 119 120#ifdef INET6 121#include <netinet/ip6.h> 122#endif 123 124#include <netgraph/ng_message.h> 125#include <netgraph/netgraph.h> 126#include <netgraph/ng_parse.h> 127#include <netgraph/ng_fec.h> 128 129/* 130 * We need a way to stash a pointer to our netgraph node in the 131 * ifnet structure so that receive handling works. As far as I can 132 * tell, although there is an AF_NETGRAPH address family, it's only 133 * used to identify sockaddr_ng structures: there is no netgraph address 134 * family domain. This means the AF_NETGRAPH entry in ifp->if_afdata 135 * should be unused, so we can use to hold our node context. 136 */ 137#define IFP2NG(ifp) (struct ng_node *)(ifp->if_afdata[AF_NETGRAPH]) 138#define IFP2NG_SET(ifp, val) ifp->if_afdata[AF_NETGRAPH] = (val); 139#define FEC_INC(x, y) (x) = (x + 1) % y 140 141/* 142 * Current fast etherchannel implementations use either 2 or 4 143 * ports, so for now we limit the maximum bundle size to 4 interfaces. 144 */ 145#define FEC_BUNDLESIZ 4 146 147struct ng_fec_portlist { 148 struct ifnet *fec_if; 149 void (*fec_if_input) (struct ifnet *, 150 struct mbuf *); 151 int fec_idx; 152 int fec_ifstat; 153 struct ether_addr fec_mac; 154 TAILQ_ENTRY(ng_fec_portlist) fec_list; 155}; 156 157struct ng_fec_bundle { 158 TAILQ_HEAD(,ng_fec_portlist) ng_fec_ports; 159 int fec_ifcnt; 160 int fec_btype; 161 int (*fec_if_output) (struct ifnet *, 162 struct mbuf *, 163 struct sockaddr *, 164 struct rtentry *); 165}; 166 167#define FEC_BTYPE_MAC 0x01 168#define FEC_BTYPE_INET 0x02 169#define FEC_BTYPE_INET6 0x03 170 171/* Node private data */ 172struct ng_fec_private { 173 struct ifnet *ifp; 174 struct ifmedia ifmedia; 175 int if_flags; 176 int if_error; /* XXX */ 177 int unit; /* Interface unit number */ 178 node_p node; /* Our netgraph node */ 179 struct ng_fec_bundle fec_bundle;/* Aggregate bundle */ 180 struct callout_handle fec_ch; /* callout handle for ticker */ 181}; 182typedef struct ng_fec_private *priv_p; 183 184/* Interface methods */ 185static void ng_fec_input(struct ifnet *, struct mbuf *); 186static void ng_fec_start(struct ifnet *ifp); 187static int ng_fec_choose_port(struct ng_fec_bundle *b, 188 struct mbuf *m, struct ifnet **ifp); 189static int ng_fec_setport(struct ifnet *ifp, u_long cmd, caddr_t data); 190static void ng_fec_init(void *arg); 191static void ng_fec_stop(struct ifnet *ifp); 192static int ng_fec_ifmedia_upd(struct ifnet *ifp); 193static void ng_fec_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr); 194static int ng_fec_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); 195static int ng_fec_output(struct ifnet *ifp, struct mbuf *m0, 196 struct sockaddr *dst, struct rtentry *rt0); 197static void ng_fec_tick(void *arg); 198static int ng_fec_addport(struct ng_fec_private *priv, char *iface); 199static int ng_fec_delport(struct ng_fec_private *priv, char *iface); 200 201#ifdef DEBUG 202static void ng_fec_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data); 203#endif 204 205/* Netgraph methods */ 206static int ng_fec_mod_event(module_t, int, void *); 207static ng_constructor_t ng_fec_constructor; 208static ng_rcvmsg_t ng_fec_rcvmsg; 209static ng_shutdown_t ng_fec_shutdown; 210 211/* List of commands and how to convert arguments to/from ASCII */ 212static const struct ng_cmdlist ng_fec_cmds[] = { 213 { 214 NGM_FEC_COOKIE, 215 NGM_FEC_ADD_IFACE, 216 "add_iface", 217 &ng_parse_string_type, 218 NULL, 219 }, 220 { 221 NGM_FEC_COOKIE, 222 NGM_FEC_DEL_IFACE, 223 "del_iface", 224 &ng_parse_string_type, 225 NULL, 226 }, 227 { 228 NGM_FEC_COOKIE, 229 NGM_FEC_SET_MODE_MAC, 230 "set_mode_mac", 231 NULL, 232 NULL, 233 }, 234 { 235 NGM_FEC_COOKIE, 236 NGM_FEC_SET_MODE_INET, 237 "set_mode_inet", 238 NULL, 239 NULL, 240 }, 241 { 0 } 242}; 243 244/* Node type descriptor */ 245static struct ng_type typestruct = { 246 .version = NG_ABI_VERSION, 247 .name = NG_FEC_NODE_TYPE, 248 .mod_event = ng_fec_mod_event, 249 .constructor = ng_fec_constructor, 250 .rcvmsg = ng_fec_rcvmsg, 251 .shutdown = ng_fec_shutdown, 252 .cmdlist = ng_fec_cmds, 253}; 254NETGRAPH_INIT(fec, &typestruct); 255 256/* We keep a bitmap indicating which unit numbers are free. 257 One means the unit number is free, zero means it's taken. */ 258static int *ng_fec_units = NULL; 259static int ng_fec_units_len = 0; 260static int ng_units_in_use = 0; 261 262#define UNITS_BITSPERWORD (sizeof(*ng_fec_units) * NBBY) 263 264static struct mtx ng_fec_mtx; 265 266/* 267 * Find the first free unit number for a new interface. 268 * Increase the size of the unit bitmap as necessary. 269 */ 270static __inline int 271ng_fec_get_unit(int *unit) 272{ 273 int index, bit; 274 275 mtx_lock(&ng_fec_mtx); 276 for (index = 0; index < ng_fec_units_len 277 && ng_fec_units[index] == 0; index++); 278 if (index == ng_fec_units_len) { /* extend array */ 279 int i, *newarray, newlen; 280 281 newlen = (2 * ng_fec_units_len) + 4; 282 MALLOC(newarray, int *, newlen * sizeof(*ng_fec_units), 283 M_NETGRAPH, M_NOWAIT); 284 if (newarray == NULL) { 285 mtx_unlock(&ng_fec_mtx); 286 return (ENOMEM); 287 } 288 bcopy(ng_fec_units, newarray, 289 ng_fec_units_len * sizeof(*ng_fec_units)); 290 for (i = ng_fec_units_len; i < newlen; i++) 291 newarray[i] = ~0; 292 if (ng_fec_units != NULL) 293 FREE(ng_fec_units, M_NETGRAPH); 294 ng_fec_units = newarray; 295 ng_fec_units_len = newlen; 296 } 297 bit = ffs(ng_fec_units[index]) - 1; 298 KASSERT(bit >= 0 && bit <= UNITS_BITSPERWORD - 1, 299 ("%s: word=%d bit=%d", __func__, ng_fec_units[index], bit)); 300 ng_fec_units[index] &= ~(1 << bit); 301 *unit = (index * UNITS_BITSPERWORD) + bit; 302 ng_units_in_use++; 303 mtx_unlock(&ng_fec_mtx); 304 return (0); 305} 306 307/* 308 * Free a no longer needed unit number. 309 */ 310static __inline void 311ng_fec_free_unit(int unit) 312{ 313 int index, bit; 314 315 index = unit / UNITS_BITSPERWORD; 316 bit = unit % UNITS_BITSPERWORD; 317 mtx_lock(&ng_fec_mtx); 318 KASSERT(index < ng_fec_units_len, 319 ("%s: unit=%d len=%d", __func__, unit, ng_fec_units_len)); 320 KASSERT((ng_fec_units[index] & (1 << bit)) == 0, 321 ("%s: unit=%d is free", __func__, unit)); 322 ng_fec_units[index] |= (1 << bit); 323 /* 324 * XXX We could think about reducing the size of ng_fec_units[] 325 * XXX here if the last portion is all ones 326 * XXX At least free it if no more units 327 * Needed if we are to eventually be able to unload. 328 */ 329 ng_units_in_use--; 330 if (ng_units_in_use == 0) { /* XXX make SMP safe */ 331 FREE(ng_fec_units, M_NETGRAPH); 332 ng_fec_units_len = 0; 333 ng_fec_units = NULL; 334 } 335 mtx_unlock(&ng_fec_mtx); 336} 337 338/************************************************************************ 339 INTERFACE STUFF 340 ************************************************************************/ 341 342static int 343ng_fec_addport(struct ng_fec_private *priv, char *iface) 344{ 345 struct ng_fec_bundle *b; 346 struct ifnet *ifp, *bifp; 347 struct ng_fec_portlist *p, *new; 348 349 if (priv == NULL || iface == NULL) 350 return(EINVAL); 351 352 b = &priv->fec_bundle; 353 ifp = priv->ifp; 354 355 /* Only allow reconfiguration if not running. */ 356 if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 357 printf("fec%d: can't add new iface; bundle is running\n", 358 priv->unit); 359 return (EINVAL); 360 } 361 362 /* Find the interface */ 363 bifp = ifunit(iface); 364 if (bifp == NULL) { 365 printf("fec%d: tried to add iface %s, which " 366 "doesn't seem to exist\n", priv->unit, iface); 367 return(ENOENT); 368 } 369 370 /* See if we have room in the bundle */ 371 if (b->fec_ifcnt == FEC_BUNDLESIZ) { 372 printf("fec%d: can't add new iface; bundle is full\n", 373 priv->unit); 374 return(ENOSPC); 375 } 376 377 /* See if the interface is already in the bundle */ 378 TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) { 379 if (p->fec_if == bifp) { 380 printf("fec%d: iface %s is already in this " 381 "bundle\n", priv->unit, iface); 382 return(EINVAL); 383 } 384 } 385 386 /* 387 * All interfaces must use the same output vector. Once the 388 * user attaches an interface of one type, make all subsequent 389 * interfaces have the same output vector. 390 */ 391 if (b->fec_if_output != NULL) { 392 if (b->fec_if_output != bifp->if_output) { 393 printf("fec%d: iface %s is not the same type " 394 "as the other interface(s) already in " 395 "the bundle\n", priv->unit, iface); 396 return(EINVAL); 397 } 398 } 399 400 /* Allocate new list entry. */ 401 MALLOC(new, struct ng_fec_portlist *, 402 sizeof(struct ng_fec_portlist), M_NETGRAPH, M_NOWAIT); 403 if (new == NULL) 404 return(ENOMEM); 405 406 IF_AFDATA_LOCK(bifp); 407 bifp->if_afdata[AF_NETGRAPH] = priv->node; 408 IF_AFDATA_UNLOCK(bifp); 409 410 /* 411 * If this is the first interface added to the bundle, 412 * use its MAC address for the virtual interface (and, 413 * by extension, all the other ports in the bundle). 414 */ 415 if (b->fec_ifcnt == 0) 416 if_setlladdr(ifp, IFP2ENADDR(bifp), ETHER_ADDR_LEN); 417 418 b->fec_btype = FEC_BTYPE_MAC; 419 new->fec_idx = b->fec_ifcnt; 420 b->fec_ifcnt++; 421 422 /* Save the real MAC address. */ 423 bcopy(IFP2ENADDR(bifp), 424 (char *)&new->fec_mac, ETHER_ADDR_LEN); 425 426 /* Set up phony MAC address. */ 427 if_setlladdr(bifp, IFP2ENADDR(ifp), ETHER_ADDR_LEN); 428 429 /* Save original input vector */ 430 new->fec_if_input = bifp->if_input; 431 432 /* Override it with our own */ 433 bifp->if_input = ng_fec_input; 434 435 /* Save output vector too. */ 436 if (b->fec_if_output == NULL) 437 b->fec_if_output = bifp->if_output; 438 439 /* Add to the queue */ 440 new->fec_if = bifp; 441 new->fec_ifstat = -1; 442 TAILQ_INSERT_TAIL(&b->ng_fec_ports, new, fec_list); 443 444 return(0); 445} 446 447static int 448ng_fec_delport(struct ng_fec_private *priv, char *iface) 449{ 450 struct ng_fec_bundle *b; 451 struct ifnet *ifp, *bifp; 452 struct ng_fec_portlist *p; 453 454 if (priv == NULL || iface == NULL) 455 return(EINVAL); 456 457 b = &priv->fec_bundle; 458 ifp = priv->ifp; 459 460 /* Only allow reconfiguration if not running. */ 461 if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 462 printf("fec%d: can't remove iface; bundle is running\n", 463 priv->unit); 464 return (EINVAL); 465 } 466 467 /* Find the interface */ 468 bifp = ifunit(iface); 469 if (bifp == NULL) { 470 printf("fec%d: tried to remove iface %s, which " 471 "doesn't seem to exist\n", priv->unit, iface); 472 return(ENOENT); 473 } 474 475 TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) { 476 if (p->fec_if == bifp) 477 break; 478 } 479 480 if (p == NULL) { 481 printf("fec%d: tried to remove iface %s which " 482 "is not in our bundle\n", priv->unit, iface); 483 return(EINVAL); 484 } 485 486 /* Stop interface */ 487 bifp->if_flags &= ~IFF_UP; 488 (*bifp->if_ioctl)(bifp, SIOCSIFFLAGS, NULL); 489 490 /* Restore MAC address. */ 491 if_setlladdr(bifp, (u_char *)&p->fec_mac, ETHER_ADDR_LEN); 492 493 /* Restore input vector */ 494 bifp->if_input = p->fec_if_input; 495 496 /* Remove our node context pointer. */ 497 IF_AFDATA_LOCK(bifp); 498 bifp->if_afdata[AF_NETGRAPH] = NULL; 499 IF_AFDATA_UNLOCK(bifp); 500 501 /* Delete port */ 502 TAILQ_REMOVE(&b->ng_fec_ports, p, fec_list); 503 FREE(p, M_NETGRAPH); 504 b->fec_ifcnt--; 505 506 if (b->fec_ifcnt == 0) 507 b->fec_if_output = NULL; 508 509 return(0); 510} 511 512/* 513 * Pass an ioctl command down to all the underyling interfaces in a 514 * bundle. Used for setting multicast filters and flags. 515 */ 516 517static int 518ng_fec_setport(struct ifnet *ifp, u_long command, caddr_t data) 519{ 520 struct ng_fec_private *priv; 521 struct ng_fec_bundle *b; 522 struct ifnet *oifp; 523 struct ng_fec_portlist *p; 524 525 priv = ifp->if_softc; 526 b = &priv->fec_bundle; 527 528 TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) { 529 oifp = p->fec_if; 530 if (oifp != NULL) 531 (*oifp->if_ioctl)(oifp, command, data); 532 } 533 534 return(0); 535} 536 537static void 538ng_fec_init(void *arg) 539{ 540 struct ng_fec_private *priv; 541 struct ng_fec_bundle *b; 542 struct ifnet *ifp, *bifp; 543 struct ng_fec_portlist *p; 544 545 priv = arg; 546 ifp = priv->ifp; 547 b = &priv->fec_bundle; 548 549 if (b->fec_ifcnt != 2 && b->fec_ifcnt != FEC_BUNDLESIZ) { 550 printf("fec%d: invalid bundle " 551 "size: %d\n", priv->unit, 552 b->fec_ifcnt); 553 return; 554 } 555 556 ng_fec_stop(ifp); 557 558 TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) { 559 bifp = p->fec_if; 560 bifp->if_flags |= IFF_UP; 561 (*bifp->if_ioctl)(bifp, SIOCSIFFLAGS, NULL); 562 /* mark iface as up and let the monitor check it */ 563 p->fec_ifstat = -1; 564 } 565 566 ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE); 567 ifp->if_drv_flags |= IFF_DRV_RUNNING; 568 569 priv->fec_ch = timeout(ng_fec_tick, priv, hz); 570 571 return; 572} 573 574static void 575ng_fec_stop(struct ifnet *ifp) 576{ 577 struct ng_fec_private *priv; 578 struct ng_fec_bundle *b; 579 struct ifnet *bifp; 580 struct ng_fec_portlist *p; 581 582 priv = ifp->if_softc; 583 b = &priv->fec_bundle; 584 585 TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) { 586 bifp = p->fec_if; 587 bifp->if_flags &= ~IFF_UP; 588 (*bifp->if_ioctl)(bifp, SIOCSIFFLAGS, NULL); 589 } 590 591 untimeout(ng_fec_tick, priv, priv->fec_ch); 592 593 ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 594 595 return; 596} 597 598static void 599ng_fec_tick(void *arg) 600{ 601 struct ng_fec_private *priv; 602 struct ng_fec_bundle *b; 603 struct ifmediareq ifmr; 604 struct ifnet *ifp; 605 struct ng_fec_portlist *p; 606 int error = 0; 607 608 priv = arg; 609 b = &priv->fec_bundle; 610 611 TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) { 612 bzero((char *)&ifmr, sizeof(ifmr)); 613 ifp = p->fec_if; 614 error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr); 615 if (error) { 616 printf("fec%d: failed to check status " 617 "of link %s\n", priv->unit, ifp->if_xname); 618 continue; 619 } 620 621 if (ifmr.ifm_status & IFM_AVALID) { 622 if (ifmr.ifm_status & IFM_ACTIVE) { 623 if (p->fec_ifstat == -1 || 624 p->fec_ifstat == 0) { 625 p->fec_ifstat = 1; 626 printf("fec%d: port %s in bundle " 627 "is up\n", priv->unit, 628 ifp->if_xname); 629 } 630 } else { 631 if (p->fec_ifstat == -1 || 632 p->fec_ifstat == 1) { 633 p->fec_ifstat = 0; 634 printf("fec%d: port %s in bundle " 635 "is down\n", priv->unit, 636 ifp->if_xname); 637 } 638 } 639 } 640 } 641 642 ifp = priv->ifp; 643 if (ifp->if_drv_flags & IFF_DRV_RUNNING) 644 priv->fec_ch = timeout(ng_fec_tick, priv, hz); 645 646 return; 647} 648 649static int 650ng_fec_ifmedia_upd(struct ifnet *ifp) 651{ 652 return(0); 653} 654 655static void ng_fec_ifmedia_sts(struct ifnet *ifp, 656 struct ifmediareq *ifmr) 657{ 658 struct ng_fec_private *priv; 659 struct ng_fec_bundle *b; 660 struct ng_fec_portlist *p; 661 662 priv = ifp->if_softc; 663 b = &priv->fec_bundle; 664 665 ifmr->ifm_status = IFM_AVALID; 666 TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) { 667 if (p->fec_ifstat == 1) { 668 ifmr->ifm_status |= IFM_ACTIVE; 669 break; 670 } 671 } 672 673 return; 674} 675 676/* 677 * Process an ioctl for the virtual interface 678 */ 679static int 680ng_fec_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 681{ 682 struct ifreq *const ifr = (struct ifreq *) data; 683 int s, error = 0; 684 struct ng_fec_private *priv; 685 struct ng_fec_bundle *b; 686 687 priv = ifp->if_softc; 688 b = &priv->fec_bundle; 689 690#ifdef DEBUG 691 ng_fec_print_ioctl(ifp, command, data); 692#endif 693 s = splimp(); 694 switch (command) { 695 696 /* These two are mostly handled at a higher layer */ 697 case SIOCSIFADDR: 698 case SIOCGIFADDR: 699 case SIOCSIFMTU: 700 error = ether_ioctl(ifp, command, data); 701 break; 702 703 /* Set flags */ 704 case SIOCSIFFLAGS: 705 /* 706 * If the interface is marked up and stopped, then start it. 707 * If it is marked down and running, then stop it. 708 */ 709 if (ifr->ifr_flags & IFF_UP) { 710 if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 711 /* Sanity. */ 712 if (b->fec_ifcnt != 2 && 713 b->fec_ifcnt != FEC_BUNDLESIZ) { 714 printf("fec%d: invalid bundle " 715 "size: %d\n", priv->unit, 716 b->fec_ifcnt); 717 error = EINVAL; 718 break; 719 } 720 ng_fec_init(priv); 721 } 722 /* 723 * Bubble down changes in promisc mode to 724 * underlying interfaces. 725 */ 726 if ((ifp->if_flags & IFF_PROMISC) != 727 (priv->if_flags & IFF_PROMISC)) { 728 ng_fec_setport(ifp, command, data); 729 priv->if_flags = ifp->if_flags; 730 } 731 } else { 732 if (ifp->if_drv_flags & IFF_DRV_RUNNING) 733 ng_fec_stop(ifp); 734 } 735 break; 736 737 case SIOCADDMULTI: 738 case SIOCDELMULTI: 739 ng_fec_setport(ifp, command, data); 740 error = 0; 741 break; 742 case SIOCGIFMEDIA: 743 case SIOCSIFMEDIA: 744 error = ifmedia_ioctl(ifp, ifr, &priv->ifmedia, command); 745 break; 746 /* Stuff that's not supported */ 747 case SIOCSIFPHYS: 748 error = EOPNOTSUPP; 749 break; 750 751 default: 752 error = EINVAL; 753 break; 754 } 755 (void) splx(s); 756 return (error); 757} 758 759/* 760 * This routine spies on mbufs received by underlying network device 761 * drivers. When we add an interface to our bundle, we override its 762 * if_input routine with a pointer to ng_fec_input(). This means we 763 * get to look at all the device's packets before sending them to the 764 * real ether_input() for processing by the stack. Once we verify the 765 * packet comes from an interface that's been aggregated into 766 * our bundle, we fix up the rcvif pointer and increment our 767 * packet counters so that it looks like the frames are actually 768 * coming from us. 769 */ 770static void 771ng_fec_input(struct ifnet *ifp, struct mbuf *m0) 772{ 773 struct ng_node *node; 774 struct ng_fec_private *priv; 775 struct ng_fec_bundle *b; 776 struct ifnet *bifp; 777 struct ng_fec_portlist *p; 778 779 /* Sanity check */ 780 if (ifp == NULL || m0 == NULL) 781 return; 782 783 node = IFP2NG(ifp); 784 785 /* Sanity check part II */ 786 if (node == NULL) 787 return; 788 789 priv = NG_NODE_PRIVATE(node); 790 b = &priv->fec_bundle; 791 bifp = priv->ifp; 792 793 TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) { 794 if (p->fec_if == m0->m_pkthdr.rcvif) 795 break; 796 } 797 798 /* Wasn't meant for us; leave this frame alone. */ 799 if (p == NULL) 800 return; 801 802 /* 803 * Check for a BPF tap on the underlying interface. This 804 * is mainly a debugging aid: it allows tcpdump-ing of an 805 * individual interface in a bundle to work, which it 806 * otherwise would not. BPF tapping of our own aggregate 807 * interface will occur once we call ether_input(). 808 */ 809 BPF_MTAP(m0->m_pkthdr.rcvif, m0); 810 811 /* Convince the system that this is our frame. */ 812 m0->m_pkthdr.rcvif = bifp; 813 bifp->if_ipackets++; 814 bifp->if_ibytes += m0->m_pkthdr.len + sizeof(struct ether_header); 815 816 (*bifp->if_input)(bifp, m0); 817 818 return; 819} 820 821/* 822 * Take a quick peek at the packet and see if it's ok for us to use 823 * the inet or inet6 hash methods on it, if they're enabled. We do 824 * this by setting flags in the mbuf header. Once we've made up our 825 * mind what to do, we pass the frame to output vector for further 826 * processing. 827 */ 828 829static int 830ng_fec_output(struct ifnet *ifp, struct mbuf *m, 831 struct sockaddr *dst, struct rtentry *rt0) 832{ 833 const priv_p priv = (priv_p) ifp->if_softc; 834 struct ng_fec_bundle *b; 835 int error; 836 837 /* Check interface flags */ 838 if (!((ifp->if_flags & IFF_UP) && 839 (ifp->if_drv_flags & IFF_DRV_RUNNING))) { 840 m_freem(m); 841 return (ENETDOWN); 842 } 843 844 b = &priv->fec_bundle; 845 846 switch (b->fec_btype) { 847 case FEC_BTYPE_MAC: 848 m->m_flags |= M_FEC_MAC; 849 break; 850#ifdef INET 851 case FEC_BTYPE_INET: 852 /* 853 * We can't use the INET address port selection 854 * scheme if this isn't an INET packet. 855 */ 856 if (dst->sa_family == AF_INET) 857 m->m_flags |= M_FEC_INET; 858#ifdef INET6 859 else if (dst->sa_family == AF_INET6) 860 m->m_flags |= M_FEC_INET6; 861#endif 862 else { 863#ifdef DEBUG 864 if_printf(ifp, "can't do inet aggregation of non " 865 "inet packet\n"); 866#endif 867 m->m_flags |= M_FEC_MAC; 868 } 869 break; 870#endif 871 default: 872 if_printf(ifp, "bogus hash type: %d\n", 873 b->fec_btype); 874 m_freem(m); 875 return(EINVAL); 876 break; 877 } 878 879 /* 880 * Pass the frame to the output vector for all the protocol 881 * handling. This will put the ethernet header on the packet 882 * for us. 883 */ 884 priv->if_error = 0; 885 error = (*b->fec_if_output)(ifp, m, dst, rt0); 886 if (priv->if_error && !error) 887 error = priv->if_error; 888 889 return(error); 890} 891 892/* 893 * Apply a hash to the source and destination addresses in the packet 894 * in order to select an interface. Also check link status and handle 895 * dead links accordingly. 896 */ 897 898static int 899ng_fec_choose_port(struct ng_fec_bundle *b, 900 struct mbuf *m, struct ifnet **ifp) 901{ 902 struct ether_header *eh; 903 struct mbuf *m0; 904#ifdef INET 905 struct ip *ip; 906#ifdef INET6 907 struct ip6_hdr *ip6; 908#endif 909#endif 910 911 struct ng_fec_portlist *p; 912 int port = 0, mask; 913 914 /* 915 * If there are only two ports, mask off all but the 916 * last bit for XORing. If there are 4, mask off all 917 * but the last 2 bits. 918 */ 919 mask = b->fec_ifcnt == 2 ? 0x1 : 0x3; 920 eh = mtod(m, struct ether_header *); 921#ifdef INET 922 ip = (struct ip *)(mtod(m, char *) + 923 sizeof(struct ether_header)); 924#ifdef INET6 925 ip6 = (struct ip6_hdr *)(mtod(m, char *) + 926 sizeof(struct ether_header)); 927#endif 928#endif 929 930 /* 931 * The fg_fec_output() routine is supposed to leave a 932 * flag for us in the mbuf that tells us what hash to 933 * use, but sometimes a new mbuf is prepended to the 934 * chain, so we have to search every mbuf in the chain 935 * to find the flags. 936 */ 937 m0 = m; 938 while (m0) { 939 if (m0->m_flags & (M_FEC_MAC|M_FEC_INET|M_FEC_INET6)) 940 break; 941 m0 = m0->m_next; 942 } 943 if (m0 == NULL) 944 return(EINVAL); 945 946 switch (m0->m_flags & (M_FEC_MAC|M_FEC_INET|M_FEC_INET6)) { 947 case M_FEC_MAC: 948 port = (eh->ether_dhost[5] ^ 949 eh->ether_shost[5]) & mask; 950 break; 951#ifdef INET 952 case M_FEC_INET: 953 port = (ntohl(ip->ip_dst.s_addr) ^ 954 ntohl(ip->ip_src.s_addr)) & mask; 955 break; 956#ifdef INET6 957 case M_FEC_INET6: 958 port = (ip6->ip6_dst.s6_addr[15] ^ 959 ip6->ip6_dst.s6_addr[15]) & mask; 960 break; 961#endif 962#endif 963 default: 964 return(EINVAL); 965 break; 966 } 967 968 TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) { 969 if (port == p->fec_idx) 970 break; 971 } 972 973 /* 974 * Now that we've chosen a port, make sure it's 975 * alive. If it's not alive, cycle through the bundle 976 * looking for a port that is alive. If we don't find 977 * any, return an error. 978 */ 979 if (p->fec_ifstat != 1) { 980 struct ng_fec_portlist *n = NULL; 981 982 n = TAILQ_NEXT(p, fec_list); 983 if (n == NULL) 984 n = TAILQ_FIRST(&b->ng_fec_ports); 985 while (n != p) { 986 if (n->fec_ifstat == 1) 987 break; 988 n = TAILQ_NEXT(n, fec_list); 989 if (n == NULL) 990 n = TAILQ_FIRST(&b->ng_fec_ports); 991 } 992 if (n == p) 993 return(EAGAIN); 994 p = n; 995 } 996 997 *ifp = p->fec_if; 998 999 return(0); 1000} 1001 1002/* 1003 * Now that the packet has been run through ether_output(), yank it 1004 * off our own send queue and stick it on the queue for the appropriate 1005 * underlying physical interface. Note that if the interface's send 1006 * queue is full, we save an error status in our private netgraph 1007 * space which will eventually be handed up to ng_fec_output(), which 1008 * will return it to the rest of the IP stack. We need to do this 1009 * in order to duplicate the effect of ether_output() returning ENOBUFS 1010 * when it detects that an interface's send queue is full. There's no 1011 * other way to signal the error status from here since the if_start() 1012 * routine is spec'ed to return void. 1013 * 1014 * Once the frame is queued, we call ether_output_frame() to initiate 1015 * transmission. 1016 */ 1017static void 1018ng_fec_start(struct ifnet *ifp) 1019{ 1020 struct ng_fec_private *priv; 1021 struct ng_fec_bundle *b; 1022 struct ifnet *oifp = NULL; 1023 struct mbuf *m0; 1024 int error; 1025 1026 priv = ifp->if_softc; 1027 b = &priv->fec_bundle; 1028 1029 IF_DEQUEUE(&ifp->if_snd, m0); 1030 if (m0 == NULL) 1031 return; 1032 1033 BPF_MTAP(ifp, m0); 1034 1035 /* Queue up packet on the proper port. */ 1036 error = ng_fec_choose_port(b, m0, &oifp); 1037 if (error) { 1038 ifp->if_ierrors++; 1039 m_freem(m0); 1040 priv->if_error = ENOBUFS; 1041 return; 1042 } 1043 ifp->if_opackets++; 1044 1045 priv->if_error = IF_HANDOFF(&oifp->if_snd, m0, oifp) ? 0 : ENOBUFS; 1046 1047 return; 1048} 1049 1050#ifdef DEBUG 1051/* 1052 * Display an ioctl to the virtual interface 1053 */ 1054 1055static void 1056ng_fec_print_ioctl(struct ifnet *ifp, int command, caddr_t data) 1057{ 1058 char *str; 1059 1060 switch (command & IOC_DIRMASK) { 1061 case IOC_VOID: 1062 str = "IO"; 1063 break; 1064 case IOC_OUT: 1065 str = "IOR"; 1066 break; 1067 case IOC_IN: 1068 str = "IOW"; 1069 break; 1070 case IOC_INOUT: 1071 str = "IORW"; 1072 break; 1073 default: 1074 str = "IO??"; 1075 } 1076 log(LOG_DEBUG, "%s: %s('%c', %d, char[%d])\n", 1077 ifp->if_xname, 1078 str, 1079 IOCGROUP(command), 1080 command & 0xff, 1081 IOCPARM_LEN(command)); 1082} 1083#endif /* DEBUG */ 1084 1085/************************************************************************ 1086 NETGRAPH NODE STUFF 1087 ************************************************************************/ 1088 1089/* 1090 * Constructor for a node 1091 */ 1092static int 1093ng_fec_constructor(node_p node) 1094{ 1095 char ifname[NG_FEC_FEC_NAME_MAX + 1]; 1096 struct ifnet *ifp; 1097 priv_p priv; 1098 struct ng_fec_bundle *b; 1099 int error = 0; 1100 1101 /* Allocate node and interface private structures */ 1102 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO); 1103 if (priv == NULL) 1104 return (ENOMEM); 1105 1106 ifp = priv->ifp = if_alloc(IFT_ETHER); 1107 if (ifp == NULL) { 1108 FREE(priv, M_NETGRAPH); 1109 return (ENOSPC); 1110 } 1111 b = &priv->fec_bundle; 1112 1113 /* Link them together */ 1114 ifp->if_softc = priv; 1115 1116 /* Get an interface unit number */ 1117 if ((error = ng_fec_get_unit(&priv->unit)) != 0) { 1118 if_free(ifp); 1119 FREE(priv, M_NETGRAPH); 1120 return (error); 1121 } 1122 1123 /* Link together node and private info */ 1124 NG_NODE_SET_PRIVATE(node, priv); 1125 priv->node = node; 1126 1127 /* Initialize interface structure */ 1128 if_initname(ifp, NG_FEC_FEC_NAME, priv->unit); 1129 ifp->if_start = ng_fec_start; 1130 ifp->if_ioctl = ng_fec_ioctl; 1131 ifp->if_init = ng_fec_init; 1132 ifp->if_watchdog = NULL; 1133 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 1134 ifp->if_mtu = NG_FEC_MTU_DEFAULT; 1135 ifp->if_flags = (IFF_SIMPLEX|IFF_BROADCAST|IFF_MULTICAST); 1136 ifp->if_addrlen = 0; /* XXX */ 1137 ifp->if_hdrlen = 0; /* XXX */ 1138 ifp->if_baudrate = 100000000; /* XXX */ 1139 TAILQ_INIT(&ifp->if_addrhead); /* XXX useless - done in if_attach */ 1140 1141 /* Give this node the same name as the interface (if possible) */ 1142 bzero(ifname, sizeof(ifname)); 1143 strlcpy(ifname, ifp->if_xname, sizeof(ifname)); 1144 if (ng_name_node(node, ifname) != 0) 1145 log(LOG_WARNING, "%s: can't acquire netgraph name\n", ifname); 1146 1147 /* Attach the interface */ 1148 ether_ifattach(ifp, IFP2ENADDR(priv->ifp)); 1149 callout_handle_init(&priv->fec_ch); 1150 1151 /* Override output method with our own */ 1152 ifp->if_output = ng_fec_output; 1153 1154 TAILQ_INIT(&b->ng_fec_ports); 1155 b->fec_ifcnt = 0; 1156 1157 ifmedia_init(&priv->ifmedia, 0, 1158 ng_fec_ifmedia_upd, ng_fec_ifmedia_sts); 1159 ifmedia_add(&priv->ifmedia, IFM_ETHER|IFM_NONE, 0, NULL); 1160 ifmedia_set(&priv->ifmedia, IFM_ETHER|IFM_NONE); 1161 1162 /* Done */ 1163 return (0); 1164} 1165 1166/* 1167 * Receive a control message 1168 */ 1169static int 1170ng_fec_rcvmsg(node_p node, item_p item, hook_p lasthook) 1171{ 1172 const priv_p priv = NG_NODE_PRIVATE(node); 1173 struct ng_fec_bundle *b; 1174 struct ng_mesg *resp = NULL; 1175 struct ng_mesg *msg; 1176 char *ifname; 1177 int error = 0; 1178 1179 NGI_GET_MSG(item, msg); 1180 b = &priv->fec_bundle; 1181 1182 switch (msg->header.typecookie) { 1183 case NGM_FEC_COOKIE: 1184 switch (msg->header.cmd) { 1185 case NGM_FEC_ADD_IFACE: 1186 ifname = msg->data; 1187 error = ng_fec_addport(priv, ifname); 1188 break; 1189 case NGM_FEC_DEL_IFACE: 1190 ifname = msg->data; 1191 error = ng_fec_delport(priv, ifname); 1192 break; 1193 case NGM_FEC_SET_MODE_MAC: 1194 b->fec_btype = FEC_BTYPE_MAC; 1195 break; 1196#ifdef INET 1197 case NGM_FEC_SET_MODE_INET: 1198 b->fec_btype = FEC_BTYPE_INET; 1199 break; 1200#ifdef INET6 1201 case NGM_FEC_SET_MODE_INET6: 1202 b->fec_btype = FEC_BTYPE_INET6; 1203 break; 1204#endif 1205#endif 1206 default: 1207 error = EINVAL; 1208 break; 1209 } 1210 break; 1211 default: 1212 error = EINVAL; 1213 break; 1214 } 1215 NG_RESPOND_MSG(error, node, item, resp); 1216 NG_FREE_MSG(msg); 1217 return (error); 1218} 1219 1220/* 1221 * Shutdown and remove the node and its associated interface. 1222 */ 1223static int 1224ng_fec_shutdown(node_p node) 1225{ 1226 const priv_p priv = NG_NODE_PRIVATE(node); 1227 struct ng_fec_bundle *b; 1228 struct ng_fec_portlist *p; 1229 1230 b = &priv->fec_bundle; 1231 ng_fec_stop(priv->ifp); 1232 1233 while (!TAILQ_EMPTY(&b->ng_fec_ports)) { 1234 p = TAILQ_FIRST(&b->ng_fec_ports); 1235 ng_fec_delport(priv, p->fec_if->if_xname); 1236 } 1237 1238 ether_ifdetach(priv->ifp); 1239 if_free_type(priv->ifp, IFT_ETHER); 1240 ifmedia_removeall(&priv->ifmedia); 1241 ng_fec_free_unit(priv->unit); 1242 FREE(priv, M_NETGRAPH); 1243 NG_NODE_SET_PRIVATE(node, NULL); 1244 NG_NODE_UNREF(node); 1245 return (0); 1246} 1247 1248/* 1249 * Handle loading and unloading for this node type. 1250 */ 1251static int 1252ng_fec_mod_event(module_t mod, int event, void *data) 1253{ 1254 int error = 0; 1255 1256 switch (event) { 1257 case MOD_LOAD: 1258 mtx_init(&ng_fec_mtx, "ng_fec", NULL, MTX_DEF); 1259 break; 1260 case MOD_UNLOAD: 1261 mtx_destroy(&ng_fec_mtx); 1262 break; 1263 default: 1264 error = EOPNOTSUPP; 1265 break; 1266 } 1267 return (error); 1268} 1269