[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAAedzxpD7EEV-3BXdGA72wqwxM1b0tge0iqBKehfZG4KvRjYrQ@mail.gmail.com>
Date: Fri, 10 Jul 2015 16:19:24 +0900
From: Erik Kline <ek@...gle.com>
To: YOSHIFUJI Hideaki/吉藤英明
<hideaki.yoshifuji@...aclelinux.com>
Cc: David Miller <davem@...emloft.net>,
netdev <netdev@...r.kernel.org>,
Hannes Frederic Sowa <hannes@...essinduktion.org>,
Lorenzo Colitti <lorenzo@...gle.com>
Subject: Re: [PATCH net-next] ipv6: Do not iterate over all interfaces when
finding source address on specific interface.
On 10 July 2015 at 15:50, YOSHIFUJI Hideaki/吉藤英明
<hideaki.yoshifuji@...aclelinux.com> wrote:
> If outgoing interface is specified and the candidate addresses
> are restricted to the outgoing interface, it is enough to iterate
> over that given interface only.
>
> Signed-off-by: YOSHIFUJI Hideaki <hideaki.yoshifuji@...aclelinux.com>
> ---
> net/ipv6/addrconf.c | 201 +++++++++++++++++++++++++++++-----------------------
> 1 file changed, 111 insertions(+), 90 deletions(-)
>
> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> index 21c2c81..b4c82d8 100644
> --- a/net/ipv6/addrconf.c
> +++ b/net/ipv6/addrconf.c
> @@ -1358,15 +1358,94 @@ out:
> return ret;
> }
>
> +static void __ipv6_dev_get_saddr(struct net *net,
> + struct ipv6_saddr_dst *dst,
> + unsigned int prefs,
> + const struct in6_addr *saddr,
> + struct inet6_dev *idev,
> + struct ipv6_saddr_score *scores)
> +{
> + struct ipv6_saddr_score *score = &scores[0], *hiscore = &scores[1];
> +
> + read_lock_bh(&idev->lock);
> + list_for_each_entry(score->ifa, &idev->addr_list, if_list) {
> + int i;
> +
> + /*
> + * - Tentative Address (RFC2462 section 5.4)
> + * - A tentative address is not considered
> + * "assigned to an interface" in the traditional
> + * 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 ((score->ifa->flags & IFA_F_TENTATIVE) &&
> + (!(score->ifa->flags & IFA_F_OPTIMISTIC)))
> + continue;
> +
> + score->addr_type = __ipv6_addr_type(&score->ifa->addr);
> +
> + if (unlikely(score->addr_type == IPV6_ADDR_ANY ||
> + score->addr_type & IPV6_ADDR_MULTICAST)) {
> + net_dbg_ratelimited("ADDRCONF: unspecified / multicast address assigned as unicast address on %s",
> + idev->dev->name);
> + continue;
> + }
> +
> + score->rule = -1;
> + bitmap_zero(score->scorebits, IPV6_SADDR_RULE_MAX);
> +
> + for (i = 0; i < IPV6_SADDR_RULE_MAX; i++) {
> + int minihiscore, miniscore;
> +
> + minihiscore = ipv6_get_saddr_eval(net, hiscore, dst, i);
> + miniscore = ipv6_get_saddr_eval(net, score, dst, i);
> +
> + if (minihiscore > miniscore) {
> + if (i == IPV6_SADDR_RULE_SCOPE &&
> + score->scopedist > 0) {
> + /*
> + * special case:
> + * each remaining entry
> + * has too small (not enough)
> + * scope, because ifa entries
> + * are sorted by their scope
> + * values.
> + */
> + goto out;
> + }
> + break;
> + } else if (minihiscore < miniscore) {
> + if (hiscore->ifa)
> + in6_ifa_put(hiscore->ifa);
> +
> + in6_ifa_hold(score->ifa);
> +
> + swap(hiscore, score);
> +
> + /* restore our iterator */
> + score->ifa = hiscore->ifa;
> +
> + break;
> + }
> + }
> + }
> +out:
> + read_unlock_bh(&idev->lock);
> +}
> +
> int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev,
> const struct in6_addr *daddr, unsigned int prefs,
> struct in6_addr *saddr)
> {
> - struct ipv6_saddr_score scores[2],
> - *score = &scores[0], *hiscore = &scores[1];
> + struct ipv6_saddr_score scores[2], *hiscore = &scores[1];
> struct ipv6_saddr_dst dst;
> + struct inet6_dev *idev;
> struct net_device *dev;
> int dst_type;
> + bool use_oif_addr = false;
>
> dst_type = __ipv6_addr_type(daddr);
> dst.addr = daddr;
> @@ -1380,97 +1459,39 @@ int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev,
>
> rcu_read_lock();
>
> - for_each_netdev_rcu(net, dev) {
> - struct inet6_dev *idev;
> -
> - /* Candidate Source Address (section 4)
> - * - multicast and link-local destination address,
> - * the set of candidate source address MUST only
> - * include addresses assigned to interfaces
> - * belonging to the same link as the outgoing
> - * interface.
> - * (- For site-local destination addresses, the
> - * set of candidate source addresses MUST only
> - * include addresses assigned to interfaces
> - * belonging to the same site as the outgoing
> - * interface.)
> - */
> - if (((dst_type & IPV6_ADDR_MULTICAST) ||
> - dst.scope <= IPV6_ADDR_SCOPE_LINKLOCAL) &&
> - dst.ifindex && dev->ifindex != dst.ifindex)
> - continue;
> -
> - idev = __in6_dev_get(dev);
> - if (!idev)
> - continue;
> -
> - read_lock_bh(&idev->lock);
> - list_for_each_entry(score->ifa, &idev->addr_list, if_list) {
> - int i;
> -
> - /*
> - * - Tentative Address (RFC2462 section 5.4)
> - * - A tentative address is not considered
> - * "assigned to an interface" in the traditional
> - * 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 ((score->ifa->flags & IFA_F_TENTATIVE) &&
> - (!(score->ifa->flags & IFA_F_OPTIMISTIC)))
> - continue;
> -
> - score->addr_type = __ipv6_addr_type(&score->ifa->addr);
> + /* Candidate Source Address (section 4)
> + * - multicast and link-local destination address,
> + * the set of candidate source address MUST only
> + * include addresses assigned to interfaces
> + * belonging to the same link as the outgoing
> + * interface.
> + * (- For site-local destination addresses, the
> + * set of candidate source addresses MUST only
> + * include addresses assigned to interfaces
> + * belonging to the same site as the outgoing
> + * interface.)
> + * - "It is RECOMMENDED that the candidate source addresses
> + * be the set of unicast addresses assigned to the
> + * interface that will be used to send to the destination
> + * (the 'outgoing' interface)." (RFC 6724)
> + */
> + if (dst_dev) {
> + if ((dst_type & IPV6_ADDR_MULTICAST) ||
> + dst.scope <= IPV6_ADDR_SCOPE_LINKLOCAL) {
> + idev = __in6_dev_get(dst_dev);
> + use_oif_addr = true;
> + }
> + }
>
> - if (unlikely(score->addr_type == IPV6_ADDR_ANY ||
> - score->addr_type & IPV6_ADDR_MULTICAST)) {
> - net_dbg_ratelimited("ADDRCONF: unspecified / multicast address assigned as unicast address on %s",
> - dev->name);
> + if (use_oif_addr) {
> + __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores);
> + } else {
> + for_each_netdev_rcu(net, dev) {
> + idev = __in6_dev_get(dev);
> + if (!idev)
> continue;
> - }
> -
> - score->rule = -1;
> - bitmap_zero(score->scorebits, IPV6_SADDR_RULE_MAX);
> -
> - for (i = 0; i < IPV6_SADDR_RULE_MAX; i++) {
> - int minihiscore, miniscore;
> -
> - minihiscore = ipv6_get_saddr_eval(net, hiscore, &dst, i);
> - miniscore = ipv6_get_saddr_eval(net, score, &dst, i);
> -
> - if (minihiscore > miniscore) {
> - if (i == IPV6_SADDR_RULE_SCOPE &&
> - score->scopedist > 0) {
> - /*
> - * special case:
> - * each remaining entry
> - * has too small (not enough)
> - * scope, because ifa entries
> - * are sorted by their scope
> - * values.
> - */
> - goto try_nextdev;
> - }
> - break;
> - } else if (minihiscore < miniscore) {
> - if (hiscore->ifa)
> - in6_ifa_put(hiscore->ifa);
> -
> - in6_ifa_hold(score->ifa);
> -
> - swap(hiscore, score);
> -
> - /* restore our iterator */
> - score->ifa = hiscore->ifa;
> -
> - break;
> - }
> - }
> + __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores);
> }
> -try_nextdev:
> - read_unlock_bh(&idev->lock);
> }
> rcu_read_unlock();
>
> --
> 1.9.1
>
LGTM, and thanks again.
Acked-by: Erik Kline <ek@...gle.com>
--
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