tech-net archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: refactoring ip_output() and the L2 _output()
David Young <dyoung%pobox.com@localhost> wrote:
> <...>
>
> I'd like ether_output never, ever to deal with the routing table,
> but arpresolve() deals some in routes, so eventually I will have
> to factor that out. I'm aiming for a streamlined IP transmission
> path. Today we have something comparatively baroque,
>
> # enter ip_output
> dst <- destination(packet)
> nexthop <- lookup(ip routing table, dst)
> # enter ether_output
> if (nexthop is gateway)
> if (gateway is cached)
> nexthop <- gwcache(nexthop)
> else
> gwcache(nexthop) <- lookup(ip routing table,
> gwaddr(nexthop))
> nexthop <- gwcache(nexthop)
> if (nexthop l2 info incomplete)
> defer_until_arp_complete(nexthop, packet)
> else
> l2hdr <- create_l2header(interface(nexthop), gwaddr
> (nexthop)) transmit(interface(nexthop), l2hdr | packet)
>
> I'm aiming for something more like this:
>
> # enter ip_output
> dst <- destination(packet)
> nexthop <- lookup(ip routing table, dst)
> if (nexthop l2 info incomplete)
> defer_until_arp_complete(nexthop, packet)
> else
> # enter ether_output
> transmit(interface(nexthop), l2header(nexthop), packet)
>
> It will take several steps to get there. Here is one. A step in the
> wrong direction? Your feedback, please. :-)
Seems reasonable direction to me.
Few small comments on the patch:
> +/*
> + * Send an IP packet to a host.
> + *
> + * If necessary, resolve the arbitrary IP route, rt0, to an IP host route
> before
> + * calling ifp's output routine.
> + */
> +int
> +ip_hresolv_output(struct ifnet * const ifp, struct mbuf * const m,
> + const struct sockaddr * const dst, struct rtentry *rt0)
> +{
> +#define senderr(e) { error = (e); goto bad;}
I do not think it is worth to macrify such error path; most of the code in
the kernel does not. Actually, it might be worth to just leave the error
handling for the caller here.
> + int error = 0;
> + struct rtentry *rt;
> +
> + if (!ip_hresolv_needed(ifp))
> + return klock_if_output(ifp, m, dst, rt0);
> +
> + if ((rt = rt0) == NULL)
> + return klock_if_output(ifp, m, dst, NULL);
> +
> + /* The following block is highly questionable. How did we get
> here
> + * with a !RTF_UP route? Does rtalloc1() always return an RTF_UP
> + * route?
> + */
/*
* KNF. :)
*/
> + if ((rt->rt_flags & RTF_UP) == 0) {
> + if ((rt0 = rt = rtalloc1(dst, 1)) == NULL)
> + senderr(EHOSTUNREACH);
> + rt->rt_refcnt--;
> + if (rt->rt_ifp != ifp)
> + return ip_hresolv_output(rt->rt_ifp, m, dst, rt);
> + }
Recursive? How about handling this in a loop?
> +static bool
> +ip_hresolv_needed(const struct ifnet * const ifp)
> +{
> + switch (ifp->if_type) {
> + case IFT_ARCNET:
> + case IFT_ETHER:
> + case IFT_FDDI:
> + case IFT_IEEE1394:
> + return 1;
> + default:
> + return 0;
> + }
> +}
There are standard "true" and "false" for bool.
+static __attribute__((always_inline)) inline int
+klock_if_output(struct ifnet * const ifp, struct mbuf * const m,
+ const struct sockaddr * const dst, struct rtentry *rt)
+{
+ int error;
+
+ if (ifp->if_intern_txenqueue == NULL)
+ KERNEL_LOCK(1, NULL);
+
+ error = (*ifp->if_output)(ifp, m, dst, rt);
I do not think always-inline is worth here, seems like nano-optimising,
especially when this routine performs call on a function pointer. Better
code would probably be generated by having:
const bool mpsafe = ifp->if_intern_txenqueue != NULL;
--
Mindaugas
Home |
Main Index |
Thread Index |
Old Index