ipv4: Initialise ->flowi4_scope properly in ICMP handlers.
authorGuillaume Nault <gnault@redhat.com>
Wed, 20 Apr 2022 23:21:37 +0000 (01:21 +0200)
committerDavid S. Miller <davem@davemloft.net>
Fri, 22 Apr 2022 12:06:03 +0000 (13:06 +0100)
All the *_redirect() and *_update_pmtu() functions initialise their
struct flowi4 variable with either __build_flow_key() or
build_sk_flow_key(). When sk is provided, these functions use
RT_CONN_FLAGS() to set ->flowi4_tos and always use RT_SCOPE_UNIVERSE
for ->flowi4_scope. Then they rely on ip_rt_fix_tos() to adjust the
scope based on the RTO_ONLINK bit and to mask the tos with
IPTOS_RT_MASK.

This patch modifies __build_flow_key() and build_sk_flow_key() to
properly initialise ->flowi4_tos and ->flowi4_scope, so that the
ICMP redirects and PMTU handlers don't need an extra call to
ip_rt_fix_tos() before doing a fib lookup. That is, we:

  * Drop RT_CONN_FLAGS(): use ip_sock_rt_tos() and ip_sock_rt_scope()
    instead, so that we don't have to rely on ip_rt_fix_tos() to adjust
    the scope anymore.

  * Apply IPTOS_RT_MASK to the tos, so that we don't need
    ip_rt_fix_tos() to do it for us.

  * Drop the ip_rt_fix_tos() calls that now become useless.

The only remaining ip_rt_fix_tos() caller is ip_route_output_key_hash()
which needs it as long as external callers still use the RTO_ONLINK
flag.

Note:
  This patch also drops some useless RT_TOS() calls as IPTOS_RT_MASK is
  a stronger mask.

Signed-off-by: Guillaume Nault <gnault@redhat.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/route.c

index d8f82c0ac132e47d8ee519c6dd67987063edd173..ffbe2e4f8c89196e1510fc1d29b6517f63c9d68e 100644 (file)
@@ -508,23 +508,24 @@ static void ip_rt_fix_tos(struct flowi4 *fl4)
 }
 
 static void __build_flow_key(const struct net *net, struct flowi4 *fl4,
-                            const struct sock *sk,
-                            const struct iphdr *iph,
-                            int oif, u8 tos,
-                            u8 prot, u32 mark, int flow_flags)
+                            const struct sock *sk, const struct iphdr *iph,
+                            int oif, __u8 tos, u8 prot, u32 mark,
+                            int flow_flags)
 {
+       __u8 scope = RT_SCOPE_UNIVERSE;
+
        if (sk) {
                const struct inet_sock *inet = inet_sk(sk);
 
                oif = sk->sk_bound_dev_if;
                mark = sk->sk_mark;
-               tos = RT_CONN_FLAGS(sk);
+               tos = ip_sock_rt_tos(sk);
+               scope = ip_sock_rt_scope(sk);
                prot = inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol;
        }
-       flowi4_init_output(fl4, oif, mark, tos,
-                          RT_SCOPE_UNIVERSE, prot,
-                          flow_flags,
-                          iph->daddr, iph->saddr, 0, 0,
+
+       flowi4_init_output(fl4, oif, mark, tos & IPTOS_RT_MASK, scope,
+                          prot, flow_flags, iph->daddr, iph->saddr, 0, 0,
                           sock_net_uid(net, sk));
 }
 
@@ -534,9 +535,9 @@ static void build_skb_flow_key(struct flowi4 *fl4, const struct sk_buff *skb,
        const struct net *net = dev_net(skb->dev);
        const struct iphdr *iph = ip_hdr(skb);
        int oif = skb->dev->ifindex;
-       u8 tos = RT_TOS(iph->tos);
        u8 prot = iph->protocol;
        u32 mark = skb->mark;
+       __u8 tos = iph->tos;
 
        __build_flow_key(net, fl4, sk, iph, oif, tos, prot, mark, 0);
 }
@@ -552,7 +553,8 @@ static void build_sk_flow_key(struct flowi4 *fl4, const struct sock *sk)
        if (inet_opt && inet_opt->opt.srr)
                daddr = inet_opt->opt.faddr;
        flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark,
-                          RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE,
+                          ip_sock_rt_tos(sk) & IPTOS_RT_MASK,
+                          ip_sock_rt_scope(sk),
                           inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
                           inet_sk_flowi_flags(sk),
                           daddr, inet->inet_saddr, 0, 0, sk->sk_uid);
@@ -825,14 +827,13 @@ static void ip_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buf
        const struct iphdr *iph = (const struct iphdr *) skb->data;
        struct net *net = dev_net(skb->dev);
        int oif = skb->dev->ifindex;
-       u8 tos = RT_TOS(iph->tos);
        u8 prot = iph->protocol;
        u32 mark = skb->mark;
+       __u8 tos = iph->tos;
 
        rt = (struct rtable *) dst;
 
        __build_flow_key(net, &fl4, sk, iph, oif, tos, prot, mark, 0);
-       ip_rt_fix_tos(&fl4);
        __ip_do_redirect(rt, skb, &fl4, true);
 }
 
@@ -1061,7 +1062,6 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
        struct flowi4 fl4;
 
        ip_rt_build_flow_key(&fl4, sk, skb);
-       ip_rt_fix_tos(&fl4);
 
        /* Don't make lookup fail for bridged encapsulations */
        if (skb && netif_is_any_bridge_port(skb->dev))
@@ -1078,8 +1078,8 @@ void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu,
        struct rtable *rt;
        u32 mark = IP4_REPLY_MARK(net, skb->mark);
 
-       __build_flow_key(net, &fl4, NULL, iph, oif,
-                        RT_TOS(iph->tos), protocol, mark, 0);
+       __build_flow_key(net, &fl4, NULL, iph, oif, iph->tos, protocol, mark,
+                        0);
        rt = __ip_route_output_key(net, &fl4);
        if (!IS_ERR(rt)) {
                __ip_rt_update_pmtu(rt, &fl4, mtu);
@@ -1136,8 +1136,6 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
                        goto out;
 
                new = true;
-       } else {
-               ip_rt_fix_tos(&fl4);
        }
 
        __ip_rt_update_pmtu((struct rtable *)xfrm_dst_path(&rt->dst), &fl4, mtu);
@@ -1169,8 +1167,7 @@ void ipv4_redirect(struct sk_buff *skb, struct net *net,
        struct flowi4 fl4;
        struct rtable *rt;
 
-       __build_flow_key(net, &fl4, NULL, iph, oif,
-                        RT_TOS(iph->tos), protocol, 0, 0);
+       __build_flow_key(net, &fl4, NULL, iph, oif, iph->tos, protocol, 0, 0);
        rt = __ip_route_output_key(net, &fl4);
        if (!IS_ERR(rt)) {
                __ip_do_redirect(rt, skb, &fl4, false);