[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20070212212037.GA18470@hmsreliant.homelinux.net>
Date: Mon, 12 Feb 2007 16:20:37 -0500
From: Neil Horman <nhorman@...driver.com>
To: YOSHIFUJI Hideaki / 吉藤英明
<yoshfuji@...ux-ipv6.org>
Cc: vladislav.yasevich@...com, sri@...ibm.com, davem@...emloft.net,
kuznet@....inr.ac.ru, pekkas@...core.fi, jmorris@...ei.org,
kaber@...eworks.de, netdev@...r.kernel.org
Subject: Re: [PATCH] IPv6: Implement RFC 4429 Optimistic Duplicate Address Detection
>
> New patch attached with these fixes included
>
>
Ping? Any further thoughts here? My (allbeit limited) testing seems to be going
fairly well so far...
Neil
> Thanks & Regards
> Neil
>
> Signed-off-by: Neil Horman <nhorman@...driver.com>
>
>
> include/linux/if_addr.h | 1
> include/linux/ipv6.h | 4 ++
> include/linux/sysctl.h | 1
> include/net/addrconf.h | 4 +-
> net/ipv6/Kconfig | 10 +++++
> net/ipv6/addrconf.c | 90 ++++++++++++++++++++++++++++++++++++++++--------
> net/ipv6/ip6_output.c | 35 ++++++++++++++++++
> net/ipv6/mcast.c | 4 +-
> net/ipv6/ndisc.c | 84 ++++++++++++++++++++++++++++++++------------
> 9 files changed, 192 insertions(+), 41 deletions(-)
>
>
>
>
> diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h
> index d557e4c..43f3bed 100644
> --- a/include/linux/if_addr.h
> +++ b/include/linux/if_addr.h
> @@ -39,6 +39,7 @@ enum
> #define IFA_F_TEMPORARY IFA_F_SECONDARY
>
> #define IFA_F_NODAD 0x02
> +#define IFA_F_OPTIMISTIC 0x04
> #define IFA_F_HOMEADDRESS 0x10
> #define IFA_F_DEPRECATED 0x20
> #define IFA_F_TENTATIVE 0x40
> diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
> index f824113..bf93c1b 100644
> --- a/include/linux/ipv6.h
> +++ b/include/linux/ipv6.h
> @@ -177,6 +177,9 @@ struct ipv6_devconf {
> #endif
> #endif
> __s32 proxy_ndp;
> +#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
> + __s32 optimistic_dad;
> +#endif
> void *sysctl;
> };
>
> @@ -205,6 +208,7 @@ enum {
> DEVCONF_RTR_PROBE_INTERVAL,
> DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN,
> DEVCONF_PROXY_NDP,
> + DEVCONF_OPTIMISTIC_DAD,
> DEVCONF_MAX
> };
>
> diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
> index 81480e6..972a33a 100644
> --- a/include/linux/sysctl.h
> +++ b/include/linux/sysctl.h
> @@ -570,6 +570,7 @@ enum {
> NET_IPV6_RTR_PROBE_INTERVAL=21,
> NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN=22,
> NET_IPV6_PROXY_NDP=23,
> + NET_IPV6_OPTIMISTIC_DAD=24,
> __NET_IPV6_MAX
> };
>
> diff --git a/include/net/addrconf.h b/include/net/addrconf.h
> index 88df8fc..d248a19 100644
> --- a/include/net/addrconf.h
> +++ b/include/net/addrconf.h
> @@ -73,7 +73,9 @@ extern int ipv6_get_saddr(struct dst_entry *dst,
> extern int ipv6_dev_get_saddr(struct net_device *dev,
> struct in6_addr *daddr,
> struct in6_addr *saddr);
> -extern int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *);
> +extern int ipv6_get_lladdr(struct net_device *dev,
> + struct in6_addr *,
> + unsigned char banned_flags);
> extern int ipv6_rcv_saddr_equal(const struct sock *sk,
> const struct sock *sk2);
> extern void addrconf_join_solict(struct net_device *dev,
> diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
> index deb4101..822d3eb 100644
> --- a/net/ipv6/Kconfig
> +++ b/net/ipv6/Kconfig
> @@ -57,6 +57,16 @@ config IPV6_ROUTE_INFO
>
> If unsure, say N.
>
> +config IPV6_OPTIMISTIC_DAD
> + bool "IPv6: Enable RFC 4429 Optimistic DAD (EXPERIMENTAL)"
> + depends on IPV6 && EXPERIMENTAL
> + ---help---
> + This is experimental support for optimistic Duplicate
> + Address Detection. It allows for autoconfigured addresses
> + to be used more quickly.
> +
> + If unsure, say N.
> +
> config INET6_AH
> tristate "IPv6: AH transformation"
> depends on IPV6
> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> index e385469..c884eeb 100644
> --- a/net/ipv6/addrconf.c
> +++ b/net/ipv6/addrconf.c
> @@ -594,6 +594,16 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
>
> ifa->rt = rt;
>
> + /*
> + * part one of RFC 4429, section 3.3
> + * We should not configure an address as
> + * optimistic if we do not yet know the link
> + * layer address of our nexhop router
> + */
> +
> + if (rt->rt6i_nexthop == NULL)
> + ifa->flags &= ~IFA_F_OPTIMISTIC;
> +
> ifa->idev = idev;
> in6_dev_hold(idev);
> /* For caller */
> @@ -770,6 +780,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i
> int tmp_plen;
> int ret = 0;
> int max_addresses;
> + u32 addr_flags;
>
> write_lock(&idev->lock);
> if (ift) {
> @@ -827,10 +838,17 @@ retry:
> spin_unlock_bh(&ifp->lock);
>
> write_unlock(&idev->lock);
> +
> + addr_flags = IFA_F_TEMPORARY;
> + /* set in addrconf_prefix_rcv() */
> + if (ifp->flags & IFA_F_OPTIMISTIC)
> + addr_flags |= IFA_F_OPTIMISTIC;
> +
> ift = !max_addresses ||
> ipv6_count_addresses(idev) < max_addresses ?
> ipv6_add_addr(idev, &addr, tmp_plen,
> - ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, IFA_F_TEMPORARY) : NULL;
> + ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK,
> + addr_flags) : NULL;
> if (!ift || IS_ERR(ift)) {
> in6_ifa_put(ifp);
> in6_dev_put(idev);
> @@ -962,13 +980,14 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
> * - Tentative Address (RFC2462 section 5.4)
> * - A tentative address is not considered
> * "assigned to an interface" in the traditional
> - * sense.
> + * sense, unless it is also flagged as optimistic.
> * - Candidate Source Address (section 4)
> * - In any case, anycast addresses, multicast
> * addresses, and the unspecified address MUST
> * NOT be included in a candidate set.
> */
> - if (ifa->flags & IFA_F_TENTATIVE)
> + if ((ifa->flags & IFA_F_TENTATIVE) &&
> + (!(ifa->flags & IFA_F_OPTIMISTIC)))
> continue;
> if (unlikely(score.addr_type == IPV6_ADDR_ANY ||
> score.addr_type & IPV6_ADDR_MULTICAST)) {
> @@ -1027,15 +1046,17 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
> }
> }
>
> - /* Rule 3: Avoid deprecated address */
> + /* Rule 3: Avoid deprecated and optimistic addresses */
> if (hiscore.rule < 3) {
> if (ipv6_saddr_preferred(hiscore.addr_type) ||
> - !(ifa_result->flags & IFA_F_DEPRECATED))
> + (((ifa_result->flags &
> + (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0)))
> hiscore.attrs |= IPV6_SADDR_SCORE_PREFERRED;
> hiscore.rule++;
> }
> if (ipv6_saddr_preferred(score.addr_type) ||
> - !(ifa->flags & IFA_F_DEPRECATED)) {
> + (((ifa_result->flags &
> + (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0))) {
> score.attrs |= IPV6_SADDR_SCORE_PREFERRED;
> if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) {
> score.rule = 3;
> @@ -1174,7 +1195,8 @@ int ipv6_get_saddr(struct dst_entry *dst,
> }
>
>
> -int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr)
> +int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
> + unsigned char banned_flags)
> {
> struct inet6_dev *idev;
> int err = -EADDRNOTAVAIL;
> @@ -1185,7 +1207,7 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr)
>
> read_lock_bh(&idev->lock);
> for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
> - if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) {
> + if (ifp->scope == IFA_LINK && !(ifp->flags & banned_flags)) {
> ipv6_addr_copy(addr, &ifp->addr);
> err = 0;
> break;
> @@ -1735,6 +1757,13 @@ ok:
>
> if (ifp == NULL && valid_lft) {
> int max_addresses = in6_dev->cnf.max_addresses;
> + u32 addr_flags = 0;
> +
> +#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
> + if (in6_dev->cnf.optimistic_dad &&
> + !ipv6_devconf.forwarding)
> + addr_flags = IFA_F_OPTIMISTIC;
> +#endif
>
> /* Do not allow to create too much of autoconfigured
> * addresses; this would be too easy way to crash kernel.
> @@ -1742,7 +1771,8 @@ ok:
> if (!max_addresses ||
> ipv6_count_addresses(in6_dev) < max_addresses)
> ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len,
> - addr_type&IPV6_ADDR_SCOPE_MASK, 0);
> + addr_type&IPV6_ADDR_SCOPE_MASK,
> + addr_flags);
>
> if (!ifp || IS_ERR(ifp)) {
> in6_dev_put(in6_dev);
> @@ -1945,7 +1975,11 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
> ifp->prefered_lft = prefered_lft;
> ifp->tstamp = jiffies;
> spin_unlock_bh(&ifp->lock);
> -
> + /*
> + * Note that section 3.1 of RFC 4429 indicates
> + * that the Optimistic flag should not be set for
> + * manually configured addresses
> + */
> addrconf_dad_start(ifp, 0);
> in6_ifa_put(ifp);
> addrconf_verify(0);
> @@ -2122,8 +2156,16 @@ static void init_loopback(struct net_device *dev)
> static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr)
> {
> struct inet6_ifaddr * ifp;
> + u32 addr_flags = IFA_F_PERMANENT;
>
> - ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT);
> +#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
> + if (idev->cnf.optimistic_dad &&
> + !ipv6_devconf.forwarding)
> + addr_flags |= IFA_F_OPTIMISTIC;
> +#endif
> +
> +
> + ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, addr_flags);
> if (!IS_ERR(ifp)) {
> addrconf_dad_start(ifp, 0);
> in6_ifa_put(ifp);
> @@ -2190,7 +2232,7 @@ ipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev)
> {
> struct in6_addr lladdr;
>
> - if (!ipv6_get_lladdr(link_dev, &lladdr)) {
> + if (!ipv6_get_lladdr(link_dev, &lladdr, IFA_F_TENTATIVE)) {
> addrconf_add_linklocal(idev, &lladdr);
> return 0;
> }
> @@ -2527,7 +2569,11 @@ static void addrconf_dad_kick(struct inet6_ifaddr *ifp)
> unsigned long rand_num;
> struct inet6_dev *idev = ifp->idev;
>
> - rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1);
> + if (ifp->flags & IFA_F_OPTIMISTIC)
> + rand_num = 0;
> + else
> + rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1);
> +
> ifp->probes = idev->cnf.dad_transmits;
> addrconf_mod_timer(ifp, AC_DAD, rand_num);
> }
> @@ -2553,7 +2599,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
> if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
> !(ifp->flags&IFA_F_TENTATIVE) ||
> ifp->flags & IFA_F_NODAD) {
> - ifp->flags &= ~IFA_F_TENTATIVE;
> + ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC);
> spin_unlock_bh(&ifp->lock);
> read_unlock_bh(&idev->lock);
>
> @@ -2597,7 +2643,7 @@ static void addrconf_dad_timer(unsigned long data)
> * DAD was successful
> */
>
> - ifp->flags &= ~IFA_F_TENTATIVE;
> + ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC);
> spin_unlock_bh(&ifp->lock);
> read_unlock_bh(&idev->lock);
>
> @@ -3398,6 +3444,9 @@ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf,
> #endif
> #endif
> array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp;
> +#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
> + array[DEVCONF_OPTIMISTIC_DAD] = cnf->optimistic_dad;
> +#endif
> }
>
> static inline size_t inet6_if_nlmsg_size(void)
> @@ -3917,6 +3966,17 @@ static struct addrconf_sysctl_table
> .mode = 0644,
> .proc_handler = &proc_dointvec,
> },
> +#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
> + {
> + .ctl_name = NET_IPV6_OPTIMISTIC_DAD,
> + .procname = "optimistic_dad",
> + .data = &ipv6_devconf.optimistic_dad,
> + .maxlen = sizeof(int),
> + .mode = 0644,
> + .proc_handler = &proc_dointvec,
> +
> + },
> +#endif
> {
> .ctl_name = 0, /* sentinel */
> }
> diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
> index 7b7bd44..df13fc8 100644
> --- a/net/ipv6/ip6_output.c
> +++ b/net/ipv6/ip6_output.c
> @@ -861,6 +861,41 @@ static int ip6_dst_lookup_tail(struct sock *sk,
> goto out_err_release;
> }
>
> +#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
> + /*
> + * Here if the dst entry we've looked up
> + * has a neighbour entry that is in the INCOMPLETE
> + * state and the src address from the flow is
> + * marked as OPTIMISTIC, we release the found
> + * dst entry and replace it instead with the
> + * dst entry of the nexthop router
> + */
> + if (!((*dst)->neighbour->nud_state & NUD_VALID)) {
> + struct inet6_ifaddr *ifp;
> + struct flowi fl_gw;
> + int redirect;
> +
> + ifp = ipv6_get_ifaddr(&fl->fl6_src, (*dst)->dev, 1);
> +
> + redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC);
> + if (ifp)
> + in6_ifa_put(ifp);
> +
> + if (redirect) {
> + /*
> + * We need to get the dst entry for the
> + * default router instead
> + */
> + dst_release(*dst);
> + memcpy(&fl_gw, fl, sizeof(struct flowi));
> + memset(&fl_gw.fl6_dst, 0, sizeof(struct in6_addr));
> + *dst = ip6_route_output(sk, &fl_gw);
> + if ((err = (*dst)->error))
> + goto out_err_release;
> + }
> + }
> +#endif
> +
> return 0;
>
> out_err_release:
> diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
> index 882cde4..9c5273c 100644
> --- a/net/ipv6/mcast.c
> +++ b/net/ipv6/mcast.c
> @@ -1411,7 +1411,7 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size)
>
> skb_reserve(skb, LL_RESERVED_SPACE(dev));
>
> - if (ipv6_get_lladdr(dev, &addr_buf)) {
> + if (ipv6_get_lladdr(dev, &addr_buf, IFA_F_TENTATIVE)) {
> /* <draft-ietf-magma-mld-source-05.txt>:
> * use unspecified address as the source address
> * when a valid link-local address is not available.
> @@ -1789,7 +1789,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
>
> skb_reserve(skb, LL_RESERVED_SPACE(dev));
>
> - if (ipv6_get_lladdr(dev, &addr_buf)) {
> + if (ipv6_get_lladdr(dev, &addr_buf, IFA_F_TENTATIVE)) {
> /* <draft-ietf-magma-mld-source-05.txt>:
> * use unspecified address as the source address
> * when a valid link-local address is not available.
> diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
> index 39bb658..98913c4 100644
> --- a/net/ipv6/ndisc.c
> +++ b/net/ipv6/ndisc.c
> @@ -447,6 +447,8 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
> ifp = ipv6_get_ifaddr(solicited_addr, dev, 1);
> if (ifp) {
> src_addr = solicited_addr;
> + if (ifp->flags & IFA_F_OPTIMISTIC)
> + override = 0;
> in6_ifa_put(ifp);
> } else {
> if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr))
> @@ -542,7 +544,8 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
> int send_llinfo;
>
> if (saddr == NULL) {
> - if (ipv6_get_lladdr(dev, &addr_buf))
> + if (ipv6_get_lladdr(dev, &addr_buf,
> + (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
> return;
> saddr = &addr_buf;
> }
> @@ -622,9 +625,33 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
> struct sk_buff *skb;
> struct icmp6hdr *hdr;
> __u8 * opt;
> + struct inet6_ifaddr *ifp;
> + int send_sllao = dev->addr_len;
> int len;
> int err;
>
> +
> +#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
> + /*
> + * According to section 2.2 of RFC 4429, we must not
> + * send router solicitations with a sllao from
> + * optimistic addresses, but we may send the solicitation
> + * if we don't include the sllao. So here we check
> + * if our address is optimistic, and if so, we
> + * supress the inclusion of the sllao.
> + */
> + if (send_sllao) {
> + ifp = ipv6_get_ifaddr(saddr, dev, 1);
> + if (ifp) {
> + if (ifp->flags & IFA_F_OPTIMISTIC) {
> + send_sllao=0;
> + in6_ifa_put(ifp);
> + }
> + } else {
> + send_sllao = 0;
> + }
> + }
> +#endif
> ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr,
> dev->ifindex);
>
> @@ -637,7 +664,7 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
> return;
>
> len = sizeof(struct icmp6hdr);
> - if (dev->addr_len)
> + if (send_sllao)
> len += ndisc_opt_addr_space(dev);
>
> skb = sock_alloc_send_skb(sk,
> @@ -664,7 +691,7 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
>
> opt = (u8*) (hdr + 1);
>
> - if (dev->addr_len)
> + if (send_sllao)
> ndisc_fill_addr_option(opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr,
> dev->addr_len, dev->type);
>
> @@ -796,28 +823,39 @@ static void ndisc_recv_ns(struct sk_buff *skb)
> inc = ipv6_addr_is_multicast(daddr);
>
> if ((ifp = ipv6_get_ifaddr(&msg->target, dev, 1)) != NULL) {
> - if (ifp->flags & IFA_F_TENTATIVE) {
> - /* Address is tentative. If the source
> - is unspecified address, it is someone
> - does DAD, otherwise we ignore solicitations
> - until DAD timer expires.
> - */
> - if (!dad)
> +
> + if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
> + if (dad) {
> + if (dev->type == ARPHRD_IEEE802_TR) {
> + unsigned char *sadr = skb->mac.raw;
> + if (((sadr[8] ^ dev->dev_addr[0]) & 0x7f) == 0 &&
> + sadr[9] == dev->dev_addr[1] &&
> + sadr[10] == dev->dev_addr[2] &&
> + sadr[11] == dev->dev_addr[3] &&
> + sadr[12] == dev->dev_addr[4] &&
> + sadr[13] == dev->dev_addr[5]) {
> + /* looped-back to us */
> + goto out;
> + }
> + }
> +
> + /*
> + * We are colliding with another node
> + * who is doing DAD
> + * so fail our DAD process
> + */
> + addrconf_dad_failure(ifp);
> goto out;
> - if (dev->type == ARPHRD_IEEE802_TR) {
> - unsigned char *sadr = skb->mac.raw;
> - if (((sadr[8] ^ dev->dev_addr[0]) & 0x7f) == 0 &&
> - sadr[9] == dev->dev_addr[1] &&
> - sadr[10] == dev->dev_addr[2] &&
> - sadr[11] == dev->dev_addr[3] &&
> - sadr[12] == dev->dev_addr[4] &&
> - sadr[13] == dev->dev_addr[5]) {
> - /* looped-back to us */
> + } else {
> + /*
> + * This is not a dad solicitation.
> + * If we are an optimistic node,
> + * we should respond.
> + * Otherwise, we should ignore it.
> + */
> + if (!(ifp->flags & IFA_F_OPTIMISTIC))
> goto out;
> - }
> }
> - addrconf_dad_failure(ifp);
> - return;
> }
>
> idev = ifp->idev;
> @@ -1406,7 +1444,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
>
> dev = skb->dev;
>
> - if (ipv6_get_lladdr(dev, &saddr_buf)) {
> + if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
> ND_PRINTK2(KERN_WARNING
> "ICMPv6 Redirect: no link-local address on %s\n",
> dev->name);
> -
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@...r.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists