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 $
38 * Copyright (c) 1996-1999 Whistle Communications, Inc.
39 * All rights reserved.
41 * Subject to the following obligations and disclaimer of warranty, use and
42 * redistribution of this software, in source or object code forms, with or
43 * without modifications are expressly permitted by Whistle Communications;
44 * provided, however, that:
45 * 1. Any and all reproductions of the source or object code must include the
46 * copyright notice above and the following disclaimer of warranties; and
47 * 2. No rights are granted, in any manner or form, to use Whistle
48 * Communications, Inc. trademarks, including the mark "WHISTLE
49 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
50 * such appears in the above copyright notice or in the software.
52 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
53 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
54 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
55 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
56 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
57 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
58 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
59 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
60 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
61 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
62 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
63 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
64 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
65 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
66 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
67 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
70 * Author: Archie Cobbs <archie@freebsd.org>
72 * $Whistle: ng_fec.c,v 1.33 1999/11/01 09:24:51 julian Exp $
76 * This module implements ethernet channel bonding using the Cisco
77 * Fast EtherChannel mechanism. Two or four ports may be combined
78 * into a single aggregate interface.
80 * Interfaces are named fec0, fec1, etc. New nodes take the
81 * first available interface name.
83 * This node also includes Berkeley packet filter support.
85 * Note that this node doesn't need to connect to any other
86 * netgraph nodes in order to do its work.
89 #include <sys/param.h>
90 #include <sys/systm.h>
91 #include <sys/errno.h>
92 #include <sys/kernel.h>
93 #include <sys/malloc.h>
95 #include <sys/sockio.h>
96 #include <sys/socket.h>
97 #include <sys/syslog.h>
98 #include <sys/libkern.h>
99 #include <sys/queue.h>
100 #include <sys/thread2.h>
103 #include <net/if_types.h>
104 #include <net/if_arp.h>
105 #include <net/if_dl.h>
106 #include <net/if_media.h>
107 #include <net/ifq_var.h>
109 #include <net/ethernet.h>
111 #include "opt_inet.h"
112 #include "opt_inet6.h"
114 #include <netinet/in.h>
116 #include <netinet/in_systm.h>
117 #include <netinet/ip.h>
121 #include <netinet/ip6.h>
124 #include <netgraph/ng_message.h>
125 #include <netgraph/netgraph.h>
126 #include <netgraph/ng_parse.h>
129 #define IFP2NG(ifp) ((struct ng_node *)((struct arpcom *)(ifp))->ac_netgraph)
130 #define FEC_INC(x, y) (x) = (x + 1) % y
133 * Current fast etherchannel implementations use either 2 or 4
134 * ports, so for now we limit the maximum bundle size to 4 interfaces.
136 #define FEC_BUNDLESIZ 4
138 struct ng_fec_portlist
{
139 struct ifnet
*fec_if
;
142 struct ether_addr fec_mac
;
143 TAILQ_ENTRY(ng_fec_portlist
) fec_list
;
146 struct ng_fec_bundle
{
147 TAILQ_HEAD(,ng_fec_portlist
) ng_fec_ports
;
152 #define FEC_BTYPE_MAC 0x01
153 #define FEC_BTYPE_INET 0x02
154 #define FEC_BTYPE_INET6 0x03
156 /* Node private data */
157 struct ng_fec_private
{
158 struct arpcom arpcom
;
159 struct ifmedia ifmedia
;
161 int if_error
; /* XXX */
162 int unit
; /* Interface unit number */
163 node_p node
; /* Our netgraph node */
164 struct ng_fec_bundle fec_bundle
;/* Aggregate bundle */
165 struct callout fec_timeout
; /* callout for ticker */
166 int (*real_if_output
)(struct ifnet
*, struct mbuf
*,
167 struct sockaddr
*, struct rtentry
*);
169 typedef struct ng_fec_private
*priv_p
;
171 /* Interface methods */
172 static void ng_fec_input(struct ifnet
*, struct mbuf
**);
173 static void ng_fec_start(struct ifnet
*ifp
, struct ifaltq_subque
*);
174 static int ng_fec_choose_port(struct ng_fec_bundle
*b
,
175 struct mbuf
*m
, struct ifnet
**ifp
);
176 static int ng_fec_setport(struct ifnet
*ifp
, u_long cmd
, caddr_t data
);
177 static void ng_fec_init(void *arg
);
178 static void ng_fec_stop(struct ifnet
*ifp
);
179 static int ng_fec_ifmedia_upd(struct ifnet
*ifp
);
180 static void ng_fec_ifmedia_sts(struct ifnet
*ifp
, struct ifmediareq
*ifmr
);
181 static int ng_fec_ioctl(struct ifnet
*ifp
, u_long cmd
, caddr_t data
,
183 static int ng_fec_output(struct ifnet
*ifp
, struct mbuf
*m0
,
184 struct sockaddr
*dst
, struct rtentry
*rt0
);
185 static void ng_fec_tick(void *arg
);
186 static int ng_fec_addport(struct ng_fec_private
*priv
, char *iface
);
187 static int ng_fec_delport(struct ng_fec_private
*priv
, char *iface
);
190 static void ng_fec_print_ioctl(struct ifnet
*ifp
, int cmd
, caddr_t data
);
193 /* Netgraph methods */
194 static ng_constructor_t ng_fec_constructor
;
195 static ng_rcvmsg_t ng_fec_rcvmsg
;
196 static ng_shutdown_t ng_fec_rmnode
;
198 /* List of commands and how to convert arguments to/from ASCII */
199 static const struct ng_cmdlist ng_fec_cmds
[] = {
204 &ng_parse_string_type
,
211 &ng_parse_string_type
,
216 NGM_FEC_SET_MODE_MAC
,
223 NGM_FEC_SET_MODE_INET
,
231 /* Node type descriptor */
232 static struct ng_type typestruct
= {
247 NETGRAPH_INIT(fec
, &typestruct
);
249 /* We keep a bitmap indicating which unit numbers are free.
250 One means the unit number is free, zero means it's taken. */
251 static int *ng_fec_units
= NULL
;
252 static int ng_fec_units_len
= 0;
253 static int ng_units_in_use
= 0;
255 #define UNITS_BITSPERWORD (sizeof(*ng_fec_units) * NBBY)
258 * Find the first free unit number for a new interface.
259 * Increase the size of the unit bitmap as necessary.
261 static __inline__
int
262 ng_fec_get_unit(int *unit
)
266 for (index
= 0; index
< ng_fec_units_len
267 && ng_fec_units
[index
] == 0; index
++);
268 if (index
== ng_fec_units_len
) { /* extend array */
269 int i
, *newarray
, newlen
;
271 newlen
= (2 * ng_fec_units_len
) + 4;
272 newarray
= kmalloc(newlen
* sizeof(*ng_fec_units
),
273 M_NETGRAPH
, M_NOWAIT
);
274 if (newarray
== NULL
)
276 bcopy(ng_fec_units
, newarray
,
277 ng_fec_units_len
* sizeof(*ng_fec_units
));
278 for (i
= ng_fec_units_len
; i
< newlen
; i
++)
280 if (ng_fec_units
!= NULL
)
281 kfree(ng_fec_units
, M_NETGRAPH
);
282 ng_fec_units
= newarray
;
283 ng_fec_units_len
= newlen
;
285 bit
= ffs(ng_fec_units
[index
]) - 1;
286 KASSERT(bit
>= 0 && bit
<= UNITS_BITSPERWORD
- 1,
287 ("%s: word=%d bit=%d", __func__
, ng_fec_units
[index
], bit
));
288 ng_fec_units
[index
] &= ~(1 << bit
);
289 *unit
= (index
* UNITS_BITSPERWORD
) + bit
;
295 * Free a no longer needed unit number.
297 static __inline__
void
298 ng_fec_free_unit(int unit
)
302 index
= unit
/ UNITS_BITSPERWORD
;
303 bit
= unit
% UNITS_BITSPERWORD
;
304 KASSERT(index
< ng_fec_units_len
,
305 ("%s: unit=%d len=%d", __func__
, unit
, ng_fec_units_len
));
306 KASSERT((ng_fec_units
[index
] & (1 << bit
)) == 0,
307 ("%s: unit=%d is free", __func__
, unit
));
308 ng_fec_units
[index
] |= (1 << bit
);
310 * XXX We could think about reducing the size of ng_fec_units[]
311 * XXX here if the last portion is all ones
312 * XXX At least free it if no more units.
313 * Needed if we are eventually be able to unload.
316 if (ng_units_in_use
== 0) { /* XXX make SMP safe */
317 kfree(ng_fec_units
, M_NETGRAPH
);
318 ng_fec_units_len
= 0;
323 /************************************************************************
325 ************************************************************************/
328 ng_fec_addport(struct ng_fec_private
*priv
, char *iface
)
330 struct ng_fec_bundle
*b
;
331 struct ifnet
*ifp
, *bifp
;
333 struct sockaddr_dl
*sdl
;
334 struct ng_fec_portlist
*p
, *new;
336 if (priv
== NULL
|| iface
== NULL
)
339 b
= &priv
->fec_bundle
;
340 ifp
= &priv
->arpcom
.ac_if
;
344 /* Find the interface */
345 bifp
= ifunit(iface
);
348 kprintf("fec%d: tried to add iface %s, which "
349 "doesn't seem to exist\n", priv
->unit
, iface
);
353 /* See if we have room in the bundle */
354 if (b
->fec_ifcnt
== FEC_BUNDLESIZ
) {
356 kprintf("fec%d: can't add new iface; bundle is full\n",
361 /* See if the interface is already in the bundle */
362 TAILQ_FOREACH(p
, &b
->ng_fec_ports
, fec_list
) {
363 if (p
->fec_if
== bifp
) {
365 kprintf("fec%d: iface %s is already in this "
366 "bundle\n", priv
->unit
, iface
);
371 /* Allocate new list entry. */
372 new = kmalloc(sizeof(struct ng_fec_portlist
), M_NETGRAPH
, M_NOWAIT
);
378 ac
= (struct arpcom
*)bifp
;
379 ac
->ac_netgraph
= priv
->node
;
382 * If this is the first interface added to the bundle,
383 * use its MAC address for the virtual interface (and,
384 * by extension, all the other ports in the bundle).
386 if (b
->fec_ifcnt
== 0) {
387 sdl
= IF_LLSOCKADDR(ifp
);
388 bcopy((char *)ac
->ac_enaddr
,
389 priv
->arpcom
.ac_enaddr
, ETHER_ADDR_LEN
);
390 bcopy((char *)ac
->ac_enaddr
,
391 LLADDR(sdl
), ETHER_ADDR_LEN
);
394 b
->fec_btype
= FEC_BTYPE_MAC
;
395 new->fec_idx
= b
->fec_ifcnt
;
398 /* Save the real MAC address. */
399 bcopy((char *)ac
->ac_enaddr
,
400 (char *)&new->fec_mac
, ETHER_ADDR_LEN
);
402 /* Set up phony MAC address. */
403 sdl
= IF_LLSOCKADDR(bifp
);
404 bcopy(priv
->arpcom
.ac_enaddr
, ac
->ac_enaddr
, ETHER_ADDR_LEN
);
405 bcopy(priv
->arpcom
.ac_enaddr
, LLADDR(sdl
), ETHER_ADDR_LEN
);
407 /* Add to the queue */
409 TAILQ_INSERT_TAIL(&b
->ng_fec_ports
, new, fec_list
);
417 ng_fec_delport(struct ng_fec_private
*priv
, char *iface
)
419 struct ng_fec_bundle
*b
;
422 struct sockaddr_dl
*sdl
;
423 struct ng_fec_portlist
*p
;
425 if (priv
== NULL
|| iface
== NULL
)
428 b
= &priv
->fec_bundle
;
432 /* Find the interface */
433 bifp
= ifunit(iface
);
436 kprintf("fec%d: tried to remove iface %s, which "
437 "doesn't seem to exist\n", priv
->unit
, iface
);
441 TAILQ_FOREACH(p
, &b
->ng_fec_ports
, fec_list
) {
442 if (p
->fec_if
== bifp
)
448 kprintf("fec%d: tried to remove iface %s which "
449 "is not in our bundle\n", priv
->unit
, iface
);
454 bifp
->if_flags
&= ~IFF_UP
;
455 bifp
->if_ioctl(bifp
, SIOCSIFFLAGS
, NULL
, NULL
);
457 /* Restore MAC address. */
458 ac
= (struct arpcom
*)bifp
;
459 sdl
= IF_LLSOCKADDR(bifp
);
460 bcopy((char *)&p
->fec_mac
, ac
->ac_enaddr
, ETHER_ADDR_LEN
);
461 bcopy((char *)&p
->fec_mac
, LLADDR(sdl
), ETHER_ADDR_LEN
);
464 TAILQ_REMOVE(&b
->ng_fec_ports
, p
, fec_list
);
465 kfree(p
, M_NETGRAPH
);
474 * Pass an ioctl command down to all the underyling interfaces in a
475 * bundle. Used for setting multicast filters and flags.
478 ng_fec_setport(struct ifnet
*ifp
, u_long command
, caddr_t data
)
480 struct ng_fec_private
*priv
;
481 struct ng_fec_bundle
*b
;
483 struct ng_fec_portlist
*p
;
485 priv
= ifp
->if_softc
;
486 b
= &priv
->fec_bundle
;
488 ifnet_deserialize_all(ifp
); /* XXX */
489 TAILQ_FOREACH(p
, &b
->ng_fec_ports
, fec_list
) {
492 ifnet_serialize_all(oifp
);
493 oifp
->if_ioctl(oifp
, command
, data
, NULL
);
494 ifnet_deserialize_all(oifp
);
497 ifnet_serialize_all(ifp
);
503 ng_fec_init(void *arg
)
505 struct ng_fec_private
*priv
;
506 struct ng_fec_bundle
*b
;
507 struct ifnet
*ifp
, *bifp
;
508 struct ng_fec_portlist
*p
;
511 priv
= ifp
->if_softc
;
512 b
= &priv
->fec_bundle
;
514 if (b
->fec_ifcnt
== 1 || b
->fec_ifcnt
== 3) {
515 kprintf("fec%d: invalid bundle "
516 "size: %d\n", priv
->unit
,
523 ifnet_deserialize_all(ifp
); /* XXX */
524 TAILQ_FOREACH(p
, &b
->ng_fec_ports
, fec_list
) {
526 ifnet_serialize_all(bifp
);
527 bifp
->if_flags
|= IFF_UP
;
528 bifp
->if_ioctl(bifp
, SIOCSIFFLAGS
, NULL
, NULL
);
529 /* mark iface as up and let the monitor check it */
531 ifnet_deserialize_all(bifp
);
533 ifnet_serialize_all(ifp
);
535 callout_reset(&priv
->fec_timeout
, hz
, ng_fec_tick
, priv
);
539 ng_fec_stop(struct ifnet
*ifp
)
541 struct ng_fec_private
*priv
;
542 struct ng_fec_bundle
*b
;
544 struct ng_fec_portlist
*p
;
546 priv
= ifp
->if_softc
;
547 b
= &priv
->fec_bundle
;
549 ifnet_deserialize_all(ifp
); /* XXX */
550 TAILQ_FOREACH(p
, &b
->ng_fec_ports
, fec_list
) {
552 ifnet_serialize_all(bifp
);
553 bifp
->if_flags
&= ~IFF_UP
;
554 bifp
->if_ioctl(bifp
, SIOCSIFFLAGS
, NULL
, NULL
);
555 ifnet_deserialize_all(bifp
);
557 ifnet_serialize_all(ifp
);
559 callout_stop(&priv
->fec_timeout
);
563 ng_fec_tick(void *arg
)
565 struct ng_fec_private
*priv
;
566 struct ng_fec_bundle
*b
;
567 struct ifmediareq ifmr
;
569 struct ng_fec_portlist
*p
;
573 b
= &priv
->fec_bundle
;
576 * Note: serializer for parent interface not held on entry, and
577 * cannot be held during the loop to avoid a deadlock.
579 TAILQ_FOREACH(p
, &b
->ng_fec_ports
, fec_list
) {
580 bzero((char *)&ifmr
, sizeof(ifmr
));
582 ifnet_serialize_all(ifp
);
583 error
= ifp
->if_ioctl(ifp
, SIOCGIFMEDIA
, (caddr_t
)&ifmr
, NULL
);
585 kprintf("fec%d: failed to check status "
586 "of link %s\n", priv
->unit
, ifp
->if_xname
);
587 ifnet_deserialize_all(ifp
);
591 if (ifmr
.ifm_status
& IFM_AVALID
&&
592 IFM_TYPE(ifmr
.ifm_active
) == IFM_ETHER
) {
593 if (ifmr
.ifm_status
& IFM_ACTIVE
) {
594 if (p
->fec_ifstat
== -1 ||
595 p
->fec_ifstat
== 0) {
597 kprintf("fec%d: port %s in bundle "
598 "is up\n", priv
->unit
,
602 if (p
->fec_ifstat
== -1 ||
603 p
->fec_ifstat
== 1) {
605 kprintf("fec%d: port %s in bundle "
606 "is down\n", priv
->unit
,
611 ifnet_deserialize_all(ifp
);
614 ifp
= &priv
->arpcom
.ac_if
;
615 if (ifp
->if_flags
& IFF_RUNNING
)
616 callout_reset(&priv
->fec_timeout
, hz
, ng_fec_tick
, priv
);
620 ng_fec_ifmedia_upd(struct ifnet
*ifp
)
626 ng_fec_ifmedia_sts(struct ifnet
*ifp
, struct ifmediareq
*ifmr
)
628 struct ng_fec_private
*priv
;
629 struct ng_fec_bundle
*b
;
630 struct ng_fec_portlist
*p
;
632 priv
= ifp
->if_softc
;
633 b
= &priv
->fec_bundle
;
635 ifmr
->ifm_status
= IFM_AVALID
;
636 TAILQ_FOREACH(p
, &b
->ng_fec_ports
, fec_list
) {
638 ifmr
->ifm_status
|= IFM_ACTIVE
;
645 * Process an ioctl for the virtual interface
648 ng_fec_ioctl(struct ifnet
*ifp
, u_long command
, caddr_t data
, struct ucred
*cr
)
650 struct ifreq
*const ifr
= (struct ifreq
*) data
;
652 struct ng_fec_private
*priv
;
653 struct ng_fec_bundle
*b
;
655 priv
= ifp
->if_softc
;
656 b
= &priv
->fec_bundle
;
659 ng_fec_print_ioctl(ifp
, command
, data
);
664 /* These two are mostly handled at a higher layer */
668 error
= ether_ioctl(ifp
, command
, data
);
674 * If the interface is marked up and stopped, then start it.
675 * If it is marked down and running, then stop it.
677 if (ifr
->ifr_flags
& IFF_UP
) {
678 if (!(ifp
->if_flags
& IFF_RUNNING
)) {
680 if (b
->fec_ifcnt
== 1 || b
->fec_ifcnt
== 3) {
681 kprintf("fec%d: invalid bundle "
682 "size: %d\n", priv
->unit
,
687 ifq_clr_oactive(&ifp
->if_snd
);
688 ifp
->if_flags
|= IFF_RUNNING
;
692 * Bubble down changes in promisc mode to
693 * underlying interfaces.
695 if ((ifp
->if_flags
& IFF_PROMISC
) !=
696 (priv
->if_flags
& IFF_PROMISC
)) {
697 ng_fec_setport(ifp
, command
, data
);
698 priv
->if_flags
= ifp
->if_flags
;
701 if (ifp
->if_flags
& IFF_RUNNING
) {
702 ifp
->if_flags
&= ~IFF_RUNNING
;
703 ifq_clr_oactive(&ifp
->if_snd
);
711 ng_fec_setport(ifp
, command
, data
);
716 error
= ifmedia_ioctl(ifp
, ifr
, &priv
->ifmedia
, command
);
718 /* Stuff that's not supported */
732 * This routine spies on mbufs passing through ether_input(). If
733 * they come from one of the interfaces that are aggregated into
734 * our bundle, we fix up the ifnet pointer and increment our
735 * packet counters so that it looks like the frames are actually
739 ng_fec_input(struct ifnet
*ifp
, struct mbuf
**m0
)
741 struct ng_node
*node
;
742 struct ng_fec_private
*priv
;
743 struct ng_fec_bundle
*b
;
746 struct ng_fec_portlist
*p
;
749 if (ifp
== NULL
|| m0
== NULL
)
754 /* Sanity check part II */
758 priv
= node
->private;
759 b
= &priv
->fec_bundle
;
760 bifp
= &priv
->arpcom
.ac_if
;
763 TAILQ_FOREACH(p
, &b
->ng_fec_ports
, fec_list
) {
764 if (p
->fec_if
== m
->m_pkthdr
.rcvif
)
768 /* Wasn't meant for us; leave this frame alone. */
772 /* Pretend this is our frame. */
773 m
->m_pkthdr
.rcvif
= bifp
;
774 IFNET_STAT_INC(bifp
, ipackets
, 1);
775 IFNET_STAT_INC(bifp
, ibytes
, m
->m_pkthdr
.len
);
780 bpf_mtap(bifp
->if_bpf
, m
);
786 * Take a quick peek at the packet and see if it's ok for us to use
787 * the inet or inet6 hash methods on it, if they're enabled. We do
788 * this by setting flags in the mbuf header. Once we've made up our
789 * mind what to do, we pass the frame to ether_output() for further
794 ng_fec_output_serialized(struct ifnet
*ifp
, struct mbuf
*m
,
795 struct sockaddr
*dst
, struct rtentry
*rt0
)
797 const priv_p priv
= (priv_p
) ifp
->if_softc
;
798 struct ng_fec_bundle
*b
;
801 /* Check interface flags */
802 if ((ifp
->if_flags
& (IFF_UP
|IFF_RUNNING
)) != (IFF_UP
|IFF_RUNNING
)) {
807 b
= &priv
->fec_bundle
;
809 switch (b
->fec_btype
) {
811 m
->m_flags
|= M_FEC_MAC
;
816 * We can't use the INET address port selection
817 * scheme if this isn't an INET packet.
819 if (dst
->sa_family
== AF_INET
)
820 m
->m_flags
|= M_FEC_INET
;
822 else if (dst
->sa_family
== AF_INET6
)
823 m
->m_flags
|= M_FEC_INET6
;
827 kprintf("%s: can't do inet aggregation of non "
828 "inet packet\n", ifp
->if_xname
);
830 m
->m_flags
|= M_FEC_MAC
;
835 kprintf("%s: bogus hash type: %d\n", ifp
->if_xname
,
843 * Pass the frame to ether_output() for all the protocol
844 * handling. This will put the ethernet header on the packet
848 error
= priv
->real_if_output(ifp
, m
, dst
, rt0
);
849 if (priv
->if_error
&& !error
)
850 error
= priv
->if_error
;
856 ng_fec_output(struct ifnet
*ifp
, struct mbuf
*m
,
857 struct sockaddr
*dst
, struct rtentry
*rt0
)
859 struct ifaltq_subque
*ifsq
= ifq_get_subq_default(&ifp
->if_snd
);
862 ifsq_serialize_hw(ifsq
);
863 error
= ng_fec_output_serialized(ifp
, m
, dst
, rt0
);
864 ifsq_deserialize_hw(ifsq
);
870 * Apply a hash to the source and destination addresses in the packet
871 * in order to select an interface. Also check link status and handle
872 * dead links accordingly.
876 ng_fec_choose_port(struct ng_fec_bundle
*b
,
877 struct mbuf
*m
, struct ifnet
**ifp
)
879 struct ether_header
*eh
;
888 struct ng_fec_portlist
*p
;
892 * If there are only two ports, mask off all but the
893 * last bit for XORing. If there are 4, mask off all
894 * but the last 2 bits.
896 mask
= b
->fec_ifcnt
== 2 ? 0x1 : 0x3;
897 eh
= mtod(m
, struct ether_header
*);
899 ip
= (struct ip
*)(mtod(m
, char *) +
900 sizeof(struct ether_header
));
902 ip6
= (struct ip6_hdr
*)(mtod(m
, char *) +
903 sizeof(struct ether_header
));
908 * The fg_fec_output() routine is supposed to leave a
909 * flag for us in the mbuf that tells us what hash to
910 * use, but sometimes a new mbuf is prepended to the
911 * chain, so we have to search every mbuf in the chain
916 if (m0
->m_flags
& (M_FEC_MAC
|M_FEC_INET
|M_FEC_INET6
))
923 switch (m0
->m_flags
& (M_FEC_MAC
|M_FEC_INET
|M_FEC_INET6
)) {
925 port
= (eh
->ether_dhost
[5] ^
926 eh
->ether_shost
[5]) & mask
;
930 port
= (ntohl(ip
->ip_dst
.s_addr
) ^
931 ntohl(ip
->ip_src
.s_addr
)) & mask
;
935 port
= (ip6
->ip6_dst
.s6_addr
[15] ^
936 ip6
->ip6_dst
.s6_addr
[15]) & mask
;
945 TAILQ_FOREACH(p
, &b
->ng_fec_ports
, fec_list
) {
946 if (port
== p
->fec_idx
)
951 * Now that we've chosen a port, make sure it's
952 * alive. If it's not alive, cycle through the bundle
953 * looking for a port that is alive. If we don't find
954 * any, return an error.
956 if (p
->fec_ifstat
!= 1) {
957 struct ng_fec_portlist
*n
= NULL
;
959 n
= TAILQ_NEXT(p
, fec_list
);
961 n
= TAILQ_FIRST(&b
->ng_fec_ports
);
963 if (n
->fec_ifstat
== 1)
965 n
= TAILQ_NEXT(n
, fec_list
);
967 n
= TAILQ_FIRST(&b
->ng_fec_ports
);
980 * Now that the packet has been run through ether_output(), yank it
981 * off our own send queue and stick it on the queue for the appropriate
982 * underlying physical interface. Note that if the interface's send
983 * queue is full, we save an error status in our private netgraph
984 * space which will eventually be handed up to ng_fec_output(), which
985 * will return it to the rest of the IP stack. We need to do this
986 * in order to duplicate the effect of ether_output() returning ENOBUFS
987 * when it detects that an interface's send queue is full. There's no
988 * other way to signal the error status from here since the if_start()
989 * routine is spec'ed to return void.
991 * Once the frame is queued, we call ether_output_frame() to initiate
995 ng_fec_start(struct ifnet
*ifp
, struct ifaltq_subque
*ifsq __unused
)
997 struct ng_fec_private
*priv
;
998 struct ng_fec_bundle
*b
;
999 struct ifnet
*oifp
= NULL
;
1003 priv
= ifp
->if_softc
;
1004 b
= &priv
->fec_bundle
;
1006 m0
= ifq_dequeue(&ifp
->if_snd
);
1012 /* Queue up packet on the proper port. */
1013 error
= ng_fec_choose_port(b
, m0
, &oifp
);
1015 IFNET_STAT_INC(ifp
, ierrors
, 1);
1017 priv
->if_error
= ENOBUFS
;
1020 IFNET_STAT_INC(ifp
, opackets
, 1);
1023 * Release current iface's serializer to avoid possible dead lock
1025 priv
->if_error
= ether_output_frame(oifp
, m0
);
1030 * Display an ioctl to the virtual interface
1034 ng_fec_print_ioctl(struct ifnet
*ifp
, int command
, caddr_t data
)
1038 switch (command
& IOC_DIRMASK
) {
1054 log(LOG_DEBUG
, "%s: %s('%c', %d, char[%d])\n",
1059 IOCPARM_LEN(command
));
1063 /************************************************************************
1065 ************************************************************************/
1068 * Constructor for a node
1071 ng_fec_constructor(node_p
*nodep
)
1073 char ifname
[NG_FEC_FEC_NAME_MAX
+ 1];
1077 struct ng_fec_bundle
*b
;
1080 /* Allocate node and interface private structures */
1081 priv
= kmalloc(sizeof(*priv
), M_NETGRAPH
, M_NOWAIT
| M_ZERO
);
1085 ifp
= &priv
->arpcom
.ac_if
;
1086 b
= &priv
->fec_bundle
;
1088 /* Link them together */
1089 ifp
->if_softc
= priv
;
1091 /* Get an interface unit number */
1092 if ((error
= ng_fec_get_unit(&priv
->unit
)) != 0) {
1093 kfree(ifp
, M_NETGRAPH
);
1094 kfree(priv
, M_NETGRAPH
);
1098 /* Call generic node constructor */
1099 if ((error
= ng_make_node_common(&typestruct
, nodep
)) != 0) {
1100 ng_fec_free_unit(priv
->unit
);
1101 kfree(ifp
, M_NETGRAPH
);
1102 kfree(priv
, M_NETGRAPH
);
1107 /* Link together node and private info */
1108 node
->private = priv
;
1110 priv
->arpcom
.ac_netgraph
= node
;
1112 /* Initialize interface structure */
1113 if_initname(ifp
, NG_FEC_FEC_NAME
, priv
->unit
);
1114 ifp
->if_start
= ng_fec_start
;
1115 ifp
->if_ioctl
= ng_fec_ioctl
;
1116 ifp
->if_init
= ng_fec_init
;
1117 ifp
->if_watchdog
= NULL
;
1118 ifq_set_maxlen(&ifp
->if_snd
, IFQ_MAXLEN
);
1119 ifp
->if_mtu
= NG_FEC_MTU_DEFAULT
;
1120 ifp
->if_flags
= (IFF_SIMPLEX
|IFF_BROADCAST
|IFF_MULTICAST
);
1121 ifp
->if_type
= IFT_PROPVIRTUAL
; /* XXX */
1122 ifp
->if_addrlen
= 0; /* XXX */
1123 ifp
->if_hdrlen
= 0; /* XXX */
1124 ifp
->if_baudrate
= 100000000; /* XXX */
1126 /* Give this node the same name as the interface (if possible) */
1127 bzero(ifname
, sizeof(ifname
));
1128 strlcpy(ifname
, ifp
->if_xname
, sizeof(ifname
));
1129 if (ng_name_node(node
, ifname
) != 0)
1130 log(LOG_WARNING
, "%s: can't acquire netgraph name\n", ifname
);
1132 /* Grab hold of the ether_input pipe. */
1133 if (ng_ether_input_p
== NULL
)
1134 ng_ether_input_p
= ng_fec_input
;
1136 /* Attach the interface */
1137 ether_ifattach(ifp
, priv
->arpcom
.ac_enaddr
, NULL
);
1138 priv
->real_if_output
= ifp
->if_output
;
1139 ifp
->if_output
= ng_fec_output
;
1140 callout_init(&priv
->fec_timeout
);
1142 TAILQ_INIT(&b
->ng_fec_ports
);
1145 ifmedia_init(&priv
->ifmedia
, 0,
1146 ng_fec_ifmedia_upd
, ng_fec_ifmedia_sts
);
1147 ifmedia_add(&priv
->ifmedia
, IFM_ETHER
|IFM_NONE
, 0, NULL
);
1148 ifmedia_set(&priv
->ifmedia
, IFM_ETHER
|IFM_NONE
);
1155 * Receive a control message
1158 ng_fec_rcvmsg(node_p node
, struct ng_mesg
*msg
,
1159 const char *retaddr
, struct ng_mesg
**rptr
)
1161 const priv_p priv
= node
->private;
1162 struct ng_fec_bundle
*b
;
1163 struct ng_mesg
*resp
= NULL
;
1167 b
= &priv
->fec_bundle
;
1169 switch (msg
->header
.typecookie
) {
1170 case NGM_FEC_COOKIE
:
1171 switch (msg
->header
.cmd
) {
1172 case NGM_FEC_ADD_IFACE
:
1174 error
= ng_fec_addport(priv
, ifname
);
1176 case NGM_FEC_DEL_IFACE
:
1178 error
= ng_fec_delport(priv
, ifname
);
1180 case NGM_FEC_SET_MODE_MAC
:
1181 b
->fec_btype
= FEC_BTYPE_MAC
;
1184 case NGM_FEC_SET_MODE_INET
:
1185 b
->fec_btype
= FEC_BTYPE_INET
;
1188 case NGM_FEC_SET_MODE_INET6
:
1189 b
->fec_btype
= FEC_BTYPE_INET6
;
1205 kfree(resp
, M_NETGRAPH
);
1206 kfree(msg
, M_NETGRAPH
);
1211 * Shutdown and remove the node and its associated interface.
1214 ng_fec_rmnode(node_p node
)
1216 const priv_p priv
= node
->private;
1217 struct ng_fec_bundle
*b
;
1218 struct ng_fec_portlist
*p
;
1219 char ifname
[IFNAMSIZ
];
1221 b
= &priv
->fec_bundle
;
1222 ng_fec_stop(&priv
->arpcom
.ac_if
);
1224 while (!TAILQ_EMPTY(&b
->ng_fec_ports
)) {
1225 p
= TAILQ_FIRST(&b
->ng_fec_ports
);
1226 ksprintf(ifname
, "%s",
1227 p
->fec_if
->if_xname
); /* XXX: strings */
1228 ng_fec_delport(priv
, ifname
);
1233 if (ng_ether_input_p
!= NULL
)
1234 ng_ether_input_p
= NULL
;
1235 ether_ifdetach(&priv
->arpcom
.ac_if
);
1236 ifmedia_removeall(&priv
->ifmedia
);
1237 ng_fec_free_unit(priv
->unit
);
1238 kfree(priv
, M_NETGRAPH
);
1239 node
->private = NULL
;