* [PATCH net-next v2] ipv6: Do not iterate over all interfaces when finding source address on specific interface.
@ 2015-07-10 7:58 YOSHIFUJI Hideaki/吉藤英明
2015-07-11 6:19 ` David Miller
0 siblings, 1 reply; 7+ messages in thread
From: YOSHIFUJI Hideaki/吉藤英明 @ 2015-07-10 7:58 UTC (permalink / raw)
To: davem, netdev, ek; +Cc: hannes, lorenzo, hideaki.yoshifuji
If outgoing interface is specified and the candidate address is
restricted to the outgoing interface, it is enough to iterate
over that given interface only.
Signed-off-by: YOSHIFUJI Hideaki <hideaki.yoshifuji@miraclelinux.com>
Acked-by: Erik Kline <ek@google.com>
---
net/ipv6/addrconf.c | 197 ++++++++++++++++++++++++++++------------------------
1 file changed, 107 insertions(+), 90 deletions(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 21c2c81..4ab74d5 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,35 @@ 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.)
+ */
+ 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
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH net-next v2] ipv6: Do not iterate over all interfaces when finding source address on specific interface.
2015-07-10 7:58 [PATCH net-next v2] ipv6: Do not iterate over all interfaces when finding source address on specific interface YOSHIFUJI Hideaki/吉藤英明
@ 2015-07-11 6:19 ` David Miller
2015-07-11 9:21 ` Erik Kline
0 siblings, 1 reply; 7+ messages in thread
From: David Miller @ 2015-07-11 6:19 UTC (permalink / raw)
To: hideaki.yoshifuji; +Cc: netdev, ek, hannes, lorenzo
From: YOSHIFUJI Hideaki/吉藤英明 <hideaki.yoshifuji@miraclelinux.com>
Date: Fri, 10 Jul 2015 16:58:31 +0900
> If outgoing interface is specified and the candidate address is
> restricted to the outgoing interface, it is enough to iterate
> over that given interface only.
>
> Signed-off-by: YOSHIFUJI Hideaki <hideaki.yoshifuji@miraclelinux.com>
> Acked-by: Erik Kline <ek@google.com>
Applied, thanks!
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net-next v2] ipv6: Do not iterate over all interfaces when finding source address on specific interface.
2015-07-11 6:19 ` David Miller
@ 2015-07-11 9:21 ` Erik Kline
2015-07-13 6:32 ` YOSHIFUJI Hideaki
0 siblings, 1 reply; 7+ messages in thread
From: Erik Kline @ 2015-07-11 9:21 UTC (permalink / raw)
To: David Miller
Cc: 吉藤英明,
netdev, Hannes Frederic Sowa, Lorenzo Colitti
Hmm, when I run a UML linux with this patch (which, I'm ashamed to
say, I failed to do before) I get these kinds of errors:
unregister_netdevice: waiting for <TAPdevice> to become free.
Usage count = 1
unregister_netdevice: waiting for <TAPdevice> to become free.
Usage count = 1
Perhaps they're unrelated... I'm still investigating.
On 11 July 2015 at 15:19, David Miller <davem@davemloft.net> wrote:
> From: YOSHIFUJI Hideaki/吉藤英明 <hideaki.yoshifuji@miraclelinux.com>
> Date: Fri, 10 Jul 2015 16:58:31 +0900
>
>> If outgoing interface is specified and the candidate address is
>> restricted to the outgoing interface, it is enough to iterate
>> over that given interface only.
>>
>> Signed-off-by: YOSHIFUJI Hideaki <hideaki.yoshifuji@miraclelinux.com>
>> Acked-by: Erik Kline <ek@google.com>
>
> Applied, thanks!
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net-next v2] ipv6: Do not iterate over all interfaces when finding source address on specific interface.
2015-07-11 9:21 ` Erik Kline
@ 2015-07-13 6:32 ` YOSHIFUJI Hideaki
2015-07-13 8:38 ` Erik Kline
0 siblings, 1 reply; 7+ messages in thread
From: YOSHIFUJI Hideaki @ 2015-07-13 6:32 UTC (permalink / raw)
To: Erik Kline, David Miller
Cc: hideaki.yoshifuji, netdev, Hannes Frederic Sowa, Lorenzo Colitti
[-- Attachment #1: Type: text/plain, Size: 1049 bytes --]
Hi,
Erik Kline wrote:
> Hmm, when I run a UML linux with this patch (which, I'm ashamed to
> say, I failed to do before) I get these kinds of errors:
>
> unregister_netdevice: waiting for <TAPdevice> to become free.
> Usage count = 1
> unregister_netdevice: waiting for <TAPdevice> to become free.
> Usage count = 1
>
> Perhaps they're unrelated... I'm still investigating.
Would you test attached patch please?
--yoshfuji
>
> On 11 July 2015 at 15:19, David Miller <davem@davemloft.net> wrote:
>> From: YOSHIFUJI Hideaki/吉藤英明 <hideaki.yoshifuji@miraclelinux.com>
>> Date: Fri, 10 Jul 2015 16:58:31 +0900
>>
>>> If outgoing interface is specified and the candidate address is
>>> restricted to the outgoing interface, it is enough to iterate
>>> over that given interface only.
>>>
>>> Signed-off-by: YOSHIFUJI Hideaki <hideaki.yoshifuji@miraclelinux.com>
>>> Acked-by: Erik Kline <ek@google.com>
>>
>> Applied, thanks!
--
Hideaki Yoshifuji <hideaki.yoshifuji@miraclelinux.com>
Technical Division, MIRACLE LINUX CORPORATION
[-- Attachment #2: 0001-ipv6-Avoid-NULL-pointer-dereference-in-__ipv6_dev_ge.patch --]
[-- Type: text/x-diff, Size: 1235 bytes --]
>From 38c5a10a5876ea47766ffc05b5a131a210d6e1aa Mon Sep 17 00:00:00 2001
From: YOSHIFUJI Hideaki <hideaki.yoshifuji@miraclelinux.com>
Date: Mon, 13 Jul 2015 15:23:02 +0900
Subject: [PATCH] ipv6: Avoid NULL pointer dereference in
__ipv6_dev_get_saddr().
Commit 9131f3de2 ("ipv6: Do not iterate over all interfaces when
finding source address on specific interface.") introduced
possible NULL pointer dereference if outgoing device is
specified.
Fixes: 9131f3de24db4dc12199aede7d931e6703e97f3b ("ipv6: Do not
iterate over all interfaces when finding source address
on specific interface.")
Signed-off-by: YOSHIFUJI Hideaki <hideaki.yoshifuji@miraclelinux.com>
---
net/ipv6/addrconf.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 4ab74d5..50ad476 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1480,7 +1480,8 @@ int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev,
}
if (use_oif_addr) {
- __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores);
+ if (idev)
+ __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores);
} else {
for_each_netdev_rcu(net, dev) {
idev = __in6_dev_get(dev);
--
1.9.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH net-next v2] ipv6: Do not iterate over all interfaces when finding source address on specific interface.
2015-07-13 6:32 ` YOSHIFUJI Hideaki
@ 2015-07-13 8:38 ` Erik Kline
2015-07-13 10:55 ` Hajime Tazaki
0 siblings, 1 reply; 7+ messages in thread
From: Erik Kline @ 2015-07-13 8:38 UTC (permalink / raw)
To: YOSHIFUJI Hideaki
Cc: David Miller, netdev, Hannes Frederic Sowa, Lorenzo Colitti
On 13 July 2015 at 15:32, YOSHIFUJI Hideaki
<hideaki.yoshifuji@miraclelinux.com> wrote:
> Hi,
>
> Erik Kline wrote:
>> Hmm, when I run a UML linux with this patch (which, I'm ashamed to
>> say, I failed to do before) I get these kinds of errors:
>>
>> unregister_netdevice: waiting for <TAPdevice> to become free.
>> Usage count = 1
>> unregister_netdevice: waiting for <TAPdevice> to become free.
>> Usage count = 1
>>
>> Perhaps they're unrelated... I'm still investigating.
>
> Would you test attached patch please?
That does look logically correct, so +1 to it regardless, but it does
not seem to have fixed the issue I'm seeing.
I still haven't produced the smallest possible demo test program.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net-next v2] ipv6: Do not iterate over all interfaces when finding source address on specific interface.
2015-07-13 8:38 ` Erik Kline
@ 2015-07-13 10:55 ` Hajime Tazaki
2015-07-13 13:49 ` YOSHIFUJI Hideaki
0 siblings, 1 reply; 7+ messages in thread
From: Hajime Tazaki @ 2015-07-13 10:55 UTC (permalink / raw)
To: ek; +Cc: hideaki.yoshifuji, davem, netdev, hannes, lorenzo
Yoshifuji-san,
At Mon, 13 Jul 2015 17:38:48 +0900,
Erik Kline wrote:
>
> On 13 July 2015 at 15:32, YOSHIFUJI Hideaki
> <hideaki.yoshifuji@miraclelinux.com> wrote:
> > Hi,
> >
> > Erik Kline wrote:
> >> Hmm, when I run a UML linux with this patch (which, I'm ashamed to
> >> say, I failed to do before) I get these kinds of errors:
> >>
> >> unregister_netdevice: waiting for <TAPdevice> to become free.
> >> Usage count = 1
> >> unregister_netdevice: waiting for <TAPdevice> to become free.
> >> Usage count = 1
> >>
> >> Perhaps they're unrelated... I'm still investigating.
> >
> > Would you test attached patch please?
>
> That does look logically correct, so +1 to it regardless, but it does
> not seem to have fixed the issue I'm seeing.
>
> I still haven't produced the smallest possible demo test program.
sorry to jump-in, but there is a side-effect with this
patch, which my tcp and dccp tests (ipv6) are failed.
because newly added function (__ipv6_dev_get_saddr) won't
update a variable 'hiscore' (it swaps with 'score' in some
case), the caller (ipv6_dev_get_saddr) can't fill an
appropriate saddr in the end.
I don't know if this is a good patch but the following diff
makes my test happy.
-- Hajime
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 4ab74d5..c4e9416 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1363,7 +1363,8 @@ static void __ipv6_dev_get_saddr(struct net *net,
unsigned int prefs,
const struct in6_addr *saddr,
struct inet6_dev *idev,
- struct ipv6_saddr_score *scores)
+ struct ipv6_saddr_score *scores,
+ struct ipv6_saddr_score **in_hiscore)
{
struct ipv6_saddr_score *score = &scores[0], *hiscore = &scores[1];
@@ -1424,6 +1425,7 @@ static void __ipv6_dev_get_saddr(struct net *net,
in6_ifa_hold(score->ifa);
swap(hiscore, score);
+ *in_hiscore = hiscore;
/* restore our iterator */
score->ifa = hiscore->ifa;
@@ -1480,13 +1482,15 @@ int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev,
}
if (use_oif_addr) {
- __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores);
+ __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev,
+ scores, &hiscore);
} else {
for_each_netdev_rcu(net, dev) {
idev = __in6_dev_get(dev);
if (!idev)
continue;
- __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores);
+ __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev,
+ scores, &hiscore);
}
}
rcu_read_unlock();
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH net-next v2] ipv6: Do not iterate over all interfaces when finding source address on specific interface.
2015-07-13 10:55 ` Hajime Tazaki
@ 2015-07-13 13:49 ` YOSHIFUJI Hideaki
0 siblings, 0 replies; 7+ messages in thread
From: YOSHIFUJI Hideaki @ 2015-07-13 13:49 UTC (permalink / raw)
To: Hajime Tazaki, ek; +Cc: hideaki.yoshifuji, davem, netdev, hannes, lorenzo
Hi,
Hajime Tazaki wrote:
>
> Yoshifuji-san,
>
> At Mon, 13 Jul 2015 17:38:48 +0900,
> Erik Kline wrote:
>>
>> On 13 July 2015 at 15:32, YOSHIFUJI Hideaki
>> <hideaki.yoshifuji@miraclelinux.com> wrote:
>>> Hi,
>>>
>>> Erik Kline wrote:
>>>> Hmm, when I run a UML linux with this patch (which, I'm ashamed to
>>>> say, I failed to do before) I get these kinds of errors:
>>>>
>>>> unregister_netdevice: waiting for <TAPdevice> to become free.
>>>> Usage count = 1
>>>> unregister_netdevice: waiting for <TAPdevice> to become free.
>>>> Usage count = 1
>>>>
>>>> Perhaps they're unrelated... I'm still investigating.
>>>
>>> Would you test attached patch please?
>>
>> That does look logically correct, so +1 to it regardless, but it does
>> not seem to have fixed the issue I'm seeing.
>>
>> I still haven't produced the smallest possible demo test program.
>
> sorry to jump-in, but there is a side-effect with this
> patch, which my tcp and dccp tests (ipv6) are failed.
>
> because newly added function (__ipv6_dev_get_saddr) won't
> update a variable 'hiscore' (it swaps with 'score' in some
> case), the caller (ipv6_dev_get_saddr) can't fill an
> appropriate saddr in the end.
>
> I don't know if this is a good patch but the following diff
> makes my test happy.
We should update score as well...
>
> -- Hajime
>
> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> index 4ab74d5..c4e9416 100644
> --- a/net/ipv6/addrconf.c
> +++ b/net/ipv6/addrconf.c
> @@ -1363,7 +1363,8 @@ static void __ipv6_dev_get_saddr(struct net *net,
> unsigned int prefs,
> const struct in6_addr *saddr,
> struct inet6_dev *idev,
> - struct ipv6_saddr_score *scores)
> + struct ipv6_saddr_score *scores,
> + struct ipv6_saddr_score **in_hiscore)
> {
> struct ipv6_saddr_score *score = &scores[0], *hiscore = &scores[1];
>
> @@ -1424,6 +1425,7 @@ static void __ipv6_dev_get_saddr(struct net *net,
> in6_ifa_hold(score->ifa);
>
> swap(hiscore, score);
> + *in_hiscore = hiscore;
>
> /* restore our iterator */
> score->ifa = hiscore->ifa;
> @@ -1480,13 +1482,15 @@ int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev,
> }
>
> if (use_oif_addr) {
> - __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores);
> + __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev,
> + scores, &hiscore);
> } else {
> for_each_netdev_rcu(net, dev) {
> idev = __in6_dev_get(dev);
> if (!idev)
> continue;
> - __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores);
> + __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev,
> + scores, &hiscore);
> }
> }
> rcu_read_unlock();
>
--
Hideaki Yoshifuji <hideaki.yoshifuji@miraclelinux.com>
Technical Division, MIRACLE LINUX CORPORATION
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2015-07-13 13:49 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-10 7:58 [PATCH net-next v2] ipv6: Do not iterate over all interfaces when finding source address on specific interface YOSHIFUJI Hideaki/吉藤英明
2015-07-11 6:19 ` David Miller
2015-07-11 9:21 ` Erik Kline
2015-07-13 6:32 ` YOSHIFUJI Hideaki
2015-07-13 8:38 ` Erik Kline
2015-07-13 10:55 ` Hajime Tazaki
2015-07-13 13:49 ` YOSHIFUJI Hideaki
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).