aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOr Gerlitz <ogerlitz@mellanox.com>2017-10-17 06:33:43 -0400
committerSaeed Mahameed <saeedm@mellanox.com>2017-10-26 03:47:27 -0400
commit3c37745ec614ff048d5dce38f976804b05d307ee (patch)
tree60df9abe2901def1827f7fc166b88f4ccb98b7ae
parent4ca637a20a524cd8ddbca696f12bfa92111c96e3 (diff)
net/mlx5e: Properly deal with encap flows add/del under neigh update
Currently, the encap action offload is handled in the actions parse function and not in mlx5e_tc_add_fdb_flow() where we deal with all the other aspects of offloading actions (vlan, modify header) and the rule itself. When the neigh update code (mlx5e_tc_encap_flows_add()) recreates the encap entry and offloads the related flows, we wrongly call again into mlx5e_tc_add_fdb_flow(), this for itself would cause us to handle again the offloading of vlans and header re-write which puts things in non consistent state and step on freed memory (e.g the modify header parse buffer which is already freed). Since on error, mlx5e_tc_add_fdb_flow() detaches and may release the encap entry, it causes a corruption at the neigh update code which goes over the list of flows associated with this encap entry, or double free when the tc flow is later deleted by user-space. When neigh update (mlx5e_tc_encap_flows_del()) unoffloads the flows related to an encap entry which is now invalid, we do a partial repeat of the eswitch flow removal code which is wrong too. To fix things up we do the following: (1) handle the encap action offload in the eswitch flow add function mlx5e_tc_add_fdb_flow() as done for the other actions and the rule itself. (2) modify the neigh update code (mlx5e_tc_encap_flows_add/del) to only deal with the encap entry and rules delete/add and not with any of the other offloaded actions. Fixes: 232c001398ae ('net/mlx5e: Add support to neighbour update flow') Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com> Reviewed-by: Paul Blakey <paulb@mellanox.com> Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tc.c89
1 files changed, 54 insertions, 35 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index 1aa2028ed995..9ba1f72060aa 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -78,9 +78,11 @@ struct mlx5e_tc_flow {
78}; 78};
79 79
80struct mlx5e_tc_flow_parse_attr { 80struct mlx5e_tc_flow_parse_attr {
81 struct ip_tunnel_info tun_info;
81 struct mlx5_flow_spec spec; 82 struct mlx5_flow_spec spec;
82 int num_mod_hdr_actions; 83 int num_mod_hdr_actions;
83 void *mod_hdr_actions; 84 void *mod_hdr_actions;
85 int mirred_ifindex;
84}; 86};
85 87
86enum { 88enum {
@@ -322,6 +324,12 @@ static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
322static void mlx5e_detach_encap(struct mlx5e_priv *priv, 324static void mlx5e_detach_encap(struct mlx5e_priv *priv,
323 struct mlx5e_tc_flow *flow); 325 struct mlx5e_tc_flow *flow);
324 326
327static int mlx5e_attach_encap(struct mlx5e_priv *priv,
328 struct ip_tunnel_info *tun_info,
329 struct net_device *mirred_dev,
330 struct net_device **encap_dev,
331 struct mlx5e_tc_flow *flow);
332
325static struct mlx5_flow_handle * 333static struct mlx5_flow_handle *
326mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, 334mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
327 struct mlx5e_tc_flow_parse_attr *parse_attr, 335 struct mlx5e_tc_flow_parse_attr *parse_attr,
@@ -329,9 +337,27 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
329{ 337{
330 struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 338 struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
331 struct mlx5_esw_flow_attr *attr = flow->esw_attr; 339 struct mlx5_esw_flow_attr *attr = flow->esw_attr;
332 struct mlx5_flow_handle *rule; 340 struct net_device *out_dev, *encap_dev = NULL;
341 struct mlx5_flow_handle *rule = NULL;
342 struct mlx5e_rep_priv *rpriv;
343 struct mlx5e_priv *out_priv;
333 int err; 344 int err;
334 345
346 if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) {
347 out_dev = __dev_get_by_index(dev_net(priv->netdev),
348 attr->parse_attr->mirred_ifindex);
349 err = mlx5e_attach_encap(priv, &parse_attr->tun_info,
350 out_dev, &encap_dev, flow);
351 if (err) {
352 rule = ERR_PTR(err);
353 if (err != -EAGAIN)
354 goto err_attach_encap;
355 }
356 out_priv = netdev_priv(encap_dev);
357 rpriv = out_priv->ppriv;
358 attr->out_rep = rpriv->rep;
359 }
360
335 err = mlx5_eswitch_add_vlan_action(esw, attr); 361 err = mlx5_eswitch_add_vlan_action(esw, attr);
336 if (err) { 362 if (err) {
337 rule = ERR_PTR(err); 363 rule = ERR_PTR(err);
@@ -347,10 +373,14 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
347 } 373 }
348 } 374 }
349 375
350 rule = mlx5_eswitch_add_offloaded_rule(esw, &parse_attr->spec, attr); 376 /* we get here if (1) there's no error (rule being null) or when
351 if (IS_ERR(rule)) 377 * (2) there's an encap action and we're on -EAGAIN (no valid neigh)
352 goto err_add_rule; 378 */
353 379 if (rule != ERR_PTR(-EAGAIN)) {
380 rule = mlx5_eswitch_add_offloaded_rule(esw, &parse_attr->spec, attr);
381 if (IS_ERR(rule))
382 goto err_add_rule;
383 }
354 return rule; 384 return rule;
355 385
356err_add_rule: 386err_add_rule:
@@ -361,6 +391,7 @@ err_mod_hdr:
361err_add_vlan: 391err_add_vlan:
362 if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) 392 if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP)
363 mlx5e_detach_encap(priv, flow); 393 mlx5e_detach_encap(priv, flow);
394err_attach_encap:
364 return rule; 395 return rule;
365} 396}
366 397
@@ -389,6 +420,8 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
389void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv, 420void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
390 struct mlx5e_encap_entry *e) 421 struct mlx5e_encap_entry *e)
391{ 422{
423 struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
424 struct mlx5_esw_flow_attr *esw_attr;
392 struct mlx5e_tc_flow *flow; 425 struct mlx5e_tc_flow *flow;
393 int err; 426 int err;
394 427
@@ -404,10 +437,9 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
404 mlx5e_rep_queue_neigh_stats_work(priv); 437 mlx5e_rep_queue_neigh_stats_work(priv);
405 438
406 list_for_each_entry(flow, &e->flows, encap) { 439 list_for_each_entry(flow, &e->flows, encap) {
407 flow->esw_attr->encap_id = e->encap_id; 440 esw_attr = flow->esw_attr;
408 flow->rule = mlx5e_tc_add_fdb_flow(priv, 441 esw_attr->encap_id = e->encap_id;
409 flow->esw_attr->parse_attr, 442 flow->rule = mlx5_eswitch_add_offloaded_rule(esw, &esw_attr->parse_attr->spec, esw_attr);
410 flow);
411 if (IS_ERR(flow->rule)) { 443 if (IS_ERR(flow->rule)) {
412 err = PTR_ERR(flow->rule); 444 err = PTR_ERR(flow->rule);
413 mlx5_core_warn(priv->mdev, "Failed to update cached encapsulation flow, %d\n", 445 mlx5_core_warn(priv->mdev, "Failed to update cached encapsulation flow, %d\n",
@@ -421,15 +453,13 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
421void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv, 453void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
422 struct mlx5e_encap_entry *e) 454 struct mlx5e_encap_entry *e)
423{ 455{
456 struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
424 struct mlx5e_tc_flow *flow; 457 struct mlx5e_tc_flow *flow;
425 struct mlx5_fc *counter;
426 458
427 list_for_each_entry(flow, &e->flows, encap) { 459 list_for_each_entry(flow, &e->flows, encap) {
428 if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) { 460 if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) {
429 flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED; 461 flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED;
430 counter = mlx5_flow_rule_counter(flow->rule); 462 mlx5_eswitch_del_offloaded_rule(esw, flow->rule, flow->esw_attr);
431 mlx5_del_flow_rules(flow->rule);
432 mlx5_fc_destroy(priv->mdev, counter);
433 } 463 }
434 } 464 }
435 465
@@ -1942,7 +1972,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
1942 1972
1943 if (is_tcf_mirred_egress_redirect(a)) { 1973 if (is_tcf_mirred_egress_redirect(a)) {
1944 int ifindex = tcf_mirred_ifindex(a); 1974 int ifindex = tcf_mirred_ifindex(a);
1945 struct net_device *out_dev, *encap_dev = NULL; 1975 struct net_device *out_dev;
1946 struct mlx5e_priv *out_priv; 1976 struct mlx5e_priv *out_priv;
1947 1977
1948 out_dev = __dev_get_by_index(dev_net(priv->netdev), ifindex); 1978 out_dev = __dev_get_by_index(dev_net(priv->netdev), ifindex);
@@ -1955,17 +1985,13 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
1955 rpriv = out_priv->ppriv; 1985 rpriv = out_priv->ppriv;
1956 attr->out_rep = rpriv->rep; 1986 attr->out_rep = rpriv->rep;
1957 } else if (encap) { 1987 } else if (encap) {
1958 err = mlx5e_attach_encap(priv, info, 1988 parse_attr->mirred_ifindex = ifindex;
1959 out_dev, &encap_dev, flow); 1989 parse_attr->tun_info = *info;
1960 if (err && err != -EAGAIN) 1990 attr->parse_attr = parse_attr;
1961 return err;
1962 attr->action |= MLX5_FLOW_CONTEXT_ACTION_ENCAP | 1991 attr->action |= MLX5_FLOW_CONTEXT_ACTION_ENCAP |
1963 MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | 1992 MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
1964 MLX5_FLOW_CONTEXT_ACTION_COUNT; 1993 MLX5_FLOW_CONTEXT_ACTION_COUNT;
1965 out_priv = netdev_priv(encap_dev); 1994 /* attr->out_rep is resolved when we handle encap */
1966 rpriv = out_priv->ppriv;
1967 attr->out_rep = rpriv->rep;
1968 attr->parse_attr = parse_attr;
1969 } else { 1995 } else {
1970 pr_err("devices %s %s not on same switch HW, can't offload forwarding\n", 1996 pr_err("devices %s %s not on same switch HW, can't offload forwarding\n",
1971 priv->netdev->name, out_dev->name); 1997 priv->netdev->name, out_dev->name);
@@ -2047,7 +2073,7 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv,
2047 if (flow->flags & MLX5E_TC_FLOW_ESWITCH) { 2073 if (flow->flags & MLX5E_TC_FLOW_ESWITCH) {
2048 err = parse_tc_fdb_actions(priv, f->exts, parse_attr, flow); 2074 err = parse_tc_fdb_actions(priv, f->exts, parse_attr, flow);
2049 if (err < 0) 2075 if (err < 0)
2050 goto err_handle_encap_flow; 2076 goto err_free;
2051 flow->rule = mlx5e_tc_add_fdb_flow(priv, parse_attr, flow); 2077 flow->rule = mlx5e_tc_add_fdb_flow(priv, parse_attr, flow);
2052 } else { 2078 } else {
2053 err = parse_tc_nic_actions(priv, f->exts, parse_attr, flow); 2079 err = parse_tc_nic_actions(priv, f->exts, parse_attr, flow);
@@ -2058,10 +2084,13 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv,
2058 2084
2059 if (IS_ERR(flow->rule)) { 2085 if (IS_ERR(flow->rule)) {
2060 err = PTR_ERR(flow->rule); 2086 err = PTR_ERR(flow->rule);
2061 goto err_free; 2087 if (err != -EAGAIN)
2088 goto err_free;
2062 } 2089 }
2063 2090
2064 flow->flags |= MLX5E_TC_FLOW_OFFLOADED; 2091 if (err != -EAGAIN)
2092 flow->flags |= MLX5E_TC_FLOW_OFFLOADED;
2093
2065 err = rhashtable_insert_fast(&tc->ht, &flow->node, 2094 err = rhashtable_insert_fast(&tc->ht, &flow->node,
2066 tc->ht_params); 2095 tc->ht_params);
2067 if (err) 2096 if (err)
@@ -2075,16 +2104,6 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv,
2075err_del_rule: 2104err_del_rule:
2076 mlx5e_tc_del_flow(priv, flow); 2105 mlx5e_tc_del_flow(priv, flow);
2077 2106
2078err_handle_encap_flow:
2079 if (err == -EAGAIN) {
2080 err = rhashtable_insert_fast(&tc->ht, &flow->node,
2081 tc->ht_params);
2082 if (err)
2083 mlx5e_tc_del_flow(priv, flow);
2084 else
2085 return 0;
2086 }
2087
2088err_free: 2107err_free:
2089 kvfree(parse_attr); 2108 kvfree(parse_attr);
2090 kfree(flow); 2109 kfree(flow);