net: Add address attribute to control metric of prefix route
Subsystems (4)
[email protected]
maintainercover net: Add address attribute to control metric of prefix route
From: David Ahern <[email protected]>
For use cases such as VRR (Virtual Router Redundancy) interface managers want efficient control over the order of prefix routes when multiple interfaces have addresses with overlapping/duplicate subnets.
Currently, if two interfaces have addresses in the same subnet, the order of the prefix route entries is determined by the order in which the addresses are assigned or the links brought up. Any actions like cycling an interface up and down changes that order. This set adds a new attribute for addresses to allow a user to specify the metric of the prefix route associated with an address giving interface managers better and more efficient control of the order of prefix routes.
Patches 1-3 refactor IPv6 address add functions to pass an ifa6_config struct. The functions currently have a long list of arguments and adding the metric just makes it worse. Because of the overall diff size in moving the arguments to a struct, the change is done in stages to make it easier to review starting with the bottom function and pushing the struct up to callers in each successive patch.
Patch 4 introduces the new attribute.
Patches 5 and 6 add support for the new attribute to IPv4 and IPv6 addresses.
Patch 7 adds a set of test cases.
Patch 8 adds support to iproute2
Changes since RFC
- collapsed patches 1 and 3 into patch 2
- simplified stack variables in fib_modify_prefix_metric in patch 5
David Ahern (7):
net/ipv6: Convert ipv6_add_addr to struct ifa6_config net/ipv6: Pass ifa6_config struct to inet6_addr_add net/ipv6: Pass ifa6_config struct to inet6_addr_modify
net: Add IFA_RT_PRIORITY address attribute
net/ipv4: Add support for specifying metric of connected routes net/ipv6: Add support for specifying metric of connected routes
selftests: fib_tests: Add prefix route tests with metric
include/linux/inetdevice.h | 1 + include/net/addrconf.h | 13 ++ include/net/if_inet6.h | 1 + include/net/route.h | 1 + include/uapi/linux/if_addr.h | 1 + net/ipv4/devinet.c | 15 ++ net/ipv4/fib_frontend.c | 53 ++++- net/ipv6/addrconf.c | 359 +++++++++++++++++++------------ tools/testing/selftests/net/fib_tests.sh | 181 +++++++++++++++- 9 files changed, 472 insertions(+), 153 deletions(-) mode change 100755 => 100644 tools/testing/selftests/net/fib_tests.sh
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 1/7 net/ipv6: Convert ipv6_add_addr to struct ifa6_config
From: David Ahern <[email protected]>
Move config parameters for adding an ipv6 address to a struct. struct names stem from inet6_rtm_newaddr which is the modern handler for adding an address.
Start the conversion to ifa6_config with ipv6_add_addr. This is an argument move only; no functional change intended. Mapping of variable changes:
addr --> cfg->pfx
peer_addr --> cfg->peer_pfx
pfxlen --> cfg->plen
flags --> cfg->ifa_flagsscope, valid_lft, prefered_lft have the same names within cfg (with corrected spelling).
--- include/net/addrconf.h | 12 +++++ net/ipv6/addrconf.c | 134 +++++++++++++++++++++++++++---------------------- 2 files changed, 87 insertions(+), 59 deletions(-)
include/net/addrconf.h +12 -0
@@ -59,6 +59,18 @@ struct in6_validator_info {struct netlink_ext_ack *extack; }; +struct ifa6_config { +const struct in6_addr *pfx; +unsigned int plen; + +const struct in6_addr *peer_pfx; + +u32 ifa_flags; +u32 preferred_lft; +u32 valid_lft; +u16 scope; +}; +int addrconf_init (void );void addrconf_cleanup (void );
net/ipv6/addrconf.c +75 -59
283 lines not on this page · raw message
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 2/7 net/ipv6: Pass ifa6_config struct to inet6_addr_add
In reply to [email protected]From: David Ahern <[email protected]>
Move the creation of struct ifa6_config up to callers of inet6_addr_add.
--- net/ipv6/addrconf.c | 112 ++++++++++++++++++++++++++-------------------------- 1 file changed, 57 insertions(+), 55 deletions(-)
net/ipv6/addrconf.c +57 -55
@@ -2830,20 +2830,9 @@ static int ipv6_mc_config(struct sock *sk, bool join,* Manual configuration of address on an interface */ static int inet6_addr_add (struct net *net,int ifindex, -const struct in6_addr *pfx, -const struct in6_addr *peer_pfx, -unsigned int plen,__u32 ifa_flags, -__u32 prefered_lft,__u32 valid_lft, +struct ifa6_config *cfg,struct netlink_ext_ack *extack) { -struct ifa6_config cfg = { - .pfx = pfx, - .plen = plen, - .peer_pfx = peer_pfx, - .ifa_flags = ifa_flags, - .preferred_lft = prefered_lft, - .valid_lft = valid_lft, - };struct inet6_ifaddr *ifp;struct inet6_dev *idev;struct net_device *dev;
@@ -2853,14 +2842,14 @@ static int inet6_addr_add(struct net *net, int ifindex,ASSERT_RTNL (); -if (plen >128 ) +if (cfg->plen >128 )return -EINVAL ;/* check the lifetime */ -if (!valid_lft || prefered_lft > valid_lft) +if (!cfg->valid_lft || cfg->preferred_lft > cfg->valid_lft)return -EINVAL ; -if (ifa_flags &IFA_F_MANAGETEMPADDR && plen !=64 ) +if (cfg->ifa_flags &IFA_F_MANAGETEMPADDR && cfg->plen !=64 )return -EINVAL ; dev =__dev_get_by_index (net, ifindex);
@@ -2871,37 +2860,37 @@ static int inet6_addr_add(struct net *net, int ifindex,if (IS_ERR (idev))return PTR_ERR (idev); -if (ifa_flags &IFA_F_MCAUTOJOIN ) { +if (cfg->ifa_flags &IFA_F_MCAUTOJOIN ) {int ret =ipv6_mc_config (net->ipv6.mc_autojoin_sk, - true, pfx, ifindex); + true, cfg->pfx, ifindex);if (ret <0 )return ret; } - cfg.scope =ipv6_addr_scope (pfx); + cfg->scope =ipv6_addr_scope (cfg->pfx); - timeout =addrconf_timeout_fixup (valid_lft,HZ ); + timeout =addrconf_timeout_fixup (cfg->valid_lft,HZ );if (addrconf_finite_timeout (timeout)) { expires =jiffies_to_clock_t (timeout *HZ ); - valid_lft = timeout; + cfg->valid_lft = timeout; flags =RTF_EXPIRES ; }else { expires =0 ; flags =0 ; - ifa_flags |=IFA_F_PERMANENT ; + cfg->ifa_flags |=IFA_F_PERMANENT ; } - timeout =addrconf_timeout_fixup (prefered_lft,HZ ); + timeout =addrconf_timeout_fixup (cfg->preferred_lft,HZ );if (addrconf_finite_timeout (timeout)) {if (timeout ==0 ) - ifa_flags |=IFA_F_DEPRECATED ; - prefered_lft = timeout; + cfg->ifa_flags |=IFA_F_DEPRECATED ; + cfg->preferred_lft = timeout; } - ifp =ipv6_add_addr (idev, &cfg, true, extack); + ifp =ipv6_add_addr (idev, cfg, true, extack);if (!IS_ERR (ifp)) { -if (!(ifa_flags &IFA_F_NOPREFIXROUTE )) { +if (!(cfg->ifa_flags &IFA_F_NOPREFIXROUTE )) {addrconf_prefix_route (&ifp->addr, ifp->prefix_len, dev, expires, flags,GFP_KERNEL ); }
@@ -2917,15 +2906,15 @@ static int inet6_addr_add(struct net *net, int ifindex,* manually configured addresses */ addrconf_dad_start (ifp); -if (ifa_flags &IFA_F_MANAGETEMPADDR ) -manage_tempaddrs (idev, ifp, valid_lft, prefered_lft, - true, jiffies); +if (cfg->ifa_flags &IFA_F_MANAGETEMPADDR ) +manage_tempaddrs (idev, ifp, cfg->valid_lft, + cfg->preferred_lft, true, jiffies);in6_ifa_put (ifp);addrconf_verify_rtnl ();return 0 ; - }else if (ifa_flags &IFA_F_MCAUTOJOIN ) { -ipv6_mc_config (net->ipv6.mc_autojoin_sk, - false, pfx, ifindex); + }else if (cfg->ifa_flags &IFA_F_MCAUTOJOIN ) { +ipv6_mc_config (net->ipv6.mc_autojoin_sk, false, + cfg->pfx, ifindex); }return PTR_ERR (ifp);
@@ -2976,6 +2965,11 @@ static int inet6_addr_del(struct net *net, int ifindex, u32 ifa_flags,int addrconf_add_ifaddr (struct net *net,void __user *arg) { +struct ifa6_config cfg = { + .ifa_flags =IFA_F_PERMANENT , + .preferred_lft =INFINITY_LIFE_TIME , + .valid_lft =INFINITY_LIFE_TIME , + };struct in6_ifreq ireq;int err;
@@ -2985,10 +2979,11 @@ int addrconf_add_ifaddr(struct net *net, void __user *arg)if (copy_from_user (&ireq, arg,sizeof (struct in6_ifreq )))return -EFAULT ; + cfg.pfx = &ireq.ifr6_addr; + cfg.plen = ireq.ifr6_prefixlen; +rtnl_lock (); - err =inet6_addr_add (net, ireq.ifr6_ifindex, &ireq.ifr6_addr,NULL , - ireq.ifr6_prefixlen,IFA_F_PERMANENT , -INFINITY_LIFE_TIME ,INFINITY_LIFE_TIME ,NULL ); + err =inet6_addr_add (net, ireq.ifr6_ifindex, &cfg,NULL );rtnl_unlock ();return err; }
@@ -4624,12 +4619,11 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,struct net *net =sock_net (skb->sk);struct ifaddrmsg *ifm;struct nlattr *tb[IFA_MAX +1 ]; -struct in6_addr *pfx, *peer_pfx; +struct in6_addr *peer_pfx;struct inet6_ifaddr *ifa;struct net_device *dev;struct inet6_dev *idev; -u32 valid_lft =INFINITY_LIFE_TIME , preferred_lft =INFINITY_LIFE_TIME ; -u32 ifa_flags; +struct ifa6_config cfg;int err; err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy,
@@ -4637,60 +4631,68 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,if (err <0 )return err; +memset (&cfg,0 ,sizeof (cfg)); + ifm =nlmsg_data (nlh); - pfx =extract_addr (tb[IFA_ADDRESS ], tb[IFA_LOCAL ], &peer_pfx); -if (!pfx) + cfg.pfx =extract_addr (tb[IFA_ADDRESS ], tb[IFA_LOCAL ], &peer_pfx); +if (!cfg.pfx)return -EINVAL ; + cfg.peer_pfx = peer_pfx; + cfg.plen = ifm->ifa_prefixlen; + cfg.valid_lft =INFINITY_LIFE_TIME ; + cfg.preferred_lft =INFINITY_LIFE_TIME ; +if (tb[IFA_CACHEINFO ]) {struct ifa_cacheinfo *ci; ci =nla_data (tb[IFA_CACHEINFO ]); - valid_lft = ci->ifa_valid; - preferred_lft = ci->ifa_prefered; - }else { - preferred_lft =INFINITY_LIFE_TIME ; - valid_lft =INFINITY_LIFE_TIME ; + cfg.valid_lft = ci->ifa_valid; + cfg.preferred_lft = ci->ifa_prefered; } dev =__dev_get_by_index (net, ifm->ifa_index);if (!dev)return -ENODEV ; - ifa_flags = tb[IFA_FLAGS ] ?nla_get_u32 (tb[IFA_FLAGS ]) : ifm->ifa_flags; +if (tb[IFA_FLAGS ]) + cfg.ifa_flags =nla_get_u32 (tb[IFA_FLAGS ]); +else + cfg.ifa_flags = ifm->ifa_flags;/* We ignore other flags so far. */ - ifa_flags &=IFA_F_NODAD |IFA_F_HOMEADDRESS |IFA_F_MANAGETEMPADDR | -IFA_F_NOPREFIXROUTE |IFA_F_MCAUTOJOIN |IFA_F_OPTIMISTIC ; + cfg.ifa_flags &=IFA_F_NODAD |IFA_F_HOMEADDRESS | +IFA_F_MANAGETEMPADDR |IFA_F_NOPREFIXROUTE | +IFA_F_MCAUTOJOIN |IFA_F_OPTIMISTIC ; idev =ipv6_find_idev (dev);if (IS_ERR (idev))return PTR_ERR (idev);if (!ipv6_allow_optimistic_dad (net, idev)) - ifa_flags &= ~IFA_F_OPTIMISTIC ; + cfg.ifa_flags &= ~IFA_F_OPTIMISTIC ; -if (ifa_flags &IFA_F_NODAD && ifa_flags &IFA_F_OPTIMISTIC ) { +if (cfg.ifa_flags &IFA_F_NODAD && + cfg.ifa_flags &IFA_F_OPTIMISTIC ) {NL_SET_ERR_MSG (extack,"IFA_F_NODAD and IFA_F_OPTIMISTIC are mutually exclusive" );return -EINVAL ; } - ifa =ipv6_get_ifaddr (net, pfx, dev,1 ); + ifa =ipv6_get_ifaddr (net, cfg.pfx, dev,1 );if (!ifa) {/* * It would be best to check for !NLM_F_CREATE here but * userspace already relies on not having to provide this. */ -return inet6_addr_add (net, ifm->ifa_index, pfx, peer_pfx, - ifm->ifa_prefixlen, ifa_flags, - preferred_lft, valid_lft, extack); +return inet6_addr_add (net, ifm->ifa_index, &cfg, extack); }if (nlh->nlmsg_flags &NLM_F_EXCL || !(nlh->nlmsg_flags &NLM_F_REPLACE )) err = -EEXIST ;else - err =inet6_addr_modify (ifa, ifa_flags, preferred_lft, valid_lft); + err =inet6_addr_modify (ifa, cfg.ifa_flags, cfg.preferred_lft, + cfg.valid_lft);in6_ifa_put (ifa);
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 3/7 net/ipv6: Pass ifa6_config struct to inet6_addr_modify
In reply to [email protected]From: David Ahern <[email protected]>
Update inet6_addr_modify to take ifa6_config argument versus a parameter list. This is an argument move only; no functional change intended.
--- net/ipv6/addrconf.c | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-)
net/ipv6/addrconf.c +23 -21
@@ -4527,8 +4527,7 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, ifm->ifa_prefixlen); } -static int inet6_addr_modify (struct inet6_ifaddr *ifp,u32 ifa_flags, -u32 prefered_lft,u32 valid_lft) +static int inet6_addr_modify (struct inet6_ifaddr *ifp,struct ifa6_config *cfg) {u32 flags;clock_t expires;
@@ -4538,32 +4537,32 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,ASSERT_RTNL (); -if (!valid_lft || (prefered_lft > valid_lft)) +if (!cfg->valid_lft || cfg->preferred_lft > cfg->valid_lft)return -EINVAL ; -if (ifa_flags &IFA_F_MANAGETEMPADDR && +if (cfg->ifa_flags &IFA_F_MANAGETEMPADDR && (ifp->flags &IFA_F_TEMPORARY || ifp->prefix_len !=64 ))return -EINVAL ;if (!(ifp->flags &IFA_F_TENTATIVE ) || ifp->flags &IFA_F_DADFAILED ) - ifa_flags &= ~IFA_F_OPTIMISTIC ; + cfg->ifa_flags &= ~IFA_F_OPTIMISTIC ; - timeout =addrconf_timeout_fixup (valid_lft,HZ ); + timeout =addrconf_timeout_fixup (cfg->valid_lft,HZ );if (addrconf_finite_timeout (timeout)) { expires =jiffies_to_clock_t (timeout *HZ ); - valid_lft = timeout; + cfg->valid_lft = timeout; flags =RTF_EXPIRES ; }else { expires =0 ; flags =0 ; - ifa_flags |=IFA_F_PERMANENT ; + cfg->ifa_flags |=IFA_F_PERMANENT ; } - timeout =addrconf_timeout_fixup (prefered_lft,HZ ); + timeout =addrconf_timeout_fixup (cfg->preferred_lft,HZ );if (addrconf_finite_timeout (timeout)) {if (timeout ==0 ) - ifa_flags |=IFA_F_DEPRECATED ; - prefered_lft = timeout; + cfg->ifa_flags |=IFA_F_DEPRECATED ; + cfg->preferred_lft = timeout; }spin_lock_bh (&ifp->lock);
@@ -4573,16 +4572,16 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags, ifp->flags &= ~(IFA_F_DEPRECATED |IFA_F_PERMANENT |IFA_F_NODAD |IFA_F_HOMEADDRESS |IFA_F_MANAGETEMPADDR |IFA_F_NOPREFIXROUTE ); - ifp->flags |= ifa_flags; + ifp->flags |= cfg->ifa_flags; ifp->tstamp = jiffies; - ifp->valid_lft = valid_lft; - ifp->prefered_lft = prefered_lft; + ifp->valid_lft = cfg->valid_lft; + ifp->prefered_lft = cfg->preferred_lft;spin_unlock_bh (&ifp->lock);if (!(ifp->flags&IFA_F_TENTATIVE ))ipv6_ifa_notify (0 , ifp); -if (!(ifa_flags &IFA_F_NOPREFIXROUTE )) { +if (!(cfg->ifa_flags &IFA_F_NOPREFIXROUTE )) {addrconf_prefix_route (&ifp->addr, ifp->prefix_len, ifp->idev->dev, expires, flags,GFP_KERNEL );
@@ -4601,10 +4600,14 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags, }if (was_managetempaddr || ifp->flags &IFA_F_MANAGETEMPADDR ) { -if (was_managetempaddr && !(ifp->flags &IFA_F_MANAGETEMPADDR )) - valid_lft = prefered_lft =0 ; -manage_tempaddrs (ifp->idev, ifp, valid_lft, prefered_lft, - !was_managetempaddr, jiffies); +if (was_managetempaddr && + !(ifp->flags &IFA_F_MANAGETEMPADDR )) { + cfg->valid_lft =0 ; + cfg->preferred_lft =0 ; + } +manage_tempaddrs (ifp->idev, ifp, cfg->valid_lft, + cfg->preferred_lft, !was_managetempaddr, + jiffies); }addrconf_verify_rtnl ();
@@ -4691,8 +4694,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, !(nlh->nlmsg_flags & NLM_F_REPLACE)) err = -EEXIST ; else - err =inet6_addr_modify (ifa, cfg.ifa_flags, cfg.preferred_lft, - cfg.valid_lft); + err =inet6_addr_modify (ifa, &cfg);in6_ifa_put (ifa);
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 4/7 net: Add IFA_RT_PRIORITY address attribute
In reply to [email protected]From: David Ahern <[email protected]>
Currently, if two interfaces have addresses in the same connected route, then the order of the prefix route entries is determined by the order in which the addresses are assigned or the links brought up.
Add IFA_RT_PRIORITY to allow user to specify the metric of the prefix route associated with an address giving interface managers better control of the order of prefix routes.
--- include/uapi/linux/if_addr.h | 1 + 1 file changed, 1 insertion(+)
include/uapi/linux/if_addr.h +1 -0
@@ -33,6 +33,7 @@ enum {IFA_CACHEINFO ,IFA_MULTICAST ,IFA_FLAGS , +IFA_RT_PRIORITY ,/* u32, priority/metric for prefix route */ __IFA_MAX, };
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 5/7 net/ipv4: Add support for specifying metric of connected routes
In reply to [email protected]From: David Ahern <[email protected]>
Add support for IFA_RT_PRIORITY to ipv4 addresses.
If the metric is changed on an existing address then the new route is inserted before removing the old one. Since the metric is one of the route keys, the prefix route can not be replaced.
--- include/linux/inetdevice.h | 1 + include/net/route.h | 1 + net/ipv4/devinet.c | 15 +++++++++++++ net/ipv4/fib_frontend.c | 53 ++++++++++++++++++++++++++++++++++++---------- 4 files changed, 59 insertions(+), 11 deletions(-)
include/linux/inetdevice.h +1 -0
@@ -139,6 +139,7 @@ struct in_ifaddr {__be32 ifa_local;__be32 ifa_address;__be32 ifa_mask; +__u32 ifa_rt_priority;__be32 ifa_broadcast;unsigned char ifa_scope;unsigned char ifa_prefixlen;
include/net/route.h +1 -0
@@ -225,6 +225,7 @@ struct rtable *rt_dst_alloc(struct net_device *dev,struct in_ifaddr ;void fib_add_ifaddr (struct in_ifaddr *);void fib_del_ifaddr (struct in_ifaddr *,struct in_ifaddr *); +void fib_modify_prefix_metric (struct in_ifaddr *ifa,u32 new_metric);void rt_add_uncached_list (struct rtable *rt);void rt_del_uncached_list (struct rtable *rt);
net/ipv4/devinet.c +15 -0
@@ -99,6 +99,7 @@ static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = { [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, [IFA_FLAGS] = { .type = NLA_U32 }, + [IFA_RT_PRIORITY] = { .type = NLA_U32 }, };#define IN4_ADDR_HSIZE_SHIFT 8
@@ -835,6 +836,9 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,else memcpy (ifa->ifa_label, dev->name,IFNAMSIZ ); +if (tb[IFA_RT_PRIORITY ]) + ifa->ifa_rt_priority =nla_get_u32 (tb[IFA_RT_PRIORITY ]); +if (tb[IFA_CACHEINFO ]) {struct ifa_cacheinfo *ci;
@@ -906,12 +910,20 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,return __inet_insert_ifa (ifa, nlh,NETLINK_CB (skb).portid, extack); }else { +u32 new_metric = ifa->ifa_rt_priority; +inet_free_ifa (ifa);if (nlh->nlmsg_flags &NLM_F_EXCL || !(nlh->nlmsg_flags &NLM_F_REPLACE ))return -EEXIST ; ifa = ifa_existing; + +if (ifa->ifa_rt_priority != new_metric) { +fib_modify_prefix_metric (ifa, new_metric); + ifa->ifa_rt_priority = new_metric; + } +set_ifa_lifetime (ifa, valid_lft, prefered_lft);cancel_delayed_work (&check_lifetime_work); queue_delayed_work(system_power_efficient_wq,
@@ -1549,6 +1561,7 @@ static size_t inet_nlmsg_size(void) +nla_total_size (4 )/* IFA_BROADCAST */ +nla_total_size (IFNAMSIZ )/* IFA_LABEL */ +nla_total_size (4 )/* IFA_FLAGS */ + +nla_total_size (4 )/* IFA_RT_PRIORITY */ +nla_total_size (sizeof (struct ifa_cacheinfo ));/* IFA_CACHEINFO */ }
@@ -1618,6 +1631,8 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, (ifa->ifa_label[0 ] &&nla_put_string (skb,IFA_LABEL , ifa->ifa_label)) ||nla_put_u32 (skb,IFA_FLAGS , ifa->ifa_flags) || + (ifa->ifa_rt_priority && +nla_put_u32 (skb,IFA_RT_PRIORITY , ifa->ifa_rt_priority)) ||put_cacheinfo (skb, ifa->ifa_cstamp, ifa->ifa_tstamp, preferred, valid)) goto nla_put_failure;
net/ipv4/fib_frontend.c +42 -11
110 lines not on this page · raw message
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 6/7 net/ipv6: Add support for specifying metric of connected routes
In reply to [email protected]From: David Ahern <[email protected]>
Add support for IFA_RT_PRIORITY to ipv6 addresses.
If the metric is changed on an existing address then the new route is inserted before removing the old one. Since the metric is one of the route keys, the prefix route can not be atomically replaced.
--- include/net/addrconf.h | 1 + include/net/if_inet6.h | 1 + net/ipv6/addrconf.c | 93 ++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 77 insertions(+), 18 deletions(-)
include/net/addrconf.h +1 -0
@@ -65,6 +65,7 @@ struct ifa6_config {const struct in6_addr *peer_pfx; +u32 rt_priority;u32 ifa_flags;u32 preferred_lft;u32 valid_lft;
include/net/if_inet6.h +1 -0
@@ -42,6 +42,7 @@ enum {struct inet6_ifaddr {struct in6_addr addr;__u32 prefix_len; +__u32 rt_priority;/* In seconds, relative to tstamp. Expiry is at tstamp + HZ * lft. */ __u32 valid_lft;
net/ipv6/addrconf.c +75 -18
209 lines not on this page · raw message
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 7/7 selftests: fib_tests: Add prefix route tests with metric
In reply to [email protected]From: David Ahern <[email protected]>
Add tests verifying prefix routes are inserted with expected metric.
IPv6 prefix route tests
TEST: Default metric [ OK ]
TEST: User specified metric on first device [ OK ]
TEST: User specified metric on second device [ OK ]
TEST: Delete of address on first device [ OK ]
TEST: Modify metric of address [ OK ]
TEST: Prefix route removed on link down [ OK ]
TEST: Prefix route with metric on link up [ OK ]IPv4 prefix route tests
TEST: Default metric [ OK ]
TEST: User specified metric on first device [ OK ]
TEST: User specified metric on second device [ OK ]
TEST: Delete of address on first device [ OK ]
TEST: Modify metric of address [ OK ]
TEST: Prefix route removed on link down [ OK ]
TEST: Prefix route with metric on link up [ OK ]--- tools/testing/selftests/net/fib_tests.sh | 181 ++++++++++++++++++++++++++++++- 1 file changed, 180 insertions(+), 1 deletion(-) mode change 100755 => 100644 tools/testing/selftests/net/fib_tests.sh
tools/testing/selftests/net/fib_tests.sh +180 -1
@@ -6,7 +6,8 @@ ret=0 -TESTS="unregister down carrier nexthop ipv6_rt ipv4_rt" +# all tests in this script. Can be overridden with -t option +TESTS="unregister down carrier nexthop ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric" VERBOSE=0 PAUSE_ON_FAIL=no PAUSE=no
@@ -642,6 +643,8 @@ check_route6() local rc=0 out=$($IP -6 ro ls match ${pfx} | sed -e 's/ pref medium//') + [ "${out}" = "${expected}" ] && return 0 + if [ -z "${out}" ]; then if [ "$VERBOSE" = "1" ]; then printf "\nNo route entry found\n"
@@ -911,6 +914,98 @@ ipv6_route_test() route_cleanup } +ip_addr_metric_check() +{ + ip addr help 2>&1 | grep -q metric + if [ $? -ne 0 ]; then + echo "iproute2 command does not support metric for addresses. Skipping test" + return 1 + fi + + return 0 +} + +ipv6_addr_metric_test() +{ + local rc + + echo + echo "IPv6 prefix route tests" + + ip_addr_metric_check || return 1 + + setup + + set -e + $IP li add dummy1 type dummy + $IP li add dummy2 type dummy + $IP li set dummy1 up + $IP li set dummy2 up + + # default entry is metric 256 + run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64" + run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64" + set +e + + check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 256 2001:db8:104::/64 dev dummy2 proto kernel metric 256" + log_test $? 0 "Default metric" + + set -e + run_cmd "$IP -6 addr flush dev dummy1" + run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64 metric 257" + set +e + + check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 256 2001:db8:104::/64 dev dummy1 proto kernel metric 257" + log_test $? 0 "User specified metric on first device" + + set -e + run_cmd "$IP -6 addr flush dev dummy2" + run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64 metric 258" + set +e + + check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 257 2001:db8:104::/64 dev dummy2 proto kernel metric 258" + log_test $? 0 "User specified metric on second device" + + run_cmd "$IP -6 addr del dev dummy1 2001:db8:104::1/64 metric 257" + rc=$? + if [ $rc -eq 0 ]; then + check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 258" + rc=$? + fi + log_test $rc 0 "Delete of address on first device" + + run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::2/64 metric 259" + rc=$? + if [ $rc -eq 0 ]; then + check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259" + rc=$? + fi + log_test $rc 0 "Modify metric of address" + + # verify prefix route removed on down + run_cmd "ip netns exec testns sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1" + run_cmd "$IP li set dev dummy2 down" + rc=$? + if [ $rc -eq 0 ]; then + check_route6 "" + rc=$? + fi + log_test $rc 0 "Prefix route removed on link down" + + # verify prefix route re-inserted with assigned metric + run_cmd "$IP li set dev dummy2 up" + rc=$? + if [ $rc -eq 0 ]; then + check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259" + rc=$? + fi + log_test $rc 0 "Prefix route with metric on link up" + + $IP li del dummy1 + $IP li del dummy2 + cleanup +} + # add route for a prefix, flushing any existing routes first # expected to be the first step of a test add_route()
@@ -955,6 +1050,8 @@ check_route() local rc=0 out=$($IP ro ls match ${pfx}) + [ "${out}" = "${expected}" ] && return 0 + if [ -z "${out}" ]; then if [ "$VERBOSE" = "1" ]; then printf "\nNo route entry found\n"
@@ -1181,6 +1278,86 @@ ipv4_route_test() route_cleanup } +ipv4_addr_metric_test() +{ + local rc + + echo + echo "IPv4 prefix route tests" + + ip_addr_metric_check || return 1 + + setup + + set -e + $IP li add dummy1 type dummy + $IP li add dummy2 type dummy + $IP li set dummy1 up + $IP li set dummy2 up + + # default entry is metric 256 + run_cmd "$IP addr add dev dummy1 172.16.104.1/24" + run_cmd "$IP addr add dev dummy2 172.16.104.2/24" + set +e + + check_route "172.16.104.0/24 dev dummy1 proto kernel scope link src 172.16.104.1 172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2" + log_test $? 0 "Default metric" + + set -e + run_cmd "$IP addr flush dev dummy1" + run_cmd "$IP addr add dev dummy1 172.16.104.1/24 metric 257" + set +e + + check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 172.16.104.0/24 dev dummy1 proto kernel scope link src 172.16.104.1 metric 257" + log_test $? 0 "User specified metric on first device" + + set -e + run_cmd "$IP addr flush dev dummy2" + run_cmd "$IP addr add dev dummy2 172.16.104.2/24 metric 258" + set +e + + check_route "172.16.104.0/24 dev dummy1 proto kernel scope link src 172.16.104.1 metric 257 172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258" + log_test $? 0 "User specified metric on second device" + + run_cmd "$IP addr del dev dummy1 172.16.104.1/24 metric 257" + rc=$? + if [ $rc -eq 0 ]; then + check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258" + rc=$? + fi + log_test $rc 0 "Delete of address on first device" + + run_cmd "$IP addr change dev dummy2 172.16.104.2/24 metric 259" + rc=$? + if [ $rc -eq 0 ]; then + check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259" + rc=$? + fi + log_test $rc 0 "Modify metric of address" + + # verify prefix route removed on down + run_cmd "$IP li set dev dummy2 down" + rc=$? + if [ $rc -eq 0 ]; then + check_route "" + rc=$? + fi + log_test $rc 0 "Prefix route removed on link down" + + # verify prefix route re-inserted with assigned metric + run_cmd "$IP li set dev dummy2 up" + rc=$? + if [ $rc -eq 0 ]; then + check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259" + rc=$? + fi + log_test $rc 0 "Prefix route with metric on link up" + + $IP li del dummy1 + $IP li del dummy2 + cleanup +} + ################################################################################ # usage
@@ -1245,6 +1422,8 @@ do fib_nexthop_test|nexthop) fib_nexthop_test;; ipv6_route_test|ipv6_rt) ipv6_route_test;; ipv4_route_test|ipv4_rt) ipv4_route_test;; + ipv6_addr_metric) ipv6_addr_metric_test;; + ipv4_addr_metric) ipv4_addr_metric_test;; help) echo "Test names: $TESTS"; exit 0;; esac
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 1/1 ipaddress: Add support for address metric
In reply to [email protected]From: David Ahern <[email protected]>
Add support for IFA_RT_PRIORITY using the same keywords as iproute for RTA_PRIORITY.
--- include/uapi/linux/if_addr.h | 1 + ip/ipaddress.c | 15 ++++++++++++++- man/man8/ip-address.8.in | 6 ++++++ 3 files changed, 21 insertions(+), 1 deletion(-)
include/uapi/linux/if_addr.h +1 -0
@@ -33,6 +33,7 @@ enum {IFA_CACHEINFO ,IFA_MULTICAST ,IFA_FLAGS , +IFA_RT_PRIORITY ,/* u32, priority/metric for prefix route */ __IFA_MAX, };
ip/ipaddress.c +14 -1
@@ -63,7 +63,7 @@ static void usage(void)fprintf (stderr," ip address {showdump|restore}\n" );fprintf (stderr,"IFADDR := PREFIX | ADDR peer PREFIX\n" );fprintf (stderr," [ broadcast ADDR ] [ anycast ADDR ]\n" ); -fprintf (stderr," [ label IFNAME ] [ scope SCOPE-ID ]\n" ); +fprintf (stderr," [ label IFNAME ] [ scope SCOPE-ID ] [ metric METRIC ]\n" );fprintf (stderr,"SCOPE-ID := [ host | link | global | NUMBER ]\n" );fprintf (stderr,"FLAG-LIST := [ FLAG-LIST ] FLAG\n" );fprintf (stderr,"FLAG := [ permanent | dynamic | secondary | primary |\n" );
@@ -1328,6 +1328,10 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, rta_tb[IFA_ADDRESS])); }print_int (PRINT_ANY ,"prefixlen" ,"/%d " , ifa->ifa_prefixlen); + +if (rta_tb[IFA_RT_PRIORITY ]) +print_uint (PRINT_ANY ,"metric" ,"metric %u " , +rta_getattr_u32 (rta_tb[IFA_RT_PRIORITY ])); }if (brief)
@@ -2119,6 +2123,15 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)NEXT_ARG (); l = *argv;addattr_l (&req.n,sizeof (req),IFA_LABEL , l,strlen (l)+1 ); + }else if (matches (*argv,"metric" ) ==0 || +matches (*argv,"priority" ) ==0 || +matches (*argv,"preference" ) ==0 ) { +__u32 metric; + +NEXT_ARG (); +if (get_u32 (&metric, *argv,0 )) +invarg ("\"metric\" value is invalid\n" , *argv); +addattr32 (&req.n,sizeof (req),IFA_RT_PRIORITY , metric); }else if (matches (*argv,"valid_lft" ) ==0 ) {if (valid_lftp)duparg ("valid_lft" , *argv);
man/man8/ip-address.8.in +6 -0
@@ -27,6 +27,8 @@ ip-address \- protocol address management .IR IFNAME " ] [ " .B scope .IR SCOPE-ID " ] [ " +.B metric +.IR METRIC " ] [ " .B to .IR PREFIX " ] [ " FLAG-LIST " ] [ " .B label
@@ -215,6 +217,10 @@ valid inside this site. .in -8 .TP +.BI metric " NUMBER" +priority of prefix route associated with address. + +.TP .BI valid_lft " LFT" the valid lifetime of this address; see section 5.5.4 of RFC 4862. When it expires, the address is removed by the kernel.
Signature · 1 line
2.11.0
David Ahern
AppliedRe: [PATCH iproute2-next] ipaddress: Add support for address metric
Quoted 11 lines · On 5/27/18 9:10 AM, [email protected] wrote:
From: David Ahern <[email protected]>
Add support for
IFA_RT_PRIORITYusing the same keywords as iproute forRTA_PRIORITY.Signed-off-by David Ahern <[email protected]>--- include/uapi/linux/if_addr.h | 1 + ip/ipaddress.c | 15 ++++++++++++++- man/man8/ip-address.8.in | 6 ++++++ 3 files changed, 21 insertions(+), 1 deletion(-)
applied to iproute2-next.
David Miller
maintainerFrom: [email protected]
Date: Sun, 27 May 2018 08:09:52 -0700
Quoted 11 lines
For use cases such as VRR (Virtual Router Redundancy) interface managers want efficient control over the order of prefix routes when multiple interfaces have addresses with overlapping/duplicate subnets.
Currently, if two interfaces have addresses in the same subnet, the order of the prefix route entries is determined by the order in which the addresses are assigned or the links brought up. Any actions like cycling an interface up and down changes that order. This set adds a new attribute for addresses to allow a user to specify the metric of the prefix route associated with an address giving interface managers better and more efficient control of the order of prefix routes.
Looks great, series applied, thanks David.