ipv6: Do not iterate over all interfaces when finding source address on specific interface.
Subsystems (3)
PATCH 1/1 ipv6: Do not iterate over all interfaces when finding source address on specific interface.
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 <[email protected]>
--- net/ipv6/addrconf.c | 201 +++++++++++++++++++++++++++++----------------------- 1 file changed, 111 insertions(+), 90 deletions(-)
net/ipv6/addrconf.c +111 -90
@@ -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 ();
Signature · 1 line
1.9.1
Quoted 239 lines · YOSHIFUJI Hideaki/吉藤英明
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 <[email protected]>--- net/ipv6/addrconf.c | 201 +++++++++++++++++++++++++++++----------------------- 1 file changed, 111 insertions(+), 90 deletions(-)net/ipv6/addrconf.c +111
-91@@ -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 (); --
Quoted 2 lines
1.9.1
LGTM, and thanks again.
Acked-by Erik Kline <[email protected]>
Hi,
Quoted 8 lines · Erik Kline
Quoted 8 lines
net/ipv6/addrconf.c +8
-0+/* 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
Quoted 8 lines
net/ipv6/addrconf.c int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, · line 1477
Quoted 8 lines
net/ipv6/addrconf.c +8
-0+* 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) +*/
Sorry, I forgot to remove 3rd one, which should be removed for now; I'll resubmit.
Signature · 2 lines
Hideaki Yoshifuji <[email protected]> Technical Division, MIRACLE LINUX CORPORATION