summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Ahern <dsahern@gmail.com>2018-05-27 11:09:57 -0400
committerDavid S. Miller <davem@davemloft.net>2018-05-29 10:12:45 -0400
commitaf4d768ad28cbf6542ba70dba10b49127b31b762 (patch)
treea9491a2cbbff82fd3159ffd24f6f5d7442299090
parent620dee9415fae09003d012cc7c23b011e5ebb43d (diff)
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>
-rw-r--r--include/linux/inetdevice.h1
-rw-r--r--include/net/route.h1
-rw-r--r--net/ipv4/devinet.c15
-rw-r--r--net/ipv4/fib_frontend.c53
4 files changed, 59 insertions, 11 deletions
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
index e16fe7d44a71..27650f1bff3d 100644
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -139,6 +139,7 @@ struct in_ifaddr {
139 __be32 ifa_local; 139 __be32 ifa_local;
140 __be32 ifa_address; 140 __be32 ifa_address;
141 __be32 ifa_mask; 141 __be32 ifa_mask;
142 __u32 ifa_rt_priority;
142 __be32 ifa_broadcast; 143 __be32 ifa_broadcast;
143 unsigned char ifa_scope; 144 unsigned char ifa_scope;
144 unsigned char ifa_prefixlen; 145 unsigned char ifa_prefixlen;
diff --git a/include/net/route.h b/include/net/route.h
index dbb032d5921b..bb53cdba38dc 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -225,6 +225,7 @@ struct rtable *rt_dst_alloc(struct net_device *dev,
225struct in_ifaddr; 225struct in_ifaddr;
226void fib_add_ifaddr(struct in_ifaddr *); 226void fib_add_ifaddr(struct in_ifaddr *);
227void fib_del_ifaddr(struct in_ifaddr *, struct in_ifaddr *); 227void fib_del_ifaddr(struct in_ifaddr *, struct in_ifaddr *);
228void fib_modify_prefix_metric(struct in_ifaddr *ifa, u32 new_metric);
228 229
229void rt_add_uncached_list(struct rtable *rt); 230void rt_add_uncached_list(struct rtable *rt);
230void rt_del_uncached_list(struct rtable *rt); 231void rt_del_uncached_list(struct rtable *rt);
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 40f001782c1b..d7585ab1a77a 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -99,6 +99,7 @@ static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
99 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, 99 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
100 [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, 100 [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) },
101 [IFA_FLAGS] = { .type = NLA_U32 }, 101 [IFA_FLAGS] = { .type = NLA_U32 },
102 [IFA_RT_PRIORITY] = { .type = NLA_U32 },
102}; 103};
103 104
104#define IN4_ADDR_HSIZE_SHIFT 8 105#define IN4_ADDR_HSIZE_SHIFT 8
@@ -835,6 +836,9 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
835 else 836 else
836 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); 837 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
837 838
839 if (tb[IFA_RT_PRIORITY])
840 ifa->ifa_rt_priority = nla_get_u32(tb[IFA_RT_PRIORITY]);
841
838 if (tb[IFA_CACHEINFO]) { 842 if (tb[IFA_CACHEINFO]) {
839 struct ifa_cacheinfo *ci; 843 struct ifa_cacheinfo *ci;
840 844
@@ -906,12 +910,20 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
906 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid, 910 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid,
907 extack); 911 extack);
908 } else { 912 } else {
913 u32 new_metric = ifa->ifa_rt_priority;
914
909 inet_free_ifa(ifa); 915 inet_free_ifa(ifa);
910 916
911 if (nlh->nlmsg_flags & NLM_F_EXCL || 917 if (nlh->nlmsg_flags & NLM_F_EXCL ||
912 !(nlh->nlmsg_flags & NLM_F_REPLACE)) 918 !(nlh->nlmsg_flags & NLM_F_REPLACE))
913 return -EEXIST; 919 return -EEXIST;
914 ifa = ifa_existing; 920 ifa = ifa_existing;
921
922 if (ifa->ifa_rt_priority != new_metric) {
923 fib_modify_prefix_metric(ifa, new_metric);
924 ifa->ifa_rt_priority = new_metric;
925 }
926
915 set_ifa_lifetime(ifa, valid_lft, prefered_lft); 927 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
916 cancel_delayed_work(&check_lifetime_work); 928 cancel_delayed_work(&check_lifetime_work);
917 queue_delayed_work(system_power_efficient_wq, 929 queue_delayed_work(system_power_efficient_wq,
@@ -1549,6 +1561,7 @@ static size_t inet_nlmsg_size(void)
1549 + nla_total_size(4) /* IFA_BROADCAST */ 1561 + nla_total_size(4) /* IFA_BROADCAST */
1550 + nla_total_size(IFNAMSIZ) /* IFA_LABEL */ 1562 + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
1551 + nla_total_size(4) /* IFA_FLAGS */ 1563 + nla_total_size(4) /* IFA_FLAGS */
1564 + nla_total_size(4) /* IFA_RT_PRIORITY */
1552 + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */ 1565 + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
1553} 1566}
1554 1567
@@ -1618,6 +1631,8 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
1618 (ifa->ifa_label[0] && 1631 (ifa->ifa_label[0] &&
1619 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) || 1632 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
1620 nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) || 1633 nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
1634 (ifa->ifa_rt_priority &&
1635 nla_put_u32(skb, IFA_RT_PRIORITY, ifa->ifa_rt_priority)) ||
1621 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp, 1636 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
1622 preferred, valid)) 1637 preferred, valid))
1623 goto nla_put_failure; 1638 goto nla_put_failure;
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index b69e2824c761..63aa39b3af03 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -847,7 +847,8 @@ out_err:
847 * to fib engine. It is legal, because all events occur 847 * to fib engine. It is legal, because all events occur
848 * only when netlink is already locked. 848 * only when netlink is already locked.
849 */ 849 */
850static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa) 850static void fib_magic(int cmd, int type, __be32 dst, int dst_len,
851 struct in_ifaddr *ifa, u32 rt_priority)
851{ 852{
852 struct net *net = dev_net(ifa->ifa_dev->dev); 853 struct net *net = dev_net(ifa->ifa_dev->dev);
853 u32 tb_id = l3mdev_fib_table(ifa->ifa_dev->dev); 854 u32 tb_id = l3mdev_fib_table(ifa->ifa_dev->dev);
@@ -857,6 +858,7 @@ static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifad
857 .fc_type = type, 858 .fc_type = type,
858 .fc_dst = dst, 859 .fc_dst = dst,
859 .fc_dst_len = dst_len, 860 .fc_dst_len = dst_len,
861 .fc_priority = rt_priority,
860 .fc_prefsrc = ifa->ifa_local, 862 .fc_prefsrc = ifa->ifa_local,
861 .fc_oif = ifa->ifa_dev->dev->ifindex, 863 .fc_oif = ifa->ifa_dev->dev->ifindex,
862 .fc_nlflags = NLM_F_CREATE | NLM_F_APPEND, 864 .fc_nlflags = NLM_F_CREATE | NLM_F_APPEND,
@@ -902,31 +904,57 @@ void fib_add_ifaddr(struct in_ifaddr *ifa)
902 } 904 }
903 } 905 }
904 906
905 fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim); 907 fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim, 0);
906 908
907 if (!(dev->flags & IFF_UP)) 909 if (!(dev->flags & IFF_UP))
908 return; 910 return;
909 911
910 /* Add broadcast address, if it is explicitly assigned. */ 912 /* Add broadcast address, if it is explicitly assigned. */
911 if (ifa->ifa_broadcast && ifa->ifa_broadcast != htonl(0xFFFFFFFF)) 913 if (ifa->ifa_broadcast && ifa->ifa_broadcast != htonl(0xFFFFFFFF))
912 fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); 914 fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32,
915 prim, 0);
913 916
914 if (!ipv4_is_zeronet(prefix) && !(ifa->ifa_flags & IFA_F_SECONDARY) && 917 if (!ipv4_is_zeronet(prefix) && !(ifa->ifa_flags & IFA_F_SECONDARY) &&
915 (prefix != addr || ifa->ifa_prefixlen < 32)) { 918 (prefix != addr || ifa->ifa_prefixlen < 32)) {
916 if (!(ifa->ifa_flags & IFA_F_NOPREFIXROUTE)) 919 if (!(ifa->ifa_flags & IFA_F_NOPREFIXROUTE))
917 fib_magic(RTM_NEWROUTE, 920 fib_magic(RTM_NEWROUTE,
918 dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST, 921 dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST,
919 prefix, ifa->ifa_prefixlen, prim); 922 prefix, ifa->ifa_prefixlen, prim,
923 ifa->ifa_rt_priority);
920 924
921 /* Add network specific broadcasts, when it takes a sense */ 925 /* Add network specific broadcasts, when it takes a sense */
922 if (ifa->ifa_prefixlen < 31) { 926 if (ifa->ifa_prefixlen < 31) {
923 fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32, prim); 927 fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32,
928 prim, 0);
924 fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix | ~mask, 929 fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix | ~mask,
925 32, prim); 930 32, prim, 0);
926 } 931 }
927 } 932 }
928} 933}
929 934
935void fib_modify_prefix_metric(struct in_ifaddr *ifa, u32 new_metric)
936{
937 __be32 prefix = ifa->ifa_address & ifa->ifa_mask;
938 struct in_device *in_dev = ifa->ifa_dev;
939 struct net_device *dev = in_dev->dev;
940
941 if (!(dev->flags & IFF_UP) ||
942 ifa->ifa_flags & (IFA_F_SECONDARY | IFA_F_NOPREFIXROUTE) ||
943 ipv4_is_zeronet(prefix) ||
944 prefix == ifa->ifa_local || ifa->ifa_prefixlen == 32)
945 return;
946
947 /* add the new */
948 fib_magic(RTM_NEWROUTE,
949 dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST,
950 prefix, ifa->ifa_prefixlen, ifa, new_metric);
951
952 /* delete the old */
953 fib_magic(RTM_DELROUTE,
954 dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST,
955 prefix, ifa->ifa_prefixlen, ifa, ifa->ifa_rt_priority);
956}
957
930/* Delete primary or secondary address. 958/* Delete primary or secondary address.
931 * Optionally, on secondary address promotion consider the addresses 959 * Optionally, on secondary address promotion consider the addresses
932 * from subnet iprim as deleted, even if they are in device list. 960 * from subnet iprim as deleted, even if they are in device list.
@@ -968,7 +996,7 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
968 if (!(ifa->ifa_flags & IFA_F_NOPREFIXROUTE)) 996 if (!(ifa->ifa_flags & IFA_F_NOPREFIXROUTE))
969 fib_magic(RTM_DELROUTE, 997 fib_magic(RTM_DELROUTE,
970 dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST, 998 dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST,
971 any, ifa->ifa_prefixlen, prim); 999 any, ifa->ifa_prefixlen, prim, 0);
972 subnet = 1; 1000 subnet = 1;
973 } 1001 }
974 1002
@@ -1052,17 +1080,20 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
1052 1080
1053no_promotions: 1081no_promotions:
1054 if (!(ok & BRD_OK)) 1082 if (!(ok & BRD_OK))
1055 fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); 1083 fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32,
1084 prim, 0);
1056 if (subnet && ifa->ifa_prefixlen < 31) { 1085 if (subnet && ifa->ifa_prefixlen < 31) {
1057 if (!(ok & BRD1_OK)) 1086 if (!(ok & BRD1_OK))
1058 fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32, prim); 1087 fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32,
1088 prim, 0);
1059 if (!(ok & BRD0_OK)) 1089 if (!(ok & BRD0_OK))
1060 fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim); 1090 fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32,
1091 prim, 0);
1061 } 1092 }
1062 if (!(ok & LOCAL_OK)) { 1093 if (!(ok & LOCAL_OK)) {
1063 unsigned int addr_type; 1094 unsigned int addr_type;
1064 1095
1065 fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim); 1096 fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim, 0);
1066 1097
1067 /* Check, that this local address finally disappeared. */ 1098 /* Check, that this local address finally disappeared. */
1068 addr_type = inet_addr_type_dev_table(dev_net(dev), dev, 1099 addr_type = inet_addr_type_dev_table(dev_net(dev), dev,