lkml.org 
[lkml]   [2019]   [Aug]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.19 84/85] net/mlx5e: Use flow keys dissector to parse packets for ARFS
    Date
    From: Maxim Mikityanskiy <maximmi@mellanox.com>

    [ Upstream commit 405b93eb764367a670e729da18e54dc42db32620 ]

    The current ARFS code relies on certain fields to be set in the SKB
    (e.g. transport_header) and extracts IP addresses and ports by custom
    code that parses the packet. The necessary SKB fields, however, are not
    always set at that point, which leads to an out-of-bounds access. Use
    skb_flow_dissect_flow_keys() to get the necessary information reliably,
    fix the out-of-bounds access and reuse the code.

    Fixes: 18c908e477dc ("net/mlx5e: Add accelerated RFS support")
    Signed-off-by: Maxim Mikityanskiy <maximmi@mellanox.com>
    Reviewed-by: Tariq Toukan <tariqt@mellanox.com>
    Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c | 97 +++++++---------------
    1 file changed, 34 insertions(+), 63 deletions(-)

    --- a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c
    +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c
    @@ -437,12 +437,6 @@ arfs_hash_bucket(struct arfs_table *arfs
    return &arfs_t->rules_hash[bucket_idx];
    }

    -static u8 arfs_get_ip_proto(const struct sk_buff *skb)
    -{
    - return (skb->protocol == htons(ETH_P_IP)) ?
    - ip_hdr(skb)->protocol : ipv6_hdr(skb)->nexthdr;
    -}
    -
    static struct arfs_table *arfs_get_table(struct mlx5e_arfs_tables *arfs,
    u8 ip_proto, __be16 etype)
    {
    @@ -599,31 +593,9 @@ out:
    arfs_may_expire_flow(priv);
    }

    -/* return L4 destination port from ip4/6 packets */
    -static __be16 arfs_get_dst_port(const struct sk_buff *skb)
    -{
    - char *transport_header;
    -
    - transport_header = skb_transport_header(skb);
    - if (arfs_get_ip_proto(skb) == IPPROTO_TCP)
    - return ((struct tcphdr *)transport_header)->dest;
    - return ((struct udphdr *)transport_header)->dest;
    -}
    -
    -/* return L4 source port from ip4/6 packets */
    -static __be16 arfs_get_src_port(const struct sk_buff *skb)
    -{
    - char *transport_header;
    -
    - transport_header = skb_transport_header(skb);
    - if (arfs_get_ip_proto(skb) == IPPROTO_TCP)
    - return ((struct tcphdr *)transport_header)->source;
    - return ((struct udphdr *)transport_header)->source;
    -}
    -
    static struct arfs_rule *arfs_alloc_rule(struct mlx5e_priv *priv,
    struct arfs_table *arfs_t,
    - const struct sk_buff *skb,
    + const struct flow_keys *fk,
    u16 rxq, u32 flow_id)
    {
    struct arfs_rule *rule;
    @@ -638,19 +610,19 @@ static struct arfs_rule *arfs_alloc_rule
    INIT_WORK(&rule->arfs_work, arfs_handle_work);

    tuple = &rule->tuple;
    - tuple->etype = skb->protocol;
    + tuple->etype = fk->basic.n_proto;
    + tuple->ip_proto = fk->basic.ip_proto;
    if (tuple->etype == htons(ETH_P_IP)) {
    - tuple->src_ipv4 = ip_hdr(skb)->saddr;
    - tuple->dst_ipv4 = ip_hdr(skb)->daddr;
    + tuple->src_ipv4 = fk->addrs.v4addrs.src;
    + tuple->dst_ipv4 = fk->addrs.v4addrs.dst;
    } else {
    - memcpy(&tuple->src_ipv6, &ipv6_hdr(skb)->saddr,
    + memcpy(&tuple->src_ipv6, &fk->addrs.v6addrs.src,
    sizeof(struct in6_addr));
    - memcpy(&tuple->dst_ipv6, &ipv6_hdr(skb)->daddr,
    + memcpy(&tuple->dst_ipv6, &fk->addrs.v6addrs.dst,
    sizeof(struct in6_addr));
    }
    - tuple->ip_proto = arfs_get_ip_proto(skb);
    - tuple->src_port = arfs_get_src_port(skb);
    - tuple->dst_port = arfs_get_dst_port(skb);
    + tuple->src_port = fk->ports.src;
    + tuple->dst_port = fk->ports.dst;

    rule->flow_id = flow_id;
    rule->filter_id = priv->fs.arfs.last_filter_id++ % RPS_NO_FILTER;
    @@ -661,37 +633,33 @@ static struct arfs_rule *arfs_alloc_rule
    return rule;
    }

    -static bool arfs_cmp_ips(struct arfs_tuple *tuple,
    - const struct sk_buff *skb)
    +static bool arfs_cmp(const struct arfs_tuple *tuple, const struct flow_keys *fk)
    {
    - if (tuple->etype == htons(ETH_P_IP) &&
    - tuple->src_ipv4 == ip_hdr(skb)->saddr &&
    - tuple->dst_ipv4 == ip_hdr(skb)->daddr)
    - return true;
    - if (tuple->etype == htons(ETH_P_IPV6) &&
    - (!memcmp(&tuple->src_ipv6, &ipv6_hdr(skb)->saddr,
    - sizeof(struct in6_addr))) &&
    - (!memcmp(&tuple->dst_ipv6, &ipv6_hdr(skb)->daddr,
    - sizeof(struct in6_addr))))
    - return true;
    + if (tuple->src_port != fk->ports.src || tuple->dst_port != fk->ports.dst)
    + return false;
    + if (tuple->etype != fk->basic.n_proto)
    + return false;
    + if (tuple->etype == htons(ETH_P_IP))
    + return tuple->src_ipv4 == fk->addrs.v4addrs.src &&
    + tuple->dst_ipv4 == fk->addrs.v4addrs.dst;
    + if (tuple->etype == htons(ETH_P_IPV6))
    + return !memcmp(&tuple->src_ipv6, &fk->addrs.v6addrs.src,
    + sizeof(struct in6_addr)) &&
    + !memcmp(&tuple->dst_ipv6, &fk->addrs.v6addrs.dst,
    + sizeof(struct in6_addr));
    return false;
    }

    static struct arfs_rule *arfs_find_rule(struct arfs_table *arfs_t,
    - const struct sk_buff *skb)
    + const struct flow_keys *fk)
    {
    struct arfs_rule *arfs_rule;
    struct hlist_head *head;
    - __be16 src_port = arfs_get_src_port(skb);
    - __be16 dst_port = arfs_get_dst_port(skb);

    - head = arfs_hash_bucket(arfs_t, src_port, dst_port);
    + head = arfs_hash_bucket(arfs_t, fk->ports.src, fk->ports.dst);
    hlist_for_each_entry(arfs_rule, head, hlist) {
    - if (arfs_rule->tuple.src_port == src_port &&
    - arfs_rule->tuple.dst_port == dst_port &&
    - arfs_cmp_ips(&arfs_rule->tuple, skb)) {
    + if (arfs_cmp(&arfs_rule->tuple, fk))
    return arfs_rule;
    - }
    }

    return NULL;
    @@ -704,20 +672,24 @@ int mlx5e_rx_flow_steer(struct net_devic
    struct mlx5e_arfs_tables *arfs = &priv->fs.arfs;
    struct arfs_table *arfs_t;
    struct arfs_rule *arfs_rule;
    + struct flow_keys fk;
    +
    + if (!skb_flow_dissect_flow_keys(skb, &fk, 0))
    + return -EPROTONOSUPPORT;

    - if (skb->protocol != htons(ETH_P_IP) &&
    - skb->protocol != htons(ETH_P_IPV6))
    + if (fk.basic.n_proto != htons(ETH_P_IP) &&
    + fk.basic.n_proto != htons(ETH_P_IPV6))
    return -EPROTONOSUPPORT;

    if (skb->encapsulation)
    return -EPROTONOSUPPORT;

    - arfs_t = arfs_get_table(arfs, arfs_get_ip_proto(skb), skb->protocol);
    + arfs_t = arfs_get_table(arfs, fk.basic.ip_proto, fk.basic.n_proto);
    if (!arfs_t)
    return -EPROTONOSUPPORT;

    spin_lock_bh(&arfs->arfs_lock);
    - arfs_rule = arfs_find_rule(arfs_t, skb);
    + arfs_rule = arfs_find_rule(arfs_t, &fk);
    if (arfs_rule) {
    if (arfs_rule->rxq == rxq_index) {
    spin_unlock_bh(&arfs->arfs_lock);
    @@ -725,8 +697,7 @@ int mlx5e_rx_flow_steer(struct net_devic
    }
    arfs_rule->rxq = rxq_index;
    } else {
    - arfs_rule = arfs_alloc_rule(priv, arfs_t, skb,
    - rxq_index, flow_id);
    + arfs_rule = arfs_alloc_rule(priv, arfs_t, &fk, rxq_index, flow_id);
    if (!arfs_rule) {
    spin_unlock_bh(&arfs->arfs_lock);
    return -ENOMEM;

    \
     
     \ /
      Last update: 2019-08-22 19:56    [W:4.451 / U:0.084 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site