Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net/ipv4: Add support for specifying metric of connected routes

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.

Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

David Ahern and committed by
David S. Miller
af4d768a 620dee94

+59 -11
+1
include/linux/inetdevice.h
··· 139 139 __be32 ifa_local; 140 140 __be32 ifa_address; 141 141 __be32 ifa_mask; 142 + __u32 ifa_rt_priority; 142 143 __be32 ifa_broadcast; 143 144 unsigned char ifa_scope; 144 145 unsigned char ifa_prefixlen;
+1
include/net/route.h
··· 225 225 struct in_ifaddr; 226 226 void fib_add_ifaddr(struct in_ifaddr *); 227 227 void fib_del_ifaddr(struct in_ifaddr *, struct in_ifaddr *); 228 + void fib_modify_prefix_metric(struct in_ifaddr *ifa, u32 new_metric); 228 229 229 230 void rt_add_uncached_list(struct rtable *rt); 230 231 void rt_del_uncached_list(struct rtable *rt);
+15
net/ipv4/devinet.c
··· 99 99 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, 100 100 [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, 101 101 [IFA_FLAGS] = { .type = NLA_U32 }, 102 + [IFA_RT_PRIORITY] = { .type = NLA_U32 }, 102 103 }; 103 104 104 105 #define IN4_ADDR_HSIZE_SHIFT 8 ··· 836 835 else 837 836 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); 838 837 838 + if (tb[IFA_RT_PRIORITY]) 839 + ifa->ifa_rt_priority = nla_get_u32(tb[IFA_RT_PRIORITY]); 840 + 839 841 if (tb[IFA_CACHEINFO]) { 840 842 struct ifa_cacheinfo *ci; 841 843 ··· 910 906 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid, 911 907 extack); 912 908 } else { 909 + u32 new_metric = ifa->ifa_rt_priority; 910 + 913 911 inet_free_ifa(ifa); 914 912 915 913 if (nlh->nlmsg_flags & NLM_F_EXCL || 916 914 !(nlh->nlmsg_flags & NLM_F_REPLACE)) 917 915 return -EEXIST; 918 916 ifa = ifa_existing; 917 + 918 + if (ifa->ifa_rt_priority != new_metric) { 919 + fib_modify_prefix_metric(ifa, new_metric); 920 + ifa->ifa_rt_priority = new_metric; 921 + } 922 + 919 923 set_ifa_lifetime(ifa, valid_lft, prefered_lft); 920 924 cancel_delayed_work(&check_lifetime_work); 921 925 queue_delayed_work(system_power_efficient_wq, ··· 1561 1549 + nla_total_size(4) /* IFA_BROADCAST */ 1562 1550 + nla_total_size(IFNAMSIZ) /* IFA_LABEL */ 1563 1551 + nla_total_size(4) /* IFA_FLAGS */ 1552 + + nla_total_size(4) /* IFA_RT_PRIORITY */ 1564 1553 + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */ 1565 1554 } 1566 1555 ··· 1631 1618 (ifa->ifa_label[0] && 1632 1619 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) || 1633 1620 nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) || 1621 + (ifa->ifa_rt_priority && 1622 + nla_put_u32(skb, IFA_RT_PRIORITY, ifa->ifa_rt_priority)) || 1634 1623 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp, 1635 1624 preferred, valid)) 1636 1625 goto nla_put_failure;
+42 -11
net/ipv4/fib_frontend.c
··· 847 847 * to fib engine. It is legal, because all events occur 848 848 * only when netlink is already locked. 849 849 */ 850 - static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa) 850 + static void fib_magic(int cmd, int type, __be32 dst, int dst_len, 851 + struct in_ifaddr *ifa, u32 rt_priority) 851 852 { 852 853 struct net *net = dev_net(ifa->ifa_dev->dev); 853 854 u32 tb_id = l3mdev_fib_table(ifa->ifa_dev->dev); ··· 858 857 .fc_type = type, 859 858 .fc_dst = dst, 860 859 .fc_dst_len = dst_len, 860 + .fc_priority = rt_priority, 861 861 .fc_prefsrc = ifa->ifa_local, 862 862 .fc_oif = ifa->ifa_dev->dev->ifindex, 863 863 .fc_nlflags = NLM_F_CREATE | NLM_F_APPEND, ··· 904 902 } 905 903 } 906 904 907 - fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim); 905 + fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim, 0); 908 906 909 907 if (!(dev->flags & IFF_UP)) 910 908 return; 911 909 912 910 /* Add broadcast address, if it is explicitly assigned. */ 913 911 if (ifa->ifa_broadcast && ifa->ifa_broadcast != htonl(0xFFFFFFFF)) 914 - fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); 912 + fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, 913 + prim, 0); 915 914 916 915 if (!ipv4_is_zeronet(prefix) && !(ifa->ifa_flags & IFA_F_SECONDARY) && 917 916 (prefix != addr || ifa->ifa_prefixlen < 32)) { 918 917 if (!(ifa->ifa_flags & IFA_F_NOPREFIXROUTE)) 919 918 fib_magic(RTM_NEWROUTE, 920 919 dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST, 921 - prefix, ifa->ifa_prefixlen, prim); 920 + prefix, ifa->ifa_prefixlen, prim, 921 + ifa->ifa_rt_priority); 922 922 923 923 /* Add network specific broadcasts, when it takes a sense */ 924 924 if (ifa->ifa_prefixlen < 31) { 925 - fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32, prim); 925 + fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32, 926 + prim, 0); 926 927 fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix | ~mask, 927 - 32, prim); 928 + 32, prim, 0); 928 929 } 929 930 } 931 + } 932 + 933 + void fib_modify_prefix_metric(struct in_ifaddr *ifa, u32 new_metric) 934 + { 935 + __be32 prefix = ifa->ifa_address & ifa->ifa_mask; 936 + struct in_device *in_dev = ifa->ifa_dev; 937 + struct net_device *dev = in_dev->dev; 938 + 939 + if (!(dev->flags & IFF_UP) || 940 + ifa->ifa_flags & (IFA_F_SECONDARY | IFA_F_NOPREFIXROUTE) || 941 + ipv4_is_zeronet(prefix) || 942 + prefix == ifa->ifa_local || ifa->ifa_prefixlen == 32) 943 + return; 944 + 945 + /* add the new */ 946 + fib_magic(RTM_NEWROUTE, 947 + dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST, 948 + prefix, ifa->ifa_prefixlen, ifa, new_metric); 949 + 950 + /* delete the old */ 951 + fib_magic(RTM_DELROUTE, 952 + dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST, 953 + prefix, ifa->ifa_prefixlen, ifa, ifa->ifa_rt_priority); 930 954 } 931 955 932 956 /* Delete primary or secondary address. ··· 996 968 if (!(ifa->ifa_flags & IFA_F_NOPREFIXROUTE)) 997 969 fib_magic(RTM_DELROUTE, 998 970 dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST, 999 - any, ifa->ifa_prefixlen, prim); 971 + any, ifa->ifa_prefixlen, prim, 0); 1000 972 subnet = 1; 1001 973 } 1002 974 ··· 1080 1052 1081 1053 no_promotions: 1082 1054 if (!(ok & BRD_OK)) 1083 - fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); 1055 + fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, 1056 + prim, 0); 1084 1057 if (subnet && ifa->ifa_prefixlen < 31) { 1085 1058 if (!(ok & BRD1_OK)) 1086 - fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32, prim); 1059 + fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32, 1060 + prim, 0); 1087 1061 if (!(ok & BRD0_OK)) 1088 - fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim); 1062 + fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, 1063 + prim, 0); 1089 1064 } 1090 1065 if (!(ok & LOCAL_OK)) { 1091 1066 unsigned int addr_type; 1092 1067 1093 - fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim); 1068 + fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim, 0); 1094 1069 1095 1070 /* Check, that this local address finally disappeared. */ 1096 1071 addr_type = inet_addr_type_dev_table(dev_net(dev), dev,