aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Ahern <dsa@cumulusnetworks.com>2016-01-04 12:09:27 -0500
committerDavid S. Miller <davem@davemloft.net>2016-01-04 22:58:30 -0500
commitb5bdacf3bb027ba0af4d61b38ec289bfc8b64372 (patch)
tree1346f43639075874a2c82c5d67dad70a3b95e493
parent7ec2541aa7a026874930d6117e86fe2e76fb1587 (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.c10
-rw-r--r--include/net/l3mdev.h16
-rw-r--r--include/net/route.h7
-rw-r--r--net/ipv4/raw.c7
-rw-r--r--net/ipv4/udp.c7
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 */
803static void vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4) 803static 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
115static inline void l3mdev_get_saddr(struct net *net, int ifindex, 115static 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
134static inline struct dst_entry *l3mdev_get_rt6_dst(const struct net_device *dev, 137static 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
203static inline void l3mdev_get_saddr(struct net *net, int ifindex, 206static 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
208static inline 212static 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);