net/ipv6: Refactor gateway validation on route add
authorDavid Ahern <dsahern@gmail.com>
Tue, 13 Mar 2018 15:29:36 +0000 (08:29 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 16 Mar 2018 15:28:38 +0000 (11:28 -0400)
Move gateway validation code from ip6_route_info_create into
ip6_validate_gw. Code move plus adjustments to handle the potential
reset of dev and idev and to make checkpatch happy.

Signed-off-by: David Ahern <dsahern@gmail.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv6/route.c

index 81711e3e26044043a67b87e82167364c32562fb1..23ced851fdb183d23c9444351dd14884cd7e1a9b 100644 (file)
@@ -2550,7 +2550,7 @@ static struct rt6_info *ip6_nh_lookup_table(struct net *net,
 
 static int ip6_route_check_nh_onlink(struct net *net,
                                     struct fib6_config *cfg,
-                                    struct net_device *dev,
+                                    const struct net_device *dev,
                                     struct netlink_ext_ack *extack)
 {
        u32 tbid = l3mdev_fib_table(dev) ? : RT_TABLE_MAIN;
@@ -2626,6 +2626,68 @@ out:
        return err;
 }
 
+static int ip6_validate_gw(struct net *net, struct fib6_config *cfg,
+                          struct net_device **_dev, struct inet6_dev **idev,
+                          struct netlink_ext_ack *extack)
+{
+       const struct in6_addr *gw_addr = &cfg->fc_gateway;
+       int gwa_type = ipv6_addr_type(gw_addr);
+       const struct net_device *dev = *_dev;
+       int err = -EINVAL;
+
+       /* if gw_addr is local we will fail to detect this in case
+        * address is still TENTATIVE (DAD in progress). rt6_lookup()
+        * will return already-added prefix route via interface that
+        * prefix route was assigned to, which might be non-loopback.
+        */
+       if (ipv6_chk_addr_and_flags(net, gw_addr,
+                                   gwa_type & IPV6_ADDR_LINKLOCAL ?
+                                   dev : NULL, 0, 0)) {
+               NL_SET_ERR_MSG(extack, "Invalid gateway address");
+               goto out;
+       }
+
+       if (gwa_type != (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST)) {
+               /* IPv6 strictly inhibits using not link-local
+                * addresses as nexthop address.
+                * Otherwise, router will not able to send redirects.
+                * It is very good, but in some (rare!) circumstances
+                * (SIT, PtP, NBMA NOARP links) it is handy to allow
+                * some exceptions. --ANK
+                * We allow IPv4-mapped nexthops to support RFC4798-type
+                * addressing
+                */
+               if (!(gwa_type & (IPV6_ADDR_UNICAST | IPV6_ADDR_MAPPED))) {
+                       NL_SET_ERR_MSG(extack, "Invalid gateway address");
+                       goto out;
+               }
+
+               if (cfg->fc_flags & RTNH_F_ONLINK)
+                       err = ip6_route_check_nh_onlink(net, cfg, dev, extack);
+               else
+                       err = ip6_route_check_nh(net, cfg, _dev, idev);
+
+               if (err)
+                       goto out;
+       }
+
+       /* reload in case device was changed */
+       dev = *_dev;
+
+       err = -EINVAL;
+       if (!dev) {
+               NL_SET_ERR_MSG(extack, "Egress device not specified");
+               goto out;
+       } else if (dev->flags & IFF_LOOPBACK) {
+               NL_SET_ERR_MSG(extack,
+                              "Egress device can not be loopback device for this route");
+               goto out;
+       }
+       err = 0;
+out:
+       return err;
+}
+
 static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
                                              struct netlink_ext_ack *extack)
 {
@@ -2808,61 +2870,11 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
        }
 
        if (cfg->fc_flags & RTF_GATEWAY) {
-               const struct in6_addr *gw_addr;
-               int gwa_type;
-
-               gw_addr = &cfg->fc_gateway;
-               gwa_type = ipv6_addr_type(gw_addr);
-
-               /* if gw_addr is local we will fail to detect this in case
-                * address is still TENTATIVE (DAD in progress). rt6_lookup()
-                * will return already-added prefix route via interface that
-                * prefix route was assigned to, which might be non-loopback.
-                */
-               err = -EINVAL;
-               if (ipv6_chk_addr_and_flags(net, gw_addr,
-                                           gwa_type & IPV6_ADDR_LINKLOCAL ?
-                                           dev : NULL, 0, 0)) {
-                       NL_SET_ERR_MSG(extack, "Invalid gateway address");
+               err = ip6_validate_gw(net, cfg, &dev, &idev, extack);
+               if (err)
                        goto out;
-               }
-               rt->rt6i_gateway = *gw_addr;
-
-               if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
-                       /* IPv6 strictly inhibits using not link-local
-                          addresses as nexthop address.
-                          Otherwise, router will not able to send redirects.
-                          It is very good, but in some (rare!) circumstances
-                          (SIT, PtP, NBMA NOARP links) it is handy to allow
-                          some exceptions. --ANK
-                          We allow IPv4-mapped nexthops to support RFC4798-type
-                          addressing
-                        */
-                       if (!(gwa_type & (IPV6_ADDR_UNICAST |
-                                         IPV6_ADDR_MAPPED))) {
-                               NL_SET_ERR_MSG(extack,
-                                              "Invalid gateway address");
-                               goto out;
-                       }
 
-                       if (cfg->fc_flags & RTNH_F_ONLINK) {
-                               err = ip6_route_check_nh_onlink(net, cfg, dev,
-                                                               extack);
-                       } else {
-                               err = ip6_route_check_nh(net, cfg, &dev, &idev);
-                       }
-                       if (err)
-                               goto out;
-               }
-               err = -EINVAL;
-               if (!dev) {
-                       NL_SET_ERR_MSG(extack, "Egress device not specified");
-                       goto out;
-               } else if (dev->flags & IFF_LOOPBACK) {
-                       NL_SET_ERR_MSG(extack,
-                                      "Egress device can not be loopback device for this route");
-                       goto out;
-               }
+               rt->rt6i_gateway = cfg->fc_gateway;
        }
 
        err = -ENODEV;