net/mlx5e: Use hint to resolve route when in HW multipath mode
[linux-2.6-block.git] / drivers / net / ethernet / mellanox / mlx5 / core / en / tc_tun.c
index f3c7ab6faea505202d48d1b0bd862db010e87e99..fa2a3c444cdc604c308999f140a3125becd9c8d3 100644 (file)
@@ -25,7 +25,7 @@ static int get_route_and_out_devs(struct mlx5e_priv *priv,
        /* if the egress device isn't on the same HW e-switch or
         * it's a LAG device, use the uplink
         */
-       if (!switchdev_port_same_parent_id(priv->netdev, dev) ||
+       if (!netdev_port_same_parent_id(priv->netdev, dev) ||
            dst_is_lag_dev) {
                *route_dev = uplink_dev;
                *out_dev = *route_dev;
@@ -54,12 +54,24 @@ static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv,
        struct neighbour *n = NULL;
 
 #if IS_ENABLED(CONFIG_INET)
+       struct mlx5_core_dev *mdev = priv->mdev;
+       struct net_device *uplink_dev;
        int ret;
 
+       if (mlx5_lag_is_multipath(mdev)) {
+               struct mlx5_eswitch *esw = mdev->priv.eswitch;
+
+               uplink_dev = mlx5_eswitch_uplink_get_proto_dev(esw, REP_ETH);
+               fl4->flowi4_oif = uplink_dev->ifindex;
+       }
+
        rt = ip_route_output_key(dev_net(mirred_dev), fl4);
        ret = PTR_ERR_OR_ZERO(rt);
        if (ret)
                return ret;
+
+       if (mlx5_lag_is_multipath(mdev) && !rt->rt_gateway)
+               return -ENETUNREACH;
 #else
        return -EOPNOTSUPP;
 #endif
@@ -295,7 +307,9 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv,
 
        if (!(nud_state & NUD_VALID)) {
                neigh_event_send(n, NULL);
-               err = -EAGAIN;
+               /* the encap entry will be made valid on neigh update event
+                * and not used before that.
+                */
                goto out;
        }
 
@@ -408,7 +422,9 @@ int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv,
 
        if (!(nud_state & NUD_VALID)) {
                neigh_event_send(n, NULL);
-               err = -EAGAIN;
+               /* the encap entry will be made valid on neigh update event
+                * and not used before that.
+                */
                goto out;
        }
 
@@ -498,25 +514,21 @@ static int mlx5e_tc_tun_parse_vxlan(struct mlx5e_priv *priv,
                                    void *headers_c,
                                    void *headers_v)
 {
+       struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
        struct netlink_ext_ack *extack = f->common.extack;
-       struct flow_dissector_key_ports *key =
-               skb_flow_dissector_target(f->dissector,
-                                         FLOW_DISSECTOR_KEY_ENC_PORTS,
-                                         f->key);
-       struct flow_dissector_key_ports *mask =
-               skb_flow_dissector_target(f->dissector,
-                                         FLOW_DISSECTOR_KEY_ENC_PORTS,
-                                         f->mask);
        void *misc_c = MLX5_ADDR_OF(fte_match_param,
                                    spec->match_criteria,
                                    misc_parameters);
        void *misc_v = MLX5_ADDR_OF(fte_match_param,
                                    spec->match_value,
                                    misc_parameters);
+       struct flow_match_ports enc_ports;
+
+       flow_rule_match_enc_ports(rule, &enc_ports);
 
        /* Full udp dst port must be given */
-       if (!dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_PORTS) ||
-           memchr_inv(&mask->dst, 0xff, sizeof(mask->dst))) {
+       if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS) ||
+           memchr_inv(&enc_ports.mask->dst, 0xff, sizeof(enc_ports.mask->dst))) {
                NL_SET_ERR_MSG_MOD(extack,
                                   "VXLAN decap filter must include enc_dst_port condition");
                netdev_warn(priv->netdev,
@@ -525,12 +537,12 @@ static int mlx5e_tc_tun_parse_vxlan(struct mlx5e_priv *priv,
        }
 
        /* udp dst port must be knonwn as a VXLAN port */
-       if (!mlx5_vxlan_lookup_port(priv->mdev->vxlan, be16_to_cpu(key->dst))) {
+       if (!mlx5_vxlan_lookup_port(priv->mdev->vxlan, be16_to_cpu(enc_ports.key->dst))) {
                NL_SET_ERR_MSG_MOD(extack,
                                   "Matched UDP port is not registered as a VXLAN port");
                netdev_warn(priv->netdev,
                            "UDP port %d is not registered as a VXLAN port\n",
-                           be16_to_cpu(key->dst));
+                           be16_to_cpu(enc_ports.key->dst));
                return -EOPNOTSUPP;
        }
 
@@ -538,26 +550,26 @@ static int mlx5e_tc_tun_parse_vxlan(struct mlx5e_priv *priv,
        MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ip_protocol);
        MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP);
 
-       MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_dport, ntohs(mask->dst));
-       MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, ntohs(key->dst));
+       MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_dport,
+                ntohs(enc_ports.mask->dst));
+       MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
+                ntohs(enc_ports.key->dst));
 
-       MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_sport, ntohs(mask->src));
-       MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport, ntohs(key->src));
+       MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_sport,
+                ntohs(enc_ports.mask->src));
+       MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport,
+                ntohs(enc_ports.key->src));
 
        /* match on VNI */
-       if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
-               struct flow_dissector_key_keyid *key =
-                       skb_flow_dissector_target(f->dissector,
-                                                 FLOW_DISSECTOR_KEY_ENC_KEYID,
-                                                 f->key);
-               struct flow_dissector_key_keyid *mask =
-                       skb_flow_dissector_target(f->dissector,
-                                                 FLOW_DISSECTOR_KEY_ENC_KEYID,
-                                                 f->mask);
+       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
+               struct flow_match_enc_keyid enc_keyid;
+
+               flow_rule_match_enc_keyid(rule, &enc_keyid);
+
                MLX5_SET(fte_match_set_misc, misc_c, vxlan_vni,
-                        be32_to_cpu(mask->keyid));
+                        be32_to_cpu(enc_keyid.mask->keyid));
                MLX5_SET(fte_match_set_misc, misc_v, vxlan_vni,
-                        be32_to_cpu(key->keyid));
+                        be32_to_cpu(enc_keyid.key->keyid));
        }
        return 0;
 }
@@ -572,6 +584,7 @@ static int mlx5e_tc_tun_parse_gretap(struct mlx5e_priv *priv,
                                    misc_parameters);
        void *misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
                                    misc_parameters);
+       struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
 
        if (!MLX5_CAP_ESW(priv->mdev, nvgre_encap_decap)) {
                NL_SET_ERR_MSG_MOD(f->common.extack,
@@ -589,21 +602,14 @@ static int mlx5e_tc_tun_parse_gretap(struct mlx5e_priv *priv,
        MLX5_SET(fte_match_set_misc, misc_v, gre_protocol, ETH_P_TEB);
 
        /* gre key */
-       if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
-               struct flow_dissector_key_keyid *mask = NULL;
-               struct flow_dissector_key_keyid *key = NULL;
+       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
+               struct flow_match_enc_keyid enc_keyid;
 
-               mask = skb_flow_dissector_target(f->dissector,
-                                                FLOW_DISSECTOR_KEY_ENC_KEYID,
-                                                f->mask);
+               flow_rule_match_enc_keyid(rule, &enc_keyid);
                MLX5_SET(fte_match_set_misc, misc_c,
-                        gre_key.key, be32_to_cpu(mask->keyid));
-
-               key = skb_flow_dissector_target(f->dissector,
-                                               FLOW_DISSECTOR_KEY_ENC_KEYID,
-                                               f->key);
+                        gre_key.key, be32_to_cpu(enc_keyid.mask->keyid));
                MLX5_SET(fte_match_set_misc, misc_v,
-                        gre_key.key, be32_to_cpu(key->keyid));
+                        gre_key.key, be32_to_cpu(enc_keyid.key->keyid));
        }
 
        return 0;