aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fib_semantics.c
diff options
context:
space:
mode:
authorDavid Ahern <dsahern@gmail.com>2019-04-05 19:30:31 -0400
committerDavid S. Miller <davem@davemloft.net>2019-04-08 18:22:41 -0400
commit448d7248191706cbbd7761e3bc72c2985c4d38a7 (patch)
tree30cf5625d5b433cce8f8b1bca1369249a2c9954b /net/ipv4/fib_semantics.c
parenta4ea5d43c807be28545625c1e0641905022fa0d1 (diff)
ipv4: Refactor fib_check_nh
fib_check_nh is currently huge covering multiple uses cases - device only, device + gateway, and device + gateway with ONLINK. The next patch adds validation checks for IPv6 which only further complicates it. So, break fib_check_nh into 2 helpers - one for gateway validation and one for device only. Signed-off-by: David Ahern <dsahern@gmail.com> Reviewed-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/fib_semantics.c')
-rw-r--r--net/ipv4/fib_semantics.c234
1 files changed, 125 insertions, 109 deletions
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 680b5a9a911a..32ce6e6202d2 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -885,134 +885,150 @@ bool fib_metrics_match(struct fib_config *cfg, struct fib_info *fi)
885 * | 885 * |
886 * |-> {local prefix} (terminal node) 886 * |-> {local prefix} (terminal node)
887 */ 887 */
888static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh, 888static int fib_check_nh_v4_gw(struct net *net, struct fib_nh *nh, u32 table,
889 struct netlink_ext_ack *extack) 889 u8 scope, struct netlink_ext_ack *extack)
890{ 890{
891 int err = 0;
892 struct net *net;
893 struct net_device *dev; 891 struct net_device *dev;
892 struct fib_result res;
893 int err;
894 894
895 net = cfg->fc_nlinfo.nl_net; 895 if (nh->fib_nh_flags & RTNH_F_ONLINK) {
896 if (nh->fib_nh_gw4) { 896 unsigned int addr_type;
897 struct fib_result res;
898
899 if (nh->fib_nh_flags & RTNH_F_ONLINK) {
900 unsigned int addr_type;
901 897
902 if (cfg->fc_scope >= RT_SCOPE_LINK) { 898 if (scope >= RT_SCOPE_LINK) {
903 NL_SET_ERR_MSG(extack, 899 NL_SET_ERR_MSG(extack, "Nexthop has invalid scope");
904 "Nexthop has invalid scope"); 900 return -EINVAL;
905 return -EINVAL;
906 }
907 dev = __dev_get_by_index(net, nh->fib_nh_oif);
908 if (!dev) {
909 NL_SET_ERR_MSG(extack, "Nexthop device required for onlink");
910 return -ENODEV;
911 }
912 if (!(dev->flags & IFF_UP)) {
913 NL_SET_ERR_MSG(extack,
914 "Nexthop device is not up");
915 return -ENETDOWN;
916 }
917 addr_type = inet_addr_type_dev_table(net, dev,
918 nh->fib_nh_gw4);
919 if (addr_type != RTN_UNICAST) {
920 NL_SET_ERR_MSG(extack,
921 "Nexthop has invalid gateway");
922 return -EINVAL;
923 }
924 if (!netif_carrier_ok(dev))
925 nh->fib_nh_flags |= RTNH_F_LINKDOWN;
926 nh->fib_nh_dev = dev;
927 dev_hold(dev);
928 nh->fib_nh_scope = RT_SCOPE_LINK;
929 return 0;
930 } 901 }
931 rcu_read_lock(); 902 dev = __dev_get_by_index(net, nh->fib_nh_oif);
932 { 903 if (!dev) {
933 struct fib_table *tbl = NULL; 904 NL_SET_ERR_MSG(extack, "Nexthop device required for onlink");
934 struct flowi4 fl4 = { 905 return -ENODEV;
935 .daddr = nh->fib_nh_gw4,
936 .flowi4_scope = cfg->fc_scope + 1,
937 .flowi4_oif = nh->fib_nh_oif,
938 .flowi4_iif = LOOPBACK_IFINDEX,
939 };
940
941 /* It is not necessary, but requires a bit of thinking */
942 if (fl4.flowi4_scope < RT_SCOPE_LINK)
943 fl4.flowi4_scope = RT_SCOPE_LINK;
944
945 if (cfg->fc_table)
946 tbl = fib_get_table(net, cfg->fc_table);
947
948 if (tbl)
949 err = fib_table_lookup(tbl, &fl4, &res,
950 FIB_LOOKUP_IGNORE_LINKSTATE |
951 FIB_LOOKUP_NOREF);
952
953 /* on error or if no table given do full lookup. This
954 * is needed for example when nexthops are in the local
955 * table rather than the given table
956 */
957 if (!tbl || err) {
958 err = fib_lookup(net, &fl4, &res,
959 FIB_LOOKUP_IGNORE_LINKSTATE);
960 }
961
962 if (err) {
963 NL_SET_ERR_MSG(extack,
964 "Nexthop has invalid gateway");
965 rcu_read_unlock();
966 return err;
967 }
968 } 906 }
969 err = -EINVAL; 907 if (!(dev->flags & IFF_UP)) {
970 if (res.type != RTN_UNICAST && res.type != RTN_LOCAL) { 908 NL_SET_ERR_MSG(extack, "Nexthop device is not up");
971 NL_SET_ERR_MSG(extack, "Nexthop has invalid gateway"); 909 return -ENETDOWN;
972 goto out;
973 } 910 }
974 nh->fib_nh_scope = res.scope; 911 addr_type = inet_addr_type_dev_table(net, dev, nh->fib_nh_gw4);
975 nh->fib_nh_oif = FIB_RES_OIF(res); 912 if (addr_type != RTN_UNICAST) {
976 nh->fib_nh_dev = dev = FIB_RES_DEV(res); 913 NL_SET_ERR_MSG(extack, "Nexthop has invalid gateway");
977 if (!dev) { 914 return -EINVAL;
978 NL_SET_ERR_MSG(extack,
979 "No egress device for nexthop gateway");
980 goto out;
981 } 915 }
982 dev_hold(dev);
983 if (!netif_carrier_ok(dev)) 916 if (!netif_carrier_ok(dev))
984 nh->fib_nh_flags |= RTNH_F_LINKDOWN; 917 nh->fib_nh_flags |= RTNH_F_LINKDOWN;
985 err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN; 918 nh->fib_nh_dev = dev;
986 } else { 919 dev_hold(dev);
987 struct in_device *in_dev; 920 nh->fib_nh_scope = RT_SCOPE_LINK;
988 921 return 0;
989 if (nh->fib_nh_flags & (RTNH_F_PERVASIVE | RTNH_F_ONLINK)) { 922 }
990 NL_SET_ERR_MSG(extack, 923 rcu_read_lock();
991 "Invalid flags for nexthop - PERVASIVE and ONLINK can not be set"); 924 {
992 return -EINVAL; 925 struct fib_table *tbl = NULL;
926 struct flowi4 fl4 = {
927 .daddr = nh->fib_nh_gw4,
928 .flowi4_scope = scope + 1,
929 .flowi4_oif = nh->fib_nh_oif,
930 .flowi4_iif = LOOPBACK_IFINDEX,
931 };
932
933 /* It is not necessary, but requires a bit of thinking */
934 if (fl4.flowi4_scope < RT_SCOPE_LINK)
935 fl4.flowi4_scope = RT_SCOPE_LINK;
936
937 if (table)
938 tbl = fib_get_table(net, table);
939
940 if (tbl)
941 err = fib_table_lookup(tbl, &fl4, &res,
942 FIB_LOOKUP_IGNORE_LINKSTATE |
943 FIB_LOOKUP_NOREF);
944
945 /* on error or if no table given do full lookup. This
946 * is needed for example when nexthops are in the local
947 * table rather than the given table
948 */
949 if (!tbl || err) {
950 err = fib_lookup(net, &fl4, &res,
951 FIB_LOOKUP_IGNORE_LINKSTATE);
993 } 952 }
994 rcu_read_lock(); 953
995 err = -ENODEV; 954 if (err) {
996 in_dev = inetdev_by_index(net, nh->fib_nh_oif); 955 NL_SET_ERR_MSG(extack, "Nexthop has invalid gateway");
997 if (!in_dev)
998 goto out;
999 err = -ENETDOWN;
1000 if (!(in_dev->dev->flags & IFF_UP)) {
1001 NL_SET_ERR_MSG(extack, "Device for nexthop is not up");
1002 goto out; 956 goto out;
1003 } 957 }
1004 nh->fib_nh_dev = in_dev->dev;
1005 dev_hold(nh->fib_nh_dev);
1006 nh->fib_nh_scope = RT_SCOPE_HOST;
1007 if (!netif_carrier_ok(nh->fib_nh_dev))
1008 nh->fib_nh_flags |= RTNH_F_LINKDOWN;
1009 err = 0;
1010 } 958 }
959
960 err = -EINVAL;
961 if (res.type != RTN_UNICAST && res.type != RTN_LOCAL) {
962 NL_SET_ERR_MSG(extack, "Nexthop has invalid gateway");
963 goto out;
964 }
965 nh->fib_nh_scope = res.scope;
966 nh->fib_nh_oif = FIB_RES_OIF(res);
967 nh->fib_nh_dev = dev = FIB_RES_DEV(res);
968 if (!dev) {
969 NL_SET_ERR_MSG(extack,
970 "No egress device for nexthop gateway");
971 goto out;
972 }
973 dev_hold(dev);
974 if (!netif_carrier_ok(dev))
975 nh->fib_nh_flags |= RTNH_F_LINKDOWN;
976 err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN;
1011out: 977out:
1012 rcu_read_unlock(); 978 rcu_read_unlock();
1013 return err; 979 return err;
1014} 980}
1015 981
982static int fib_check_nh_nongw(struct net *net, struct fib_nh *nh,
983 struct netlink_ext_ack *extack)
984{
985 struct in_device *in_dev;
986 int err;
987
988 if (nh->fib_nh_flags & (RTNH_F_PERVASIVE | RTNH_F_ONLINK)) {
989 NL_SET_ERR_MSG(extack,
990 "Invalid flags for nexthop - PERVASIVE and ONLINK can not be set");
991 return -EINVAL;
992 }
993
994 rcu_read_lock();
995
996 err = -ENODEV;
997 in_dev = inetdev_by_index(net, nh->fib_nh_oif);
998 if (!in_dev)
999 goto out;
1000 err = -ENETDOWN;
1001 if (!(in_dev->dev->flags & IFF_UP)) {
1002 NL_SET_ERR_MSG(extack, "Device for nexthop is not up");
1003 goto out;
1004 }
1005
1006 nh->fib_nh_dev = in_dev->dev;
1007 dev_hold(nh->fib_nh_dev);
1008 nh->fib_nh_scope = RT_SCOPE_HOST;
1009 if (!netif_carrier_ok(nh->fib_nh_dev))
1010 nh->fib_nh_flags |= RTNH_F_LINKDOWN;
1011 err = 0;
1012out:
1013 rcu_read_unlock();
1014 return err;
1015}
1016
1017static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh,
1018 struct netlink_ext_ack *extack)
1019{
1020 struct net *net = cfg->fc_nlinfo.nl_net;
1021 u32 table = cfg->fc_table;
1022 int err;
1023
1024 if (nh->fib_nh_gw_family == AF_INET)
1025 err = fib_check_nh_v4_gw(net, nh, table, cfg->fc_scope, extack);
1026 else
1027 err = fib_check_nh_nongw(net, nh, extack);
1028
1029 return err;
1030}
1031
1016static inline unsigned int fib_laddr_hashfn(__be32 val) 1032static inline unsigned int fib_laddr_hashfn(__be32 val)
1017{ 1033{
1018 unsigned int mask = (fib_info_hash_size - 1); 1034 unsigned int mask = (fib_info_hash_size - 1);