diff options
author | David Ahern <dsa@cumulusnetworks.com> | 2016-01-04 12:09:27 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-01-04 22:58:30 -0500 |
commit | b5bdacf3bb027ba0af4d61b38ec289bfc8b64372 (patch) | |
tree | 1346f43639075874a2c82c5d67dad70a3b95e493 | |
parent | 7ec2541aa7a026874930d6117e86fe2e76fb1587 (diff) |
net: Propagate lookup failure in l3mdev_get_saddr to caller
Commands run in a vrf context are not failing as expected on a route lookup:
root@kenny:~# ip ro ls table vrf-red
unreachable default
root@kenny:~# ping -I vrf-red -c1 -w1 10.100.1.254
ping: Warning: source address might be selected on device other than vrf-red.
PING 10.100.1.254 (10.100.1.254) from 0.0.0.0 vrf-red: 56(84) bytes of data.
--- 10.100.1.254 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 999ms
Since the vrf table does not have a route for 10.100.1.254 the ping
should have failed. The saddr lookup causes a full VRF table lookup.
Propogating a lookup failure to the user allows the command to fail as
expected:
root@kenny:~# ping -I vrf-red -c1 -w1 10.100.1.254
connect: No route to host
Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/vrf.c | 10 | ||||
-rw-r--r-- | include/net/l3mdev.h | 16 | ||||
-rw-r--r-- | include/net/route.h | 7 | ||||
-rw-r--r-- | net/ipv4/raw.c | 7 | ||||
-rw-r--r-- | net/ipv4/udp.c | 7 |
5 files changed, 33 insertions, 14 deletions
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 4f9748457f5a..0a242b200df4 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c | |||
@@ -800,7 +800,7 @@ static struct rtable *vrf_get_rtable(const struct net_device *dev, | |||
800 | } | 800 | } |
801 | 801 | ||
802 | /* called under rcu_read_lock */ | 802 | /* called under rcu_read_lock */ |
803 | static void vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4) | 803 | static int vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4) |
804 | { | 804 | { |
805 | struct fib_result res = { .tclassid = 0 }; | 805 | struct fib_result res = { .tclassid = 0 }; |
806 | struct net *net = dev_net(dev); | 806 | struct net *net = dev_net(dev); |
@@ -808,9 +808,10 @@ static void vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4) | |||
808 | u8 flags = fl4->flowi4_flags; | 808 | u8 flags = fl4->flowi4_flags; |
809 | u8 scope = fl4->flowi4_scope; | 809 | u8 scope = fl4->flowi4_scope; |
810 | u8 tos = RT_FL_TOS(fl4); | 810 | u8 tos = RT_FL_TOS(fl4); |
811 | int rc; | ||
811 | 812 | ||
812 | if (unlikely(!fl4->daddr)) | 813 | if (unlikely(!fl4->daddr)) |
813 | return; | 814 | return 0; |
814 | 815 | ||
815 | fl4->flowi4_flags |= FLOWI_FLAG_SKIP_NH_OIF; | 816 | fl4->flowi4_flags |= FLOWI_FLAG_SKIP_NH_OIF; |
816 | fl4->flowi4_iif = LOOPBACK_IFINDEX; | 817 | fl4->flowi4_iif = LOOPBACK_IFINDEX; |
@@ -818,7 +819,8 @@ static void vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4) | |||
818 | fl4->flowi4_scope = ((tos & RTO_ONLINK) ? | 819 | fl4->flowi4_scope = ((tos & RTO_ONLINK) ? |
819 | RT_SCOPE_LINK : RT_SCOPE_UNIVERSE); | 820 | RT_SCOPE_LINK : RT_SCOPE_UNIVERSE); |
820 | 821 | ||
821 | if (!fib_lookup(net, fl4, &res, 0)) { | 822 | rc = fib_lookup(net, fl4, &res, 0); |
823 | if (!rc) { | ||
822 | if (res.type == RTN_LOCAL) | 824 | if (res.type == RTN_LOCAL) |
823 | fl4->saddr = res.fi->fib_prefsrc ? : fl4->daddr; | 825 | fl4->saddr = res.fi->fib_prefsrc ? : fl4->daddr; |
824 | else | 826 | else |
@@ -828,6 +830,8 @@ static void vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4) | |||
828 | fl4->flowi4_flags = flags; | 830 | fl4->flowi4_flags = flags; |
829 | fl4->flowi4_tos = orig_tos; | 831 | fl4->flowi4_tos = orig_tos; |
830 | fl4->flowi4_scope = scope; | 832 | fl4->flowi4_scope = scope; |
833 | |||
834 | return rc; | ||
831 | } | 835 | } |
832 | 836 | ||
833 | #if IS_ENABLED(CONFIG_IPV6) | 837 | #if IS_ENABLED(CONFIG_IPV6) |
diff --git a/include/net/l3mdev.h b/include/net/l3mdev.h index 774d85b2d5d9..5689a0c749f7 100644 --- a/include/net/l3mdev.h +++ b/include/net/l3mdev.h | |||
@@ -29,7 +29,7 @@ struct l3mdev_ops { | |||
29 | /* IPv4 ops */ | 29 | /* IPv4 ops */ |
30 | struct rtable * (*l3mdev_get_rtable)(const struct net_device *dev, | 30 | struct rtable * (*l3mdev_get_rtable)(const struct net_device *dev, |
31 | const struct flowi4 *fl4); | 31 | const struct flowi4 *fl4); |
32 | void (*l3mdev_get_saddr)(struct net_device *dev, | 32 | int (*l3mdev_get_saddr)(struct net_device *dev, |
33 | struct flowi4 *fl4); | 33 | struct flowi4 *fl4); |
34 | 34 | ||
35 | /* IPv6 ops */ | 35 | /* IPv6 ops */ |
@@ -112,10 +112,11 @@ static inline bool netif_index_is_l3_master(struct net *net, int ifindex) | |||
112 | return rc; | 112 | return rc; |
113 | } | 113 | } |
114 | 114 | ||
115 | static inline void l3mdev_get_saddr(struct net *net, int ifindex, | 115 | static inline int l3mdev_get_saddr(struct net *net, int ifindex, |
116 | struct flowi4 *fl4) | 116 | struct flowi4 *fl4) |
117 | { | 117 | { |
118 | struct net_device *dev; | 118 | struct net_device *dev; |
119 | int rc = 0; | ||
119 | 120 | ||
120 | if (ifindex) { | 121 | if (ifindex) { |
121 | 122 | ||
@@ -124,11 +125,13 @@ static inline void l3mdev_get_saddr(struct net *net, int ifindex, | |||
124 | dev = dev_get_by_index_rcu(net, ifindex); | 125 | dev = dev_get_by_index_rcu(net, ifindex); |
125 | if (dev && netif_is_l3_master(dev) && | 126 | if (dev && netif_is_l3_master(dev) && |
126 | dev->l3mdev_ops->l3mdev_get_saddr) { | 127 | dev->l3mdev_ops->l3mdev_get_saddr) { |
127 | dev->l3mdev_ops->l3mdev_get_saddr(dev, fl4); | 128 | rc = dev->l3mdev_ops->l3mdev_get_saddr(dev, fl4); |
128 | } | 129 | } |
129 | 130 | ||
130 | rcu_read_unlock(); | 131 | rcu_read_unlock(); |
131 | } | 132 | } |
133 | |||
134 | return rc; | ||
132 | } | 135 | } |
133 | 136 | ||
134 | static inline struct dst_entry *l3mdev_get_rt6_dst(const struct net_device *dev, | 137 | static inline struct dst_entry *l3mdev_get_rt6_dst(const struct net_device *dev, |
@@ -200,9 +203,10 @@ static inline bool netif_index_is_l3_master(struct net *net, int ifindex) | |||
200 | return false; | 203 | return false; |
201 | } | 204 | } |
202 | 205 | ||
203 | static inline void l3mdev_get_saddr(struct net *net, int ifindex, | 206 | static inline int l3mdev_get_saddr(struct net *net, int ifindex, |
204 | struct flowi4 *fl4) | 207 | struct flowi4 *fl4) |
205 | { | 208 | { |
209 | return 0; | ||
206 | } | 210 | } |
207 | 211 | ||
208 | static inline | 212 | static inline |
diff --git a/include/net/route.h b/include/net/route.h index ee81307863d5..a3b9ef74a389 100644 --- a/include/net/route.h +++ b/include/net/route.h | |||
@@ -283,7 +283,12 @@ static inline struct rtable *ip_route_connect(struct flowi4 *fl4, | |||
283 | sport, dport, sk); | 283 | sport, dport, sk); |
284 | 284 | ||
285 | if (!src && oif) { | 285 | if (!src && oif) { |
286 | l3mdev_get_saddr(net, oif, fl4); | 286 | int rc; |
287 | |||
288 | rc = l3mdev_get_saddr(net, oif, fl4); | ||
289 | if (rc < 0) | ||
290 | return ERR_PTR(rc); | ||
291 | |||
287 | src = fl4->saddr; | 292 | src = fl4->saddr; |
288 | } | 293 | } |
289 | if (!dst || !src) { | 294 | if (!dst || !src) { |
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 63e5be0abd86..bc35f1842512 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c | |||
@@ -601,8 +601,11 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) | |||
601 | (inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0), | 601 | (inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0), |
602 | daddr, saddr, 0, 0); | 602 | daddr, saddr, 0, 0); |
603 | 603 | ||
604 | if (!saddr && ipc.oif) | 604 | if (!saddr && ipc.oif) { |
605 | l3mdev_get_saddr(net, ipc.oif, &fl4); | 605 | err = l3mdev_get_saddr(net, ipc.oif, &fl4); |
606 | if (err < 0) | ||
607 | goto done; | ||
608 | } | ||
606 | 609 | ||
607 | if (!inet->hdrincl) { | 610 | if (!inet->hdrincl) { |
608 | rfv.msg = msg; | 611 | rfv.msg = msg; |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 0c7b0e61b917..c43890848641 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -1025,8 +1025,11 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) | |||
1025 | flow_flags, | 1025 | flow_flags, |
1026 | faddr, saddr, dport, inet->inet_sport); | 1026 | faddr, saddr, dport, inet->inet_sport); |
1027 | 1027 | ||
1028 | if (!saddr && ipc.oif) | 1028 | if (!saddr && ipc.oif) { |
1029 | l3mdev_get_saddr(net, ipc.oif, fl4); | 1029 | err = l3mdev_get_saddr(net, ipc.oif, fl4); |
1030 | if (err < 0) | ||
1031 | goto out; | ||
1032 | } | ||
1030 | 1033 | ||
1031 | security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); | 1034 | security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); |
1032 | rt = ip_route_output_flow(net, fl4, sk); | 1035 | rt = ip_route_output_flow(net, fl4, sk); |