Author: jhb Date: Thu Jan 5 19:50:47 2012 New Revision: 229634 URL: http://svn.freebsd.org/changeset/base/229634
Log: MFC 228089: 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. Modified: stable/8/sys/net/if_vlan.c Directory Properties: stable/8/sys/ (props changed) stable/8/sys/amd64/include/xen/ (props changed) stable/8/sys/cddl/contrib/opensolaris/ (props changed) stable/8/sys/contrib/dev/acpica/ (props changed) stable/8/sys/contrib/pf/ (props changed) Modified: stable/8/sys/net/if_vlan.c ============================================================================== --- stable/8/sys/net/if_vlan.c Thu Jan 5 19:50:12 2012 (r229633) +++ stable/8/sys/net/if_vlan.c Thu Jan 5 19:50:47 2012 (r229634) @@ -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> @@ -179,14 +178,15 @@ static __inline struct ifvlan * vlan_get #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); @@ -807,9 +807,9 @@ vlan_clone_create(struct if_clone *ifc, /* 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... */ @@ -865,99 +865,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) { - 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) { + 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 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; - } + 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 _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"