diff options
author | jhb <jhb@FreeBSD.org> | 2011-11-28 19:35:08 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2011-11-28 19:35:08 +0000 |
commit | 27cc3c5372d0c489807d64037a3c990f7883f9b2 (patch) | |
tree | ca836abcd55c952c55530790dc8dd94f446c6a94 /sys/net/if_vlan.c | |
parent | 0c9d560b0b757ac39243947d0792143131fd7cb7 (diff) | |
download | FreeBSD-src-27cc3c5372d0c489807d64037a3c990f7883f9b2.zip FreeBSD-src-27cc3c5372d0c489807d64037a3c990f7883f9b2.tar.gz |
Change the if_vlan driver to use if_transmit for forwarding packets to the
parent interface. This avoids the overhead of queueing a packet to an IFQ
only to immediately dequeue it again.
Suggested by: np
Reviewed by: brooks
MFC after: 1 month
Diffstat (limited to 'sys/net/if_vlan.c')
-rw-r--r-- | sys/net/if_vlan.c | 162 |
1 files changed, 79 insertions, 83 deletions
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c index 083086e..51e1c6c 100644 --- a/sys/net/if_vlan.c +++ b/sys/net/if_vlan.c @@ -34,9 +34,8 @@ * we need to pretend to be enough of an Ethernet implementation * to make arp work. The way we do this is by telling everyone * that we are an Ethernet, and then catch the packets that - * ether_output() left on our output queue when it calls - * if_start(), rewrite them for use by the real outgoing interface, - * and ask it to send them. + * ether_output() sends to us via if_transmit(), rewrite them for + * use by the real outgoing interface, and ask it to send them. */ #include <sys/cdefs.h> @@ -183,14 +182,15 @@ static __inline struct ifvlan * vlan_gethash(struct ifvlantrunk *trunk, #endif static void trunk_destroy(struct ifvlantrunk *trunk); -static void vlan_start(struct ifnet *ifp); static void vlan_init(void *foo); static void vlan_input(struct ifnet *ifp, struct mbuf *m); static int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr); +static void vlan_qflush(struct ifnet *ifp); static int vlan_setflag(struct ifnet *ifp, int flag, int status, int (*func)(struct ifnet *, int)); static int vlan_setflags(struct ifnet *ifp, int status); static int vlan_setmulti(struct ifnet *ifp); +static int vlan_transmit(struct ifnet *ifp, struct mbuf *m); static void vlan_unconfig(struct ifnet *ifp); static void vlan_unconfig_locked(struct ifnet *ifp); static int vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t tag); @@ -944,9 +944,9 @@ vlan_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) /* NB: mtu is not set here */ ifp->if_init = vlan_init; - ifp->if_start = vlan_start; + ifp->if_transmit = vlan_transmit; + ifp->if_qflush = vlan_qflush; ifp->if_ioctl = vlan_ioctl; - ifp->if_snd.ifq_maxlen = ifqmaxlen; ifp->if_flags = VLAN_IFFLAGS; ether_ifattach(ifp, eaddr); /* Now undo some of the damage... */ @@ -1005,99 +1005,95 @@ vlan_init(void *foo __unused) } /* - * The if_start method for vlan(4) interface. It doesn't - * raises the IFF_DRV_OACTIVE flag, since it is called - * only from IFQ_HANDOFF() macro in ether_output_frame(). - * If the interface queue is full, and vlan_start() is - * not called, the queue would never get emptied and - * interface would stall forever. + * The if_transmit method for vlan(4) interface. */ -static void -vlan_start(struct ifnet *ifp) +static int +vlan_transmit(struct ifnet *ifp, struct mbuf *m) { struct ifvlan *ifv; struct ifnet *p; - struct mbuf *m; int error; ifv = ifp->if_softc; p = PARENT(ifv); - for (;;) { - IF_DEQUEUE(&ifp->if_snd, m); - if (m == NULL) - break; - BPF_MTAP(ifp, m); + BPF_MTAP(ifp, m); - /* - * Do not run parent's if_start() if the parent is not up, - * or parent's driver will cause a system crash. - */ - if (!UP_AND_RUNNING(p)) { - m_freem(m); - ifp->if_collisions++; - continue; - } + /* + * Do not run parent's if_transmit() if the parent is not up, + * or parent's driver will cause a system crash. + */ + if (!UP_AND_RUNNING(p)) { + m_freem(m); + ifp->if_collisions++; + return (0); + } - /* - * Pad the frame to the minimum size allowed if told to. - * This option is in accord with IEEE Std 802.1Q, 2003 Ed., - * paragraph C.4.4.3.b. It can help to work around buggy - * bridges that violate paragraph C.4.4.3.a from the same - * document, i.e., fail to pad short frames after untagging. - * E.g., a tagged frame 66 bytes long (incl. FCS) is OK, but - * untagging it will produce a 62-byte frame, which is a runt - * and requires padding. There are VLAN-enabled network - * devices that just discard such runts instead or mishandle - * them somehow. - */ - if (soft_pad && p->if_type == IFT_ETHER) { - static char pad[8]; /* just zeros */ - int n; - - for (n = ETHERMIN + ETHER_HDR_LEN - m->m_pkthdr.len; - n > 0; n -= sizeof(pad)) - if (!m_append(m, min(n, sizeof(pad)), pad)) - break; - - if (n > 0) { - if_printf(ifp, "cannot pad short frame\n"); - ifp->if_oerrors++; - m_freem(m); - continue; - } - } + /* + * Pad the frame to the minimum size allowed if told to. + * This option is in accord with IEEE Std 802.1Q, 2003 Ed., + * paragraph C.4.4.3.b. It can help to work around buggy + * bridges that violate paragraph C.4.4.3.a from the same + * document, i.e., fail to pad short frames after untagging. + * E.g., a tagged frame 66 bytes long (incl. FCS) is OK, but + * untagging it will produce a 62-byte frame, which is a runt + * and requires padding. There are VLAN-enabled network + * devices that just discard such runts instead or mishandle + * them somehow. + */ + if (soft_pad && p->if_type == IFT_ETHER) { + static char pad[8]; /* just zeros */ + int n; - /* - * If underlying interface can do VLAN tag insertion itself, - * just pass the packet along. However, we need some way to - * tell the interface where the packet came from so that it - * knows how to find the VLAN tag to use, so we attach a - * packet tag that holds it. - */ - if (p->if_capenable & IFCAP_VLAN_HWTAGGING) { - m->m_pkthdr.ether_vtag = ifv->ifv_tag; - m->m_flags |= M_VLANTAG; - } else { - m = ether_vlanencap(m, ifv->ifv_tag); - if (m == NULL) { - if_printf(ifp, - "unable to prepend VLAN header\n"); - ifp->if_oerrors++; - continue; - } + for (n = ETHERMIN + ETHER_HDR_LEN - m->m_pkthdr.len; + n > 0; n -= sizeof(pad)) + if (!m_append(m, min(n, sizeof(pad)), pad)) + break; + + if (n > 0) { + if_printf(ifp, "cannot pad short frame\n"); + ifp->if_oerrors++; + m_freem(m); + return (0); } + } - /* - * Send it, precisely as ether_output() would have. - * We are already running at splimp. - */ - error = (p->if_transmit)(p, m); - if (!error) - ifp->if_opackets++; - else + /* + * If underlying interface can do VLAN tag insertion itself, + * just pass the packet along. However, we need some way to + * tell the interface where the packet came from so that it + * knows how to find the VLAN tag to use, so we attach a + * packet tag that holds it. + */ + if (p->if_capenable & IFCAP_VLAN_HWTAGGING) { + m->m_pkthdr.ether_vtag = ifv->ifv_tag; + m->m_flags |= M_VLANTAG; + } else { + m = ether_vlanencap(m, ifv->ifv_tag); + if (m == NULL) { + if_printf(ifp, "unable to prepend VLAN header\n"); ifp->if_oerrors++; + return (0); + } } + + /* + * Send it, precisely as ether_output() would have. + */ + error = (p->if_transmit)(p, m); + if (!error) + ifp->if_opackets++; + else + ifp->if_oerrors++; + return (error); +} + +/* + * The ifp->if_qflush entry point for vlan(4) is a no-op. + */ +static void +vlan_qflush(struct ifnet *ifp __unused) +{ } static void |