4 * Copyright (c) 2001 Berkeley Software Design, Inc.
5 * Copyright (c) 2000, 2001
6 * Bill Paul <wpaul@osd.bsdi.com>. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Bill Paul.
19 * 4. Neither the name of the author nor the names of any co-contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33 * THE POSSIBILITY OF SUCH DAMAGE.
35 * $FreeBSD: src/sys/netgraph/ng_fec.c,v 1.1.2.1 2002/11/01 21:39:31 julian Exp $
36 * $DragonFly: src/sys/netgraph/fec/ng_fec.c,v 1.26 2008/05/28 12:11:13 sephe Exp $
39 * Copyright (c) 1996-1999 Whistle Communications, Inc.
40 * All rights reserved.
42 * Subject to the following obligations and disclaimer of warranty, use and
43 * redistribution of this software, in source or object code forms, with or
44 * without modifications are expressly permitted by Whistle Communications;
45 * provided, however, that:
46 * 1. Any and all reproductions of the source or object code must include the
47 * copyright notice above and the following disclaimer of warranties; and
48 * 2. No rights are granted, in any manner or form, to use Whistle
49 * Communications, Inc. trademarks, including the mark "WHISTLE
50 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
51 * such appears in the above copyright notice or in the software.
53 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
54 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
55 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
56 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
57 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
58 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
59 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
60 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
61 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
62 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
63 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
64 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
65 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
66 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
67 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
68 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
71 * Author: Archie Cobbs <archie@freebsd.org>
73 * $Whistle: ng_fec.c,v 1.33 1999/11/01 09:24:51 julian Exp $
77 * This module implements ethernet channel bonding using the Cisco
78 * Fast EtherChannel mechanism. Two or four ports may be combined
79 * into a single aggregate interface.
81 * Interfaces are named fec0, fec1, etc. New nodes take the
82 * first available interface name.
84 * This node also includes Berkeley packet filter support.
86 * Note that this node doesn't need to connect to any other
87 * netgraph nodes in order to do its work.
90 #include <sys/param.h>
91 #include <sys/systm.h>
92 #include <sys/errno.h>
93 #include <sys/kernel.h>
94 #include <sys/malloc.h>
96 #include <sys/errno.h>
97 #include <sys/sockio.h>
98 #include <sys/socket.h>
99 #include <sys/syslog.h>
100 #include <sys/libkern.h>
101 #include <sys/queue.h>
102 #include <sys/thread2.h>
105 #include <net/if_types.h>
106 #include <net/if_arp.h>
107 #include <net/if_dl.h>
108 #include <net/if_media.h>
110 #include <net/ethernet.h>
112 #include "opt_inet.h"
113 #include "opt_inet6.h"
115 #include <netinet/in.h>
117 #include <netinet/in_systm.h>
118 #include <netinet/ip.h>
122 #include <netinet/ip6.h>
125 #include <netgraph/ng_message.h>
126 #include <netgraph/netgraph.h>
127 #include <netgraph/ng_parse.h>
130 #define IFP2NG(ifp) ((struct ng_node *)((struct arpcom *)(ifp))->ac_netgraph)
131 #define FEC_INC(x, y) (x) = (x + 1) % y
134 * Current fast etherchannel implementations use either 2 or 4
135 * ports, so for now we limit the maximum bundle size to 4 interfaces.
137 #define FEC_BUNDLESIZ 4
139 struct ng_fec_portlist
{
140 struct ifnet
*fec_if
;
143 struct ether_addr fec_mac
;
144 TAILQ_ENTRY(ng_fec_portlist
) fec_list
;
147 struct ng_fec_bundle
{
148 TAILQ_HEAD(,ng_fec_portlist
) ng_fec_ports
;
153 #define FEC_BTYPE_MAC 0x01
154 #define FEC_BTYPE_INET 0x02
155 #define FEC_BTYPE_INET6 0x03
157 /* Node private data */
158 struct ng_fec_private
{
159 struct arpcom arpcom
;
160 struct ifmedia ifmedia
;
162 int if_error
; /* XXX */
163 int unit
; /* Interface unit number */
164 node_p node
; /* Our netgraph node */
165 struct ng_fec_bundle fec_bundle
;/* Aggregate bundle */
166 struct callout fec_timeout
; /* callout for ticker */
167 int (*real_if_output
)(struct ifnet
*, struct mbuf
*,
168 struct sockaddr
*, struct rtentry
*);
170 typedef struct ng_fec_private
*priv_p
;
172 /* Interface methods */
173 static void ng_fec_input(struct ifnet
*, struct mbuf
**);
174 static void ng_fec_start(struct ifnet
*ifp
);
175 static int ng_fec_choose_port(struct ng_fec_bundle
*b
,
176 struct mbuf
*m
, struct ifnet
**ifp
);
177 static int ng_fec_setport(struct ifnet
*ifp
, u_long cmd
, caddr_t data
);
178 static void ng_fec_init(void *arg
);
179 static void ng_fec_stop(struct ifnet
*ifp
);
180 static int ng_fec_ifmedia_upd(struct ifnet
*ifp
);
181 static void ng_fec_ifmedia_sts(struct ifnet
*ifp
, struct ifmediareq
*ifmr
);
182 static int ng_fec_ioctl(struct ifnet
*ifp
, u_long cmd
, caddr_t data
,
184 static int ng_fec_output(struct ifnet
*ifp
, struct mbuf
*m0
,
185 struct sockaddr
*dst
, struct rtentry
*rt0
);
186 static void ng_fec_tick(void *arg
);
187 static int ng_fec_addport(struct ng_fec_private
*priv
, char *iface
);
188 static int ng_fec_delport(struct ng_fec_private
*priv
, char *iface
);
191 static void ng_fec_print_ioctl(struct ifnet
*ifp
, int cmd
, caddr_t data
);
194 /* Netgraph methods */
195 static ng_constructor_t ng_fec_constructor
;
196 static ng_rcvmsg_t ng_fec_rcvmsg
;
197 static ng_shutdown_t ng_fec_rmnode
;
199 /* List of commands and how to convert arguments to/from ASCII */
200 static const struct ng_cmdlist ng_fec_cmds
[] = {
205 &ng_parse_string_type
,
212 &ng_parse_string_type
,
217 NGM_FEC_SET_MODE_MAC
,
224 NGM_FEC_SET_MODE_INET
,
232 /* Node type descriptor */
233 static struct ng_type typestruct
= {
248 NETGRAPH_INIT(fec
, &typestruct
);
250 /* We keep a bitmap indicating which unit numbers are free.
251 One means the unit number is free, zero means it's taken. */
252 static int *ng_fec_units
= NULL
;
253 static int ng_fec_units_len
= 0;
254 static int ng_units_in_use
= 0;
256 #define UNITS_BITSPERWORD (sizeof(*ng_fec_units) * NBBY)
259 * Find the first free unit number for a new interface.
260 * Increase the size of the unit bitmap as necessary.
262 static __inline__
int
263 ng_fec_get_unit(int *unit
)
267 for (index
= 0; index
< ng_fec_units_len
268 && ng_fec_units
[index
] == 0; index
++);
269 if (index
== ng_fec_units_len
) { /* extend array */
270 int i
, *newarray
, newlen
;
272 newlen
= (2 * ng_fec_units_len
) + 4;
273 MALLOC(newarray
, int *, newlen
* sizeof(*ng_fec_units
),
274 M_NETGRAPH
, M_NOWAIT
);
275 if (newarray
== NULL
)
277 bcopy(ng_fec_units
, newarray
,
278 ng_fec_units_len
* sizeof(*ng_fec_units
));
279 for (i
= ng_fec_units_len
; i
< newlen
; i
++)
281 if (ng_fec_units
!= NULL
)
282 FREE(ng_fec_units
, M_NETGRAPH
);
283 ng_fec_units
= newarray
;
284 ng_fec_units_len
= newlen
;
286 bit
= ffs(ng_fec_units
[index
]) - 1;
287 KASSERT(bit
>= 0 && bit
<= UNITS_BITSPERWORD
- 1,
288 ("%s: word=%d bit=%d", __func__
, ng_fec_units
[index
], bit
));
289 ng_fec_units
[index
] &= ~(1 << bit
);
290 *unit
= (index
* UNITS_BITSPERWORD
) + bit
;
296 * Free a no longer needed unit number.
298 static __inline__
void
299 ng_fec_free_unit(int unit
)
303 index
= unit
/ UNITS_BITSPERWORD
;
304 bit
= unit
% UNITS_BITSPERWORD
;
305 KASSERT(index
< ng_fec_units_len
,
306 ("%s: unit=%d len=%d", __func__
, unit
, ng_fec_units_len
));
307 KASSERT((ng_fec_units
[index
] & (1 << bit
)) == 0,
308 ("%s: unit=%d is free", __func__
, unit
));
309 ng_fec_units
[index
] |= (1 << bit
);
311 * XXX We could think about reducing the size of ng_fec_units[]
312 * XXX here if the last portion is all ones
313 * XXX At least free it if no more units.
314 * Needed if we are eventually be able to unload.
317 if (ng_units_in_use
== 0) { /* XXX make SMP safe */
318 FREE(ng_fec_units
, M_NETGRAPH
);
319 ng_fec_units_len
= 0;
324 /************************************************************************
326 ************************************************************************/
329 ng_fec_addport(struct ng_fec_private
*priv
, char *iface
)
331 struct ng_fec_bundle
*b
;
332 struct ifnet
*ifp
, *bifp
;
334 struct sockaddr_dl
*sdl
;
335 struct ng_fec_portlist
*p
, *new;
337 if (priv
== NULL
|| iface
== NULL
)
340 b
= &priv
->fec_bundle
;
341 ifp
= &priv
->arpcom
.ac_if
;
343 /* Find the interface */
344 bifp
= ifunit(iface
);
346 kprintf("fec%d: tried to add iface %s, which "
347 "doesn't seem to exist\n", priv
->unit
, iface
);
351 /* See if we have room in the bundle */
352 if (b
->fec_ifcnt
== FEC_BUNDLESIZ
) {
353 kprintf("fec%d: can't add new iface; bundle is full\n",
358 /* See if the interface is already in the bundle */
359 TAILQ_FOREACH(p
, &b
->ng_fec_ports
, fec_list
) {
360 if (p
->fec_if
== bifp
) {
361 kprintf("fec%d: iface %s is already in this "
362 "bundle\n", priv
->unit
, iface
);
367 /* Allocate new list entry. */
368 MALLOC(new, struct ng_fec_portlist
*,
369 sizeof(struct ng_fec_portlist
), M_NETGRAPH
, M_NOWAIT
);
373 ac
= (struct arpcom
*)bifp
;
374 ac
->ac_netgraph
= priv
->node
;
377 * If this is the first interface added to the bundle,
378 * use its MAC address for the virtual interface (and,
379 * by extension, all the other ports in the bundle).
381 if (b
->fec_ifcnt
== 0) {
382 sdl
= IF_LLSOCKADDR(ifp
);
383 bcopy((char *)ac
->ac_enaddr
,
384 priv
->arpcom
.ac_enaddr
, ETHER_ADDR_LEN
);
385 bcopy((char *)ac
->ac_enaddr
,
386 LLADDR(sdl
), ETHER_ADDR_LEN
);
389 b
->fec_btype
= FEC_BTYPE_MAC
;
390 new->fec_idx
= b
->fec_ifcnt
;
393 /* Save the real MAC address. */
394 bcopy((char *)ac
->ac_enaddr
,
395 (char *)&new->fec_mac
, ETHER_ADDR_LEN
);
397 /* Set up phony MAC address. */
398 sdl
= IF_LLSOCKADDR(bifp
);
399 bcopy(priv
->arpcom
.ac_enaddr
, ac
->ac_enaddr
, ETHER_ADDR_LEN
);
400 bcopy(priv
->arpcom
.ac_enaddr
, LLADDR(sdl
), ETHER_ADDR_LEN
);
402 /* Add to the queue */
404 TAILQ_INSERT_TAIL(&b
->ng_fec_ports
, new, fec_list
);
410 ng_fec_delport(struct ng_fec_private
*priv
, char *iface
)
412 struct ng_fec_bundle
*b
;
413 struct ifnet
*ifp
, *bifp
;
415 struct sockaddr_dl
*sdl
;
416 struct ng_fec_portlist
*p
;
418 if (priv
== NULL
|| iface
== NULL
)
421 b
= &priv
->fec_bundle
;
422 ifp
= &priv
->arpcom
.ac_if
;
424 /* Find the interface */
425 bifp
= ifunit(iface
);
427 kprintf("fec%d: tried to remove iface %s, which "
428 "doesn't seem to exist\n", priv
->unit
, iface
);
432 TAILQ_FOREACH(p
, &b
->ng_fec_ports
, fec_list
) {
433 if (p
->fec_if
== bifp
)
438 kprintf("fec%d: tried to remove iface %s which "
439 "is not in our bundle\n", priv
->unit
, iface
);
444 bifp
->if_flags
&= ~IFF_UP
;
445 bifp
->if_ioctl(bifp
, SIOCSIFFLAGS
, NULL
, NULL
);
447 /* Restore MAC address. */
448 ac
= (struct arpcom
*)bifp
;
449 sdl
= IF_LLSOCKADDR(bifp
);
450 bcopy((char *)&p
->fec_mac
, ac
->ac_enaddr
, ETHER_ADDR_LEN
);
451 bcopy((char *)&p
->fec_mac
, LLADDR(sdl
), ETHER_ADDR_LEN
);
454 TAILQ_REMOVE(&b
->ng_fec_ports
, p
, fec_list
);
462 * Pass an ioctl command down to all the underyling interfaces in a
463 * bundle. Used for setting multicast filters and flags.
466 ng_fec_setport(struct ifnet
*ifp
, u_long command
, caddr_t data
)
468 struct ng_fec_private
*priv
;
469 struct ng_fec_bundle
*b
;
471 struct ng_fec_portlist
*p
;
473 priv
= ifp
->if_softc
;
474 b
= &priv
->fec_bundle
;
476 lwkt_serialize_exit(ifp
->if_serializer
); /* XXX */
477 TAILQ_FOREACH(p
, &b
->ng_fec_ports
, fec_list
) {
480 lwkt_serialize_enter(oifp
->if_serializer
);
481 oifp
->if_ioctl(oifp
, command
, data
, NULL
);
482 lwkt_serialize_exit(oifp
->if_serializer
);
485 lwkt_serialize_enter(ifp
->if_serializer
);
491 ng_fec_init(void *arg
)
493 struct ng_fec_private
*priv
;
494 struct ng_fec_bundle
*b
;
495 struct ifnet
*ifp
, *bifp
;
496 struct ng_fec_portlist
*p
;
499 priv
= ifp
->if_softc
;
500 b
= &priv
->fec_bundle
;
502 if (b
->fec_ifcnt
== 1 || b
->fec_ifcnt
== 3) {
503 kprintf("fec%d: invalid bundle "
504 "size: %d\n", priv
->unit
,
511 lwkt_serialize_exit(ifp
->if_serializer
); /* XXX */
512 TAILQ_FOREACH(p
, &b
->ng_fec_ports
, fec_list
) {
514 lwkt_serialize_enter(bifp
->if_serializer
);
515 bifp
->if_flags
|= IFF_UP
;
516 bifp
->if_ioctl(bifp
, SIOCSIFFLAGS
, NULL
, NULL
);
517 /* mark iface as up and let the monitor check it */
519 lwkt_serialize_exit(bifp
->if_serializer
);
521 lwkt_serialize_enter(ifp
->if_serializer
);
523 callout_reset(&priv
->fec_timeout
, hz
, ng_fec_tick
, priv
);
527 ng_fec_stop(struct ifnet
*ifp
)
529 struct ng_fec_private
*priv
;
530 struct ng_fec_bundle
*b
;
532 struct ng_fec_portlist
*p
;
534 priv
= ifp
->if_softc
;
535 b
= &priv
->fec_bundle
;
537 lwkt_serialize_exit(ifp
->if_serializer
); /* XXX */
538 TAILQ_FOREACH(p
, &b
->ng_fec_ports
, fec_list
) {
540 lwkt_serialize_enter(bifp
->if_serializer
);
541 bifp
->if_flags
&= ~IFF_UP
;
542 bifp
->if_ioctl(bifp
, SIOCSIFFLAGS
, NULL
, NULL
);
543 lwkt_serialize_exit(bifp
->if_serializer
);
545 callout_stop(&priv
->fec_timeout
);
546 lwkt_serialize_enter(ifp
->if_serializer
); /* XXX */
550 ng_fec_tick(void *arg
)
552 struct ng_fec_private
*priv
;
553 struct ng_fec_bundle
*b
;
554 struct ifmediareq ifmr
;
556 struct ng_fec_portlist
*p
;
560 b
= &priv
->fec_bundle
;
563 * Note: serializer for parent interface not held on entry, and
564 * cannot be held during the loop to avoid a deadlock.
566 TAILQ_FOREACH(p
, &b
->ng_fec_ports
, fec_list
) {
567 bzero((char *)&ifmr
, sizeof(ifmr
));
569 lwkt_serialize_enter(ifp
->if_serializer
);
570 error
= ifp
->if_ioctl(ifp
, SIOCGIFMEDIA
, (caddr_t
)&ifmr
, NULL
);
572 kprintf("fec%d: failed to check status "
573 "of link %s\n", priv
->unit
, ifp
->if_xname
);
574 lwkt_serialize_exit(ifp
->if_serializer
);
578 if (ifmr
.ifm_status
& IFM_AVALID
&&
579 IFM_TYPE(ifmr
.ifm_active
) == IFM_ETHER
) {
580 if (ifmr
.ifm_status
& IFM_ACTIVE
) {
581 if (p
->fec_ifstat
== -1 ||
582 p
->fec_ifstat
== 0) {
584 kprintf("fec%d: port %s in bundle "
585 "is up\n", priv
->unit
,
589 if (p
->fec_ifstat
== -1 ||
590 p
->fec_ifstat
== 1) {
592 kprintf("fec%d: port %s in bundle "
593 "is down\n", priv
->unit
,
598 lwkt_serialize_exit(ifp
->if_serializer
);
601 ifp
= &priv
->arpcom
.ac_if
;
602 if (ifp
->if_flags
& IFF_RUNNING
)
603 callout_reset(&priv
->fec_timeout
, hz
, ng_fec_tick
, priv
);
607 ng_fec_ifmedia_upd(struct ifnet
*ifp
)
613 ng_fec_ifmedia_sts(struct ifnet
*ifp
, struct ifmediareq
*ifmr
)
615 struct ng_fec_private
*priv
;
616 struct ng_fec_bundle
*b
;
617 struct ng_fec_portlist
*p
;
619 priv
= ifp
->if_softc
;
620 b
= &priv
->fec_bundle
;
622 ifmr
->ifm_status
= IFM_AVALID
;
623 TAILQ_FOREACH(p
, &b
->ng_fec_ports
, fec_list
) {
625 ifmr
->ifm_status
|= IFM_ACTIVE
;
632 * Process an ioctl for the virtual interface
635 ng_fec_ioctl(struct ifnet
*ifp
, u_long command
, caddr_t data
, struct ucred
*cr
)
637 struct ifreq
*const ifr
= (struct ifreq
*) data
;
639 struct ng_fec_private
*priv
;
640 struct ng_fec_bundle
*b
;
642 priv
= ifp
->if_softc
;
643 b
= &priv
->fec_bundle
;
646 ng_fec_print_ioctl(ifp
, command
, data
);
651 /* These two are mostly handled at a higher layer */
655 error
= ether_ioctl(ifp
, command
, data
);
661 * If the interface is marked up and stopped, then start it.
662 * If it is marked down and running, then stop it.
664 if (ifr
->ifr_flags
& IFF_UP
) {
665 if (!(ifp
->if_flags
& IFF_RUNNING
)) {
667 if (b
->fec_ifcnt
== 1 || b
->fec_ifcnt
== 3) {
668 kprintf("fec%d: invalid bundle "
669 "size: %d\n", priv
->unit
,
674 ifp
->if_flags
&= ~(IFF_OACTIVE
);
675 ifp
->if_flags
|= IFF_RUNNING
;
679 * Bubble down changes in promisc mode to
680 * underlying interfaces.
682 if ((ifp
->if_flags
& IFF_PROMISC
) !=
683 (priv
->if_flags
& IFF_PROMISC
)) {
684 ng_fec_setport(ifp
, command
, data
);
685 priv
->if_flags
= ifp
->if_flags
;
688 if (ifp
->if_flags
& IFF_RUNNING
)
689 ifp
->if_flags
&= ~(IFF_RUNNING
| IFF_OACTIVE
);
696 ng_fec_setport(ifp
, command
, data
);
701 error
= ifmedia_ioctl(ifp
, ifr
, &priv
->ifmedia
, command
);
703 /* Stuff that's not supported */
717 * This routine spies on mbufs passing through ether_input(). If
718 * they come from one of the interfaces that are aggregated into
719 * our bundle, we fix up the ifnet pointer and increment our
720 * packet counters so that it looks like the frames are actually
724 ng_fec_input(struct ifnet
*ifp
, struct mbuf
**m0
)
726 struct ng_node
*node
;
727 struct ng_fec_private
*priv
;
728 struct ng_fec_bundle
*b
;
731 struct ng_fec_portlist
*p
;
734 if (ifp
== NULL
|| m0
== NULL
)
739 /* Sanity check part II */
743 priv
= node
->private;
744 b
= &priv
->fec_bundle
;
745 bifp
= &priv
->arpcom
.ac_if
;
748 TAILQ_FOREACH(p
, &b
->ng_fec_ports
, fec_list
) {
749 if (p
->fec_if
== m
->m_pkthdr
.rcvif
)
753 /* Wasn't meant for us; leave this frame alone. */
757 /* Pretend this is our frame. */
758 m
->m_pkthdr
.rcvif
= bifp
;
760 bifp
->if_ibytes
+= m
->m_pkthdr
.len
;
763 bpf_mtap(bifp
->if_bpf
, m
);
767 * Take a quick peek at the packet and see if it's ok for us to use
768 * the inet or inet6 hash methods on it, if they're enabled. We do
769 * this by setting flags in the mbuf header. Once we've made up our
770 * mind what to do, we pass the frame to ether_output() for further
775 ng_fec_output_serialized(struct ifnet
*ifp
, struct mbuf
*m
,
776 struct sockaddr
*dst
, struct rtentry
*rt0
)
778 const priv_p priv
= (priv_p
) ifp
->if_softc
;
779 struct ng_fec_bundle
*b
;
782 /* Check interface flags */
783 if ((ifp
->if_flags
& (IFF_UP
|IFF_RUNNING
)) != (IFF_UP
|IFF_RUNNING
)) {
788 b
= &priv
->fec_bundle
;
790 switch (b
->fec_btype
) {
792 m
->m_flags
|= M_FEC_MAC
;
797 * We can't use the INET address port selection
798 * scheme if this isn't an INET packet.
800 if (dst
->sa_family
== AF_INET
)
801 m
->m_flags
|= M_FEC_INET
;
803 else if (dst
->sa_family
== AF_INET6
)
804 m
->m_flags
|= M_FEC_INET6
;
808 kprintf("%s: can't do inet aggregation of non "
809 "inet packet\n", ifp
->if_xname
);
811 m
->m_flags
|= M_FEC_MAC
;
816 kprintf("%s: bogus hash type: %d\n", ifp
->if_xname
,
824 * Pass the frame to ether_output() for all the protocol
825 * handling. This will put the ethernet header on the packet
829 error
= priv
->real_if_output(ifp
, m
, dst
, rt0
);
830 if (priv
->if_error
&& !error
)
831 error
= priv
->if_error
;
837 ng_fec_output(struct ifnet
*ifp
, struct mbuf
*m
,
838 struct sockaddr
*dst
, struct rtentry
*rt0
)
842 lwkt_serialize_enter(ifp
->if_serializer
);
843 error
= ng_fec_output_serialized(ifp
, m
, dst
, rt0
);
844 lwkt_serialize_exit(ifp
->if_serializer
);
850 * Apply a hash to the source and destination addresses in the packet
851 * in order to select an interface. Also check link status and handle
852 * dead links accordingly.
856 ng_fec_choose_port(struct ng_fec_bundle
*b
,
857 struct mbuf
*m
, struct ifnet
**ifp
)
859 struct ether_header
*eh
;
868 struct ng_fec_portlist
*p
;
872 * If there are only two ports, mask off all but the
873 * last bit for XORing. If there are 4, mask off all
874 * but the last 2 bits.
876 mask
= b
->fec_ifcnt
== 2 ? 0x1 : 0x3;
877 eh
= mtod(m
, struct ether_header
*);
879 ip
= (struct ip
*)(mtod(m
, char *) +
880 sizeof(struct ether_header
));
882 ip6
= (struct ip6_hdr
*)(mtod(m
, char *) +
883 sizeof(struct ether_header
));
888 * The fg_fec_output() routine is supposed to leave a
889 * flag for us in the mbuf that tells us what hash to
890 * use, but sometimes a new mbuf is prepended to the
891 * chain, so we have to search every mbuf in the chain
896 if (m0
->m_flags
& (M_FEC_MAC
|M_FEC_INET
|M_FEC_INET6
))
903 switch (m0
->m_flags
& (M_FEC_MAC
|M_FEC_INET
|M_FEC_INET6
)) {
905 port
= (eh
->ether_dhost
[5] ^
906 eh
->ether_shost
[5]) & mask
;
910 port
= (ntohl(ip
->ip_dst
.s_addr
) ^
911 ntohl(ip
->ip_src
.s_addr
)) & mask
;
915 port
= (ip6
->ip6_dst
.s6_addr
[15] ^
916 ip6
->ip6_dst
.s6_addr
[15]) & mask
;
925 TAILQ_FOREACH(p
, &b
->ng_fec_ports
, fec_list
) {
926 if (port
== p
->fec_idx
)
931 * Now that we've chosen a port, make sure it's
932 * alive. If it's not alive, cycle through the bundle
933 * looking for a port that is alive. If we don't find
934 * any, return an error.
936 if (p
->fec_ifstat
!= 1) {
937 struct ng_fec_portlist
*n
= NULL
;
939 n
= TAILQ_NEXT(p
, fec_list
);
941 n
= TAILQ_FIRST(&b
->ng_fec_ports
);
943 if (n
->fec_ifstat
== 1)
945 n
= TAILQ_NEXT(n
, fec_list
);
947 n
= TAILQ_FIRST(&b
->ng_fec_ports
);
960 * Now that the packet has been run through ether_output(), yank it
961 * off our own send queue and stick it on the queue for the appropriate
962 * underlying physical interface. Note that if the interface's send
963 * queue is full, we save an error status in our private netgraph
964 * space which will eventually be handed up to ng_fec_output(), which
965 * will return it to the rest of the IP stack. We need to do this
966 * in order to duplicate the effect of ether_output() returning ENOBUFS
967 * when it detects that an interface's send queue is full. There's no
968 * other way to signal the error status from here since the if_start()
969 * routine is spec'ed to return void.
971 * Once the frame is queued, we call ether_output_frame() to initiate
975 ng_fec_start(struct ifnet
*ifp
)
977 struct ng_fec_private
*priv
;
978 struct ng_fec_bundle
*b
;
979 struct ifnet
*oifp
= NULL
;
983 priv
= ifp
->if_softc
;
984 b
= &priv
->fec_bundle
;
986 IF_DEQUEUE(&ifp
->if_snd
, m0
);
992 /* Queue up packet on the proper port. */
993 error
= ng_fec_choose_port(b
, m0
, &oifp
);
997 priv
->if_error
= ENOBUFS
;
1003 * Release current iface's serializer to avoid possible dead lock
1005 lwkt_serialize_exit(ifp
->if_serializer
);
1006 priv
->if_error
= ether_output_frame(oifp
, m0
);
1007 lwkt_serialize_enter(ifp
->if_serializer
);
1012 * Display an ioctl to the virtual interface
1016 ng_fec_print_ioctl(struct ifnet
*ifp
, int command
, caddr_t data
)
1020 switch (command
& IOC_DIRMASK
) {
1036 log(LOG_DEBUG
, "%s: %s('%c', %d, char[%d])\n",
1041 IOCPARM_LEN(command
));
1045 /************************************************************************
1047 ************************************************************************/
1050 * Constructor for a node
1053 ng_fec_constructor(node_p
*nodep
)
1055 char ifname
[NG_FEC_FEC_NAME_MAX
+ 1];
1059 struct ng_fec_bundle
*b
;
1062 /* Allocate node and interface private structures */
1063 MALLOC(priv
, priv_p
, sizeof(*priv
), M_NETGRAPH
, M_NOWAIT
| M_ZERO
);
1067 ifp
= &priv
->arpcom
.ac_if
;
1068 b
= &priv
->fec_bundle
;
1070 /* Link them together */
1071 ifp
->if_softc
= priv
;
1073 /* Get an interface unit number */
1074 if ((error
= ng_fec_get_unit(&priv
->unit
)) != 0) {
1075 FREE(ifp
, M_NETGRAPH
);
1076 FREE(priv
, M_NETGRAPH
);
1080 /* Call generic node constructor */
1081 if ((error
= ng_make_node_common(&typestruct
, nodep
)) != 0) {
1082 ng_fec_free_unit(priv
->unit
);
1083 FREE(ifp
, M_NETGRAPH
);
1084 FREE(priv
, M_NETGRAPH
);
1089 /* Link together node and private info */
1090 node
->private = priv
;
1092 priv
->arpcom
.ac_netgraph
= node
;
1094 /* Initialize interface structure */
1095 if_initname(ifp
, NG_FEC_FEC_NAME
, priv
->unit
);
1096 ifp
->if_start
= ng_fec_start
;
1097 ifp
->if_ioctl
= ng_fec_ioctl
;
1098 ifp
->if_init
= ng_fec_init
;
1099 ifp
->if_watchdog
= NULL
;
1100 ifp
->if_snd
.ifq_maxlen
= IFQ_MAXLEN
;
1101 ifp
->if_mtu
= NG_FEC_MTU_DEFAULT
;
1102 ifp
->if_flags
= (IFF_SIMPLEX
|IFF_BROADCAST
|IFF_MULTICAST
);
1103 ifp
->if_type
= IFT_PROPVIRTUAL
; /* XXX */
1104 ifp
->if_addrlen
= 0; /* XXX */
1105 ifp
->if_hdrlen
= 0; /* XXX */
1106 ifp
->if_baudrate
= 100000000; /* XXX */
1108 /* Give this node the same name as the interface (if possible) */
1109 bzero(ifname
, sizeof(ifname
));
1110 strlcpy(ifname
, ifp
->if_xname
, sizeof(ifname
));
1111 if (ng_name_node(node
, ifname
) != 0)
1112 log(LOG_WARNING
, "%s: can't acquire netgraph name\n", ifname
);
1114 /* Grab hold of the ether_input pipe. */
1115 if (ng_ether_input_p
== NULL
)
1116 ng_ether_input_p
= ng_fec_input
;
1118 /* Attach the interface */
1119 ether_ifattach(ifp
, priv
->arpcom
.ac_enaddr
, NULL
);
1120 priv
->real_if_output
= ifp
->if_output
;
1121 ifp
->if_output
= ng_fec_output
;
1122 callout_init(&priv
->fec_timeout
);
1124 TAILQ_INIT(&b
->ng_fec_ports
);
1127 ifmedia_init(&priv
->ifmedia
, 0,
1128 ng_fec_ifmedia_upd
, ng_fec_ifmedia_sts
);
1129 ifmedia_add(&priv
->ifmedia
, IFM_ETHER
|IFM_NONE
, 0, NULL
);
1130 ifmedia_set(&priv
->ifmedia
, IFM_ETHER
|IFM_NONE
);
1137 * Receive a control message
1140 ng_fec_rcvmsg(node_p node
, struct ng_mesg
*msg
,
1141 const char *retaddr
, struct ng_mesg
**rptr
)
1143 const priv_p priv
= node
->private;
1144 struct ng_fec_bundle
*b
;
1145 struct ng_mesg
*resp
= NULL
;
1149 b
= &priv
->fec_bundle
;
1151 switch (msg
->header
.typecookie
) {
1152 case NGM_FEC_COOKIE
:
1153 switch (msg
->header
.cmd
) {
1154 case NGM_FEC_ADD_IFACE
:
1156 error
= ng_fec_addport(priv
, ifname
);
1158 case NGM_FEC_DEL_IFACE
:
1160 error
= ng_fec_delport(priv
, ifname
);
1162 case NGM_FEC_SET_MODE_MAC
:
1163 b
->fec_btype
= FEC_BTYPE_MAC
;
1166 case NGM_FEC_SET_MODE_INET
:
1167 b
->fec_btype
= FEC_BTYPE_INET
;
1170 case NGM_FEC_SET_MODE_INET6
:
1171 b
->fec_btype
= FEC_BTYPE_INET6
;
1187 FREE(resp
, M_NETGRAPH
);
1188 FREE(msg
, M_NETGRAPH
);
1193 * Shutdown and remove the node and its associated interface.
1196 ng_fec_rmnode(node_p node
)
1198 const priv_p priv
= node
->private;
1199 struct ng_fec_bundle
*b
;
1200 struct ng_fec_portlist
*p
;
1201 char ifname
[IFNAMSIZ
];
1203 b
= &priv
->fec_bundle
;
1204 ng_fec_stop(&priv
->arpcom
.ac_if
);
1206 while (!TAILQ_EMPTY(&b
->ng_fec_ports
)) {
1207 p
= TAILQ_FIRST(&b
->ng_fec_ports
);
1208 ksprintf(ifname
, "%s",
1209 p
->fec_if
->if_xname
); /* XXX: strings */
1210 ng_fec_delport(priv
, ifname
);
1215 if (ng_ether_input_p
!= NULL
)
1216 ng_ether_input_p
= NULL
;
1217 ether_ifdetach(&priv
->arpcom
.ac_if
);
1218 ifmedia_removeall(&priv
->ifmedia
);
1219 ng_fec_free_unit(priv
->unit
);
1220 FREE(priv
, M_NETGRAPH
);
1221 node
->private = NULL
;