1*0d9f9647SVlad Buslov // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2*0d9f9647SVlad Buslov /* Copyright (c) 2021 Mellanox Technologies. */ 3*0d9f9647SVlad Buslov 4*0d9f9647SVlad Buslov #include "tc_tun_encap.h" 5*0d9f9647SVlad Buslov #include "en_tc.h" 6*0d9f9647SVlad Buslov #include "tc_tun.h" 7*0d9f9647SVlad Buslov #include "rep/tc.h" 8*0d9f9647SVlad Buslov #include "diag/en_tc_tracepoint.h" 9*0d9f9647SVlad Buslov 10*0d9f9647SVlad Buslov int mlx5e_tc_set_attr_rx_tun(struct mlx5e_tc_flow *flow, 11*0d9f9647SVlad Buslov struct mlx5_flow_spec *spec) 12*0d9f9647SVlad Buslov { 13*0d9f9647SVlad Buslov struct mlx5_esw_flow_attr *esw_attr = flow->attr->esw_attr; 14*0d9f9647SVlad Buslov struct mlx5_rx_tun_attr *tun_attr; 15*0d9f9647SVlad Buslov void *daddr, *saddr; 16*0d9f9647SVlad Buslov u8 ip_version; 17*0d9f9647SVlad Buslov 18*0d9f9647SVlad Buslov tun_attr = kvzalloc(sizeof(*tun_attr), GFP_KERNEL); 19*0d9f9647SVlad Buslov if (!tun_attr) 20*0d9f9647SVlad Buslov return -ENOMEM; 21*0d9f9647SVlad Buslov 22*0d9f9647SVlad Buslov esw_attr->rx_tun_attr = tun_attr; 23*0d9f9647SVlad Buslov ip_version = mlx5e_tc_get_ip_version(spec, true); 24*0d9f9647SVlad Buslov 25*0d9f9647SVlad Buslov if (ip_version == 4) { 26*0d9f9647SVlad Buslov daddr = MLX5_ADDR_OF(fte_match_param, spec->match_value, 27*0d9f9647SVlad Buslov outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4); 28*0d9f9647SVlad Buslov saddr = MLX5_ADDR_OF(fte_match_param, spec->match_value, 29*0d9f9647SVlad Buslov outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4); 30*0d9f9647SVlad Buslov tun_attr->dst_ip.v4 = *(__be32 *)daddr; 31*0d9f9647SVlad Buslov tun_attr->src_ip.v4 = *(__be32 *)saddr; 32*0d9f9647SVlad Buslov } 33*0d9f9647SVlad Buslov #if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6) 34*0d9f9647SVlad Buslov else if (ip_version == 6) { 35*0d9f9647SVlad Buslov int ipv6_size = MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6); 36*0d9f9647SVlad Buslov 37*0d9f9647SVlad Buslov daddr = MLX5_ADDR_OF(fte_match_param, spec->match_value, 38*0d9f9647SVlad Buslov outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6); 39*0d9f9647SVlad Buslov saddr = MLX5_ADDR_OF(fte_match_param, spec->match_value, 40*0d9f9647SVlad Buslov outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6); 41*0d9f9647SVlad Buslov memcpy(&tun_attr->dst_ip.v6, daddr, ipv6_size); 42*0d9f9647SVlad Buslov memcpy(&tun_attr->src_ip.v6, saddr, ipv6_size); 43*0d9f9647SVlad Buslov } 44*0d9f9647SVlad Buslov #endif 45*0d9f9647SVlad Buslov return 0; 46*0d9f9647SVlad Buslov } 47*0d9f9647SVlad Buslov 48*0d9f9647SVlad Buslov void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv, 49*0d9f9647SVlad Buslov struct mlx5e_encap_entry *e, 50*0d9f9647SVlad Buslov struct list_head *flow_list) 51*0d9f9647SVlad Buslov { 52*0d9f9647SVlad Buslov struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 53*0d9f9647SVlad Buslov struct mlx5_esw_flow_attr *esw_attr; 54*0d9f9647SVlad Buslov struct mlx5_flow_handle *rule; 55*0d9f9647SVlad Buslov struct mlx5_flow_attr *attr; 56*0d9f9647SVlad Buslov struct mlx5_flow_spec *spec; 57*0d9f9647SVlad Buslov struct mlx5e_tc_flow *flow; 58*0d9f9647SVlad Buslov int err; 59*0d9f9647SVlad Buslov 60*0d9f9647SVlad Buslov e->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev, 61*0d9f9647SVlad Buslov e->reformat_type, 62*0d9f9647SVlad Buslov e->encap_size, e->encap_header, 63*0d9f9647SVlad Buslov MLX5_FLOW_NAMESPACE_FDB); 64*0d9f9647SVlad Buslov if (IS_ERR(e->pkt_reformat)) { 65*0d9f9647SVlad Buslov mlx5_core_warn(priv->mdev, "Failed to offload cached encapsulation header, %lu\n", 66*0d9f9647SVlad Buslov PTR_ERR(e->pkt_reformat)); 67*0d9f9647SVlad Buslov return; 68*0d9f9647SVlad Buslov } 69*0d9f9647SVlad Buslov e->flags |= MLX5_ENCAP_ENTRY_VALID; 70*0d9f9647SVlad Buslov mlx5e_rep_queue_neigh_stats_work(priv); 71*0d9f9647SVlad Buslov 72*0d9f9647SVlad Buslov list_for_each_entry(flow, flow_list, tmp_list) { 73*0d9f9647SVlad Buslov bool all_flow_encaps_valid = true; 74*0d9f9647SVlad Buslov int i; 75*0d9f9647SVlad Buslov 76*0d9f9647SVlad Buslov if (!mlx5e_is_offloaded_flow(flow)) 77*0d9f9647SVlad Buslov continue; 78*0d9f9647SVlad Buslov attr = flow->attr; 79*0d9f9647SVlad Buslov esw_attr = attr->esw_attr; 80*0d9f9647SVlad Buslov spec = &attr->parse_attr->spec; 81*0d9f9647SVlad Buslov 82*0d9f9647SVlad Buslov esw_attr->dests[flow->tmp_efi_index].pkt_reformat = e->pkt_reformat; 83*0d9f9647SVlad Buslov esw_attr->dests[flow->tmp_efi_index].flags |= MLX5_ESW_DEST_ENCAP_VALID; 84*0d9f9647SVlad Buslov /* Flow can be associated with multiple encap entries. 85*0d9f9647SVlad Buslov * Before offloading the flow verify that all of them have 86*0d9f9647SVlad Buslov * a valid neighbour. 87*0d9f9647SVlad Buslov */ 88*0d9f9647SVlad Buslov for (i = 0; i < MLX5_MAX_FLOW_FWD_VPORTS; i++) { 89*0d9f9647SVlad Buslov if (!(esw_attr->dests[i].flags & MLX5_ESW_DEST_ENCAP)) 90*0d9f9647SVlad Buslov continue; 91*0d9f9647SVlad Buslov if (!(esw_attr->dests[i].flags & MLX5_ESW_DEST_ENCAP_VALID)) { 92*0d9f9647SVlad Buslov all_flow_encaps_valid = false; 93*0d9f9647SVlad Buslov break; 94*0d9f9647SVlad Buslov } 95*0d9f9647SVlad Buslov } 96*0d9f9647SVlad Buslov /* Do not offload flows with unresolved neighbors */ 97*0d9f9647SVlad Buslov if (!all_flow_encaps_valid) 98*0d9f9647SVlad Buslov continue; 99*0d9f9647SVlad Buslov /* update from slow path rule to encap rule */ 100*0d9f9647SVlad Buslov rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, attr); 101*0d9f9647SVlad Buslov if (IS_ERR(rule)) { 102*0d9f9647SVlad Buslov err = PTR_ERR(rule); 103*0d9f9647SVlad Buslov mlx5_core_warn(priv->mdev, "Failed to update cached encapsulation flow, %d\n", 104*0d9f9647SVlad Buslov err); 105*0d9f9647SVlad Buslov continue; 106*0d9f9647SVlad Buslov } 107*0d9f9647SVlad Buslov 108*0d9f9647SVlad Buslov mlx5e_tc_unoffload_from_slow_path(esw, flow); 109*0d9f9647SVlad Buslov flow->rule[0] = rule; 110*0d9f9647SVlad Buslov /* was unset when slow path rule removed */ 111*0d9f9647SVlad Buslov flow_flag_set(flow, OFFLOADED); 112*0d9f9647SVlad Buslov } 113*0d9f9647SVlad Buslov } 114*0d9f9647SVlad Buslov 115*0d9f9647SVlad Buslov void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv, 116*0d9f9647SVlad Buslov struct mlx5e_encap_entry *e, 117*0d9f9647SVlad Buslov struct list_head *flow_list) 118*0d9f9647SVlad Buslov { 119*0d9f9647SVlad Buslov struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 120*0d9f9647SVlad Buslov struct mlx5_esw_flow_attr *esw_attr; 121*0d9f9647SVlad Buslov struct mlx5_flow_handle *rule; 122*0d9f9647SVlad Buslov struct mlx5_flow_attr *attr; 123*0d9f9647SVlad Buslov struct mlx5_flow_spec *spec; 124*0d9f9647SVlad Buslov struct mlx5e_tc_flow *flow; 125*0d9f9647SVlad Buslov int err; 126*0d9f9647SVlad Buslov 127*0d9f9647SVlad Buslov list_for_each_entry(flow, flow_list, tmp_list) { 128*0d9f9647SVlad Buslov if (!mlx5e_is_offloaded_flow(flow)) 129*0d9f9647SVlad Buslov continue; 130*0d9f9647SVlad Buslov attr = flow->attr; 131*0d9f9647SVlad Buslov esw_attr = attr->esw_attr; 132*0d9f9647SVlad Buslov spec = &attr->parse_attr->spec; 133*0d9f9647SVlad Buslov 134*0d9f9647SVlad Buslov /* update from encap rule to slow path rule */ 135*0d9f9647SVlad Buslov rule = mlx5e_tc_offload_to_slow_path(esw, flow, spec); 136*0d9f9647SVlad Buslov /* mark the flow's encap dest as non-valid */ 137*0d9f9647SVlad Buslov esw_attr->dests[flow->tmp_efi_index].flags &= ~MLX5_ESW_DEST_ENCAP_VALID; 138*0d9f9647SVlad Buslov 139*0d9f9647SVlad Buslov if (IS_ERR(rule)) { 140*0d9f9647SVlad Buslov err = PTR_ERR(rule); 141*0d9f9647SVlad Buslov mlx5_core_warn(priv->mdev, "Failed to update slow path (encap) flow, %d\n", 142*0d9f9647SVlad Buslov err); 143*0d9f9647SVlad Buslov continue; 144*0d9f9647SVlad Buslov } 145*0d9f9647SVlad Buslov 146*0d9f9647SVlad Buslov mlx5e_tc_unoffload_fdb_rules(esw, flow, attr); 147*0d9f9647SVlad Buslov flow->rule[0] = rule; 148*0d9f9647SVlad Buslov /* was unset when fast path rule removed */ 149*0d9f9647SVlad Buslov flow_flag_set(flow, OFFLOADED); 150*0d9f9647SVlad Buslov } 151*0d9f9647SVlad Buslov 152*0d9f9647SVlad Buslov /* we know that the encap is valid */ 153*0d9f9647SVlad Buslov e->flags &= ~MLX5_ENCAP_ENTRY_VALID; 154*0d9f9647SVlad Buslov mlx5_packet_reformat_dealloc(priv->mdev, e->pkt_reformat); 155*0d9f9647SVlad Buslov } 156*0d9f9647SVlad Buslov 157*0d9f9647SVlad Buslov /* Takes reference to all flows attached to encap and adds the flows to 158*0d9f9647SVlad Buslov * flow_list using 'tmp_list' list_head in mlx5e_tc_flow. 159*0d9f9647SVlad Buslov */ 160*0d9f9647SVlad Buslov void mlx5e_take_all_encap_flows(struct mlx5e_encap_entry *e, struct list_head *flow_list) 161*0d9f9647SVlad Buslov { 162*0d9f9647SVlad Buslov struct encap_flow_item *efi; 163*0d9f9647SVlad Buslov struct mlx5e_tc_flow *flow; 164*0d9f9647SVlad Buslov 165*0d9f9647SVlad Buslov list_for_each_entry(efi, &e->flows, list) { 166*0d9f9647SVlad Buslov flow = container_of(efi, struct mlx5e_tc_flow, encaps[efi->index]); 167*0d9f9647SVlad Buslov if (IS_ERR(mlx5e_flow_get(flow))) 168*0d9f9647SVlad Buslov continue; 169*0d9f9647SVlad Buslov wait_for_completion(&flow->init_done); 170*0d9f9647SVlad Buslov 171*0d9f9647SVlad Buslov flow->tmp_efi_index = efi->index; 172*0d9f9647SVlad Buslov list_add(&flow->tmp_list, flow_list); 173*0d9f9647SVlad Buslov } 174*0d9f9647SVlad Buslov } 175*0d9f9647SVlad Buslov 176*0d9f9647SVlad Buslov static struct mlx5e_encap_entry * 177*0d9f9647SVlad Buslov mlx5e_get_next_valid_encap(struct mlx5e_neigh_hash_entry *nhe, 178*0d9f9647SVlad Buslov struct mlx5e_encap_entry *e) 179*0d9f9647SVlad Buslov { 180*0d9f9647SVlad Buslov struct mlx5e_encap_entry *next = NULL; 181*0d9f9647SVlad Buslov 182*0d9f9647SVlad Buslov retry: 183*0d9f9647SVlad Buslov rcu_read_lock(); 184*0d9f9647SVlad Buslov 185*0d9f9647SVlad Buslov /* find encap with non-zero reference counter value */ 186*0d9f9647SVlad Buslov for (next = e ? 187*0d9f9647SVlad Buslov list_next_or_null_rcu(&nhe->encap_list, 188*0d9f9647SVlad Buslov &e->encap_list, 189*0d9f9647SVlad Buslov struct mlx5e_encap_entry, 190*0d9f9647SVlad Buslov encap_list) : 191*0d9f9647SVlad Buslov list_first_or_null_rcu(&nhe->encap_list, 192*0d9f9647SVlad Buslov struct mlx5e_encap_entry, 193*0d9f9647SVlad Buslov encap_list); 194*0d9f9647SVlad Buslov next; 195*0d9f9647SVlad Buslov next = list_next_or_null_rcu(&nhe->encap_list, 196*0d9f9647SVlad Buslov &next->encap_list, 197*0d9f9647SVlad Buslov struct mlx5e_encap_entry, 198*0d9f9647SVlad Buslov encap_list)) 199*0d9f9647SVlad Buslov if (mlx5e_encap_take(next)) 200*0d9f9647SVlad Buslov break; 201*0d9f9647SVlad Buslov 202*0d9f9647SVlad Buslov rcu_read_unlock(); 203*0d9f9647SVlad Buslov 204*0d9f9647SVlad Buslov /* release starting encap */ 205*0d9f9647SVlad Buslov if (e) 206*0d9f9647SVlad Buslov mlx5e_encap_put(netdev_priv(e->out_dev), e); 207*0d9f9647SVlad Buslov if (!next) 208*0d9f9647SVlad Buslov return next; 209*0d9f9647SVlad Buslov 210*0d9f9647SVlad Buslov /* wait for encap to be fully initialized */ 211*0d9f9647SVlad Buslov wait_for_completion(&next->res_ready); 212*0d9f9647SVlad Buslov /* continue searching if encap entry is not in valid state after completion */ 213*0d9f9647SVlad Buslov if (!(next->flags & MLX5_ENCAP_ENTRY_VALID)) { 214*0d9f9647SVlad Buslov e = next; 215*0d9f9647SVlad Buslov goto retry; 216*0d9f9647SVlad Buslov } 217*0d9f9647SVlad Buslov 218*0d9f9647SVlad Buslov return next; 219*0d9f9647SVlad Buslov } 220*0d9f9647SVlad Buslov 221*0d9f9647SVlad Buslov void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe) 222*0d9f9647SVlad Buslov { 223*0d9f9647SVlad Buslov struct mlx5e_neigh *m_neigh = &nhe->m_neigh; 224*0d9f9647SVlad Buslov struct mlx5e_encap_entry *e = NULL; 225*0d9f9647SVlad Buslov struct mlx5e_tc_flow *flow; 226*0d9f9647SVlad Buslov struct mlx5_fc *counter; 227*0d9f9647SVlad Buslov struct neigh_table *tbl; 228*0d9f9647SVlad Buslov bool neigh_used = false; 229*0d9f9647SVlad Buslov struct neighbour *n; 230*0d9f9647SVlad Buslov u64 lastuse; 231*0d9f9647SVlad Buslov 232*0d9f9647SVlad Buslov if (m_neigh->family == AF_INET) 233*0d9f9647SVlad Buslov tbl = &arp_tbl; 234*0d9f9647SVlad Buslov #if IS_ENABLED(CONFIG_IPV6) 235*0d9f9647SVlad Buslov else if (m_neigh->family == AF_INET6) 236*0d9f9647SVlad Buslov tbl = ipv6_stub->nd_tbl; 237*0d9f9647SVlad Buslov #endif 238*0d9f9647SVlad Buslov else 239*0d9f9647SVlad Buslov return; 240*0d9f9647SVlad Buslov 241*0d9f9647SVlad Buslov /* mlx5e_get_next_valid_encap() releases previous encap before returning 242*0d9f9647SVlad Buslov * next one. 243*0d9f9647SVlad Buslov */ 244*0d9f9647SVlad Buslov while ((e = mlx5e_get_next_valid_encap(nhe, e)) != NULL) { 245*0d9f9647SVlad Buslov struct mlx5e_priv *priv = netdev_priv(e->out_dev); 246*0d9f9647SVlad Buslov struct encap_flow_item *efi, *tmp; 247*0d9f9647SVlad Buslov struct mlx5_eswitch *esw; 248*0d9f9647SVlad Buslov LIST_HEAD(flow_list); 249*0d9f9647SVlad Buslov 250*0d9f9647SVlad Buslov esw = priv->mdev->priv.eswitch; 251*0d9f9647SVlad Buslov mutex_lock(&esw->offloads.encap_tbl_lock); 252*0d9f9647SVlad Buslov list_for_each_entry_safe(efi, tmp, &e->flows, list) { 253*0d9f9647SVlad Buslov flow = container_of(efi, struct mlx5e_tc_flow, 254*0d9f9647SVlad Buslov encaps[efi->index]); 255*0d9f9647SVlad Buslov if (IS_ERR(mlx5e_flow_get(flow))) 256*0d9f9647SVlad Buslov continue; 257*0d9f9647SVlad Buslov list_add(&flow->tmp_list, &flow_list); 258*0d9f9647SVlad Buslov 259*0d9f9647SVlad Buslov if (mlx5e_is_offloaded_flow(flow)) { 260*0d9f9647SVlad Buslov counter = mlx5e_tc_get_counter(flow); 261*0d9f9647SVlad Buslov lastuse = mlx5_fc_query_lastuse(counter); 262*0d9f9647SVlad Buslov if (time_after((unsigned long)lastuse, nhe->reported_lastuse)) { 263*0d9f9647SVlad Buslov neigh_used = true; 264*0d9f9647SVlad Buslov break; 265*0d9f9647SVlad Buslov } 266*0d9f9647SVlad Buslov } 267*0d9f9647SVlad Buslov } 268*0d9f9647SVlad Buslov mutex_unlock(&esw->offloads.encap_tbl_lock); 269*0d9f9647SVlad Buslov 270*0d9f9647SVlad Buslov mlx5e_put_encap_flow_list(priv, &flow_list); 271*0d9f9647SVlad Buslov if (neigh_used) { 272*0d9f9647SVlad Buslov /* release current encap before breaking the loop */ 273*0d9f9647SVlad Buslov mlx5e_encap_put(priv, e); 274*0d9f9647SVlad Buslov break; 275*0d9f9647SVlad Buslov } 276*0d9f9647SVlad Buslov } 277*0d9f9647SVlad Buslov 278*0d9f9647SVlad Buslov trace_mlx5e_tc_update_neigh_used_value(nhe, neigh_used); 279*0d9f9647SVlad Buslov 280*0d9f9647SVlad Buslov if (neigh_used) { 281*0d9f9647SVlad Buslov nhe->reported_lastuse = jiffies; 282*0d9f9647SVlad Buslov 283*0d9f9647SVlad Buslov /* find the relevant neigh according to the cached device and 284*0d9f9647SVlad Buslov * dst ip pair 285*0d9f9647SVlad Buslov */ 286*0d9f9647SVlad Buslov n = neigh_lookup(tbl, &m_neigh->dst_ip, m_neigh->dev); 287*0d9f9647SVlad Buslov if (!n) 288*0d9f9647SVlad Buslov return; 289*0d9f9647SVlad Buslov 290*0d9f9647SVlad Buslov neigh_event_send(n, NULL); 291*0d9f9647SVlad Buslov neigh_release(n); 292*0d9f9647SVlad Buslov } 293*0d9f9647SVlad Buslov } 294*0d9f9647SVlad Buslov 295*0d9f9647SVlad Buslov static void mlx5e_encap_dealloc(struct mlx5e_priv *priv, struct mlx5e_encap_entry *e) 296*0d9f9647SVlad Buslov { 297*0d9f9647SVlad Buslov WARN_ON(!list_empty(&e->flows)); 298*0d9f9647SVlad Buslov 299*0d9f9647SVlad Buslov if (e->compl_result > 0) { 300*0d9f9647SVlad Buslov mlx5e_rep_encap_entry_detach(netdev_priv(e->out_dev), e); 301*0d9f9647SVlad Buslov 302*0d9f9647SVlad Buslov if (e->flags & MLX5_ENCAP_ENTRY_VALID) 303*0d9f9647SVlad Buslov mlx5_packet_reformat_dealloc(priv->mdev, e->pkt_reformat); 304*0d9f9647SVlad Buslov } 305*0d9f9647SVlad Buslov 306*0d9f9647SVlad Buslov kfree(e->tun_info); 307*0d9f9647SVlad Buslov kfree(e->encap_header); 308*0d9f9647SVlad Buslov kfree_rcu(e, rcu); 309*0d9f9647SVlad Buslov } 310*0d9f9647SVlad Buslov 311*0d9f9647SVlad Buslov static void mlx5e_decap_dealloc(struct mlx5e_priv *priv, 312*0d9f9647SVlad Buslov struct mlx5e_decap_entry *d) 313*0d9f9647SVlad Buslov { 314*0d9f9647SVlad Buslov WARN_ON(!list_empty(&d->flows)); 315*0d9f9647SVlad Buslov 316*0d9f9647SVlad Buslov if (!d->compl_result) 317*0d9f9647SVlad Buslov mlx5_packet_reformat_dealloc(priv->mdev, d->pkt_reformat); 318*0d9f9647SVlad Buslov 319*0d9f9647SVlad Buslov kfree_rcu(d, rcu); 320*0d9f9647SVlad Buslov } 321*0d9f9647SVlad Buslov 322*0d9f9647SVlad Buslov void mlx5e_encap_put(struct mlx5e_priv *priv, struct mlx5e_encap_entry *e) 323*0d9f9647SVlad Buslov { 324*0d9f9647SVlad Buslov struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 325*0d9f9647SVlad Buslov 326*0d9f9647SVlad Buslov if (!refcount_dec_and_mutex_lock(&e->refcnt, &esw->offloads.encap_tbl_lock)) 327*0d9f9647SVlad Buslov return; 328*0d9f9647SVlad Buslov hash_del_rcu(&e->encap_hlist); 329*0d9f9647SVlad Buslov mutex_unlock(&esw->offloads.encap_tbl_lock); 330*0d9f9647SVlad Buslov 331*0d9f9647SVlad Buslov mlx5e_encap_dealloc(priv, e); 332*0d9f9647SVlad Buslov } 333*0d9f9647SVlad Buslov 334*0d9f9647SVlad Buslov static void mlx5e_decap_put(struct mlx5e_priv *priv, struct mlx5e_decap_entry *d) 335*0d9f9647SVlad Buslov { 336*0d9f9647SVlad Buslov struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 337*0d9f9647SVlad Buslov 338*0d9f9647SVlad Buslov if (!refcount_dec_and_mutex_lock(&d->refcnt, &esw->offloads.decap_tbl_lock)) 339*0d9f9647SVlad Buslov return; 340*0d9f9647SVlad Buslov hash_del_rcu(&d->hlist); 341*0d9f9647SVlad Buslov mutex_unlock(&esw->offloads.decap_tbl_lock); 342*0d9f9647SVlad Buslov 343*0d9f9647SVlad Buslov mlx5e_decap_dealloc(priv, d); 344*0d9f9647SVlad Buslov } 345*0d9f9647SVlad Buslov 346*0d9f9647SVlad Buslov void mlx5e_detach_encap(struct mlx5e_priv *priv, 347*0d9f9647SVlad Buslov struct mlx5e_tc_flow *flow, int out_index) 348*0d9f9647SVlad Buslov { 349*0d9f9647SVlad Buslov struct mlx5e_encap_entry *e = flow->encaps[out_index].e; 350*0d9f9647SVlad Buslov struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 351*0d9f9647SVlad Buslov 352*0d9f9647SVlad Buslov /* flow wasn't fully initialized */ 353*0d9f9647SVlad Buslov if (!e) 354*0d9f9647SVlad Buslov return; 355*0d9f9647SVlad Buslov 356*0d9f9647SVlad Buslov mutex_lock(&esw->offloads.encap_tbl_lock); 357*0d9f9647SVlad Buslov list_del(&flow->encaps[out_index].list); 358*0d9f9647SVlad Buslov flow->encaps[out_index].e = NULL; 359*0d9f9647SVlad Buslov if (!refcount_dec_and_test(&e->refcnt)) { 360*0d9f9647SVlad Buslov mutex_unlock(&esw->offloads.encap_tbl_lock); 361*0d9f9647SVlad Buslov return; 362*0d9f9647SVlad Buslov } 363*0d9f9647SVlad Buslov hash_del_rcu(&e->encap_hlist); 364*0d9f9647SVlad Buslov mutex_unlock(&esw->offloads.encap_tbl_lock); 365*0d9f9647SVlad Buslov 366*0d9f9647SVlad Buslov mlx5e_encap_dealloc(priv, e); 367*0d9f9647SVlad Buslov } 368*0d9f9647SVlad Buslov 369*0d9f9647SVlad Buslov void mlx5e_detach_decap(struct mlx5e_priv *priv, 370*0d9f9647SVlad Buslov struct mlx5e_tc_flow *flow) 371*0d9f9647SVlad Buslov { 372*0d9f9647SVlad Buslov struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 373*0d9f9647SVlad Buslov struct mlx5e_decap_entry *d = flow->decap_reformat; 374*0d9f9647SVlad Buslov 375*0d9f9647SVlad Buslov if (!d) 376*0d9f9647SVlad Buslov return; 377*0d9f9647SVlad Buslov 378*0d9f9647SVlad Buslov mutex_lock(&esw->offloads.decap_tbl_lock); 379*0d9f9647SVlad Buslov list_del(&flow->l3_to_l2_reformat); 380*0d9f9647SVlad Buslov flow->decap_reformat = NULL; 381*0d9f9647SVlad Buslov 382*0d9f9647SVlad Buslov if (!refcount_dec_and_test(&d->refcnt)) { 383*0d9f9647SVlad Buslov mutex_unlock(&esw->offloads.decap_tbl_lock); 384*0d9f9647SVlad Buslov return; 385*0d9f9647SVlad Buslov } 386*0d9f9647SVlad Buslov hash_del_rcu(&d->hlist); 387*0d9f9647SVlad Buslov mutex_unlock(&esw->offloads.decap_tbl_lock); 388*0d9f9647SVlad Buslov 389*0d9f9647SVlad Buslov mlx5e_decap_dealloc(priv, d); 390*0d9f9647SVlad Buslov } 391*0d9f9647SVlad Buslov 392*0d9f9647SVlad Buslov struct encap_key { 393*0d9f9647SVlad Buslov const struct ip_tunnel_key *ip_tun_key; 394*0d9f9647SVlad Buslov struct mlx5e_tc_tunnel *tc_tunnel; 395*0d9f9647SVlad Buslov }; 396*0d9f9647SVlad Buslov 397*0d9f9647SVlad Buslov static int cmp_encap_info(struct encap_key *a, 398*0d9f9647SVlad Buslov struct encap_key *b) 399*0d9f9647SVlad Buslov { 400*0d9f9647SVlad Buslov return memcmp(a->ip_tun_key, b->ip_tun_key, sizeof(*a->ip_tun_key)) || 401*0d9f9647SVlad Buslov a->tc_tunnel->tunnel_type != b->tc_tunnel->tunnel_type; 402*0d9f9647SVlad Buslov } 403*0d9f9647SVlad Buslov 404*0d9f9647SVlad Buslov static int cmp_decap_info(struct mlx5e_decap_key *a, 405*0d9f9647SVlad Buslov struct mlx5e_decap_key *b) 406*0d9f9647SVlad Buslov { 407*0d9f9647SVlad Buslov return memcmp(&a->key, &b->key, sizeof(b->key)); 408*0d9f9647SVlad Buslov } 409*0d9f9647SVlad Buslov 410*0d9f9647SVlad Buslov static int hash_encap_info(struct encap_key *key) 411*0d9f9647SVlad Buslov { 412*0d9f9647SVlad Buslov return jhash(key->ip_tun_key, sizeof(*key->ip_tun_key), 413*0d9f9647SVlad Buslov key->tc_tunnel->tunnel_type); 414*0d9f9647SVlad Buslov } 415*0d9f9647SVlad Buslov 416*0d9f9647SVlad Buslov static int hash_decap_info(struct mlx5e_decap_key *key) 417*0d9f9647SVlad Buslov { 418*0d9f9647SVlad Buslov return jhash(&key->key, sizeof(key->key), 0); 419*0d9f9647SVlad Buslov } 420*0d9f9647SVlad Buslov 421*0d9f9647SVlad Buslov bool mlx5e_encap_take(struct mlx5e_encap_entry *e) 422*0d9f9647SVlad Buslov { 423*0d9f9647SVlad Buslov return refcount_inc_not_zero(&e->refcnt); 424*0d9f9647SVlad Buslov } 425*0d9f9647SVlad Buslov 426*0d9f9647SVlad Buslov static bool mlx5e_decap_take(struct mlx5e_decap_entry *e) 427*0d9f9647SVlad Buslov { 428*0d9f9647SVlad Buslov return refcount_inc_not_zero(&e->refcnt); 429*0d9f9647SVlad Buslov } 430*0d9f9647SVlad Buslov 431*0d9f9647SVlad Buslov static struct mlx5e_encap_entry * 432*0d9f9647SVlad Buslov mlx5e_encap_get(struct mlx5e_priv *priv, struct encap_key *key, 433*0d9f9647SVlad Buslov uintptr_t hash_key) 434*0d9f9647SVlad Buslov { 435*0d9f9647SVlad Buslov struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 436*0d9f9647SVlad Buslov struct mlx5e_encap_entry *e; 437*0d9f9647SVlad Buslov struct encap_key e_key; 438*0d9f9647SVlad Buslov 439*0d9f9647SVlad Buslov hash_for_each_possible_rcu(esw->offloads.encap_tbl, e, 440*0d9f9647SVlad Buslov encap_hlist, hash_key) { 441*0d9f9647SVlad Buslov e_key.ip_tun_key = &e->tun_info->key; 442*0d9f9647SVlad Buslov e_key.tc_tunnel = e->tunnel; 443*0d9f9647SVlad Buslov if (!cmp_encap_info(&e_key, key) && 444*0d9f9647SVlad Buslov mlx5e_encap_take(e)) 445*0d9f9647SVlad Buslov return e; 446*0d9f9647SVlad Buslov } 447*0d9f9647SVlad Buslov 448*0d9f9647SVlad Buslov return NULL; 449*0d9f9647SVlad Buslov } 450*0d9f9647SVlad Buslov 451*0d9f9647SVlad Buslov static struct mlx5e_decap_entry * 452*0d9f9647SVlad Buslov mlx5e_decap_get(struct mlx5e_priv *priv, struct mlx5e_decap_key *key, 453*0d9f9647SVlad Buslov uintptr_t hash_key) 454*0d9f9647SVlad Buslov { 455*0d9f9647SVlad Buslov struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 456*0d9f9647SVlad Buslov struct mlx5e_decap_key r_key; 457*0d9f9647SVlad Buslov struct mlx5e_decap_entry *e; 458*0d9f9647SVlad Buslov 459*0d9f9647SVlad Buslov hash_for_each_possible_rcu(esw->offloads.decap_tbl, e, 460*0d9f9647SVlad Buslov hlist, hash_key) { 461*0d9f9647SVlad Buslov r_key = e->key; 462*0d9f9647SVlad Buslov if (!cmp_decap_info(&r_key, key) && 463*0d9f9647SVlad Buslov mlx5e_decap_take(e)) 464*0d9f9647SVlad Buslov return e; 465*0d9f9647SVlad Buslov } 466*0d9f9647SVlad Buslov return NULL; 467*0d9f9647SVlad Buslov } 468*0d9f9647SVlad Buslov 469*0d9f9647SVlad Buslov struct ip_tunnel_info *mlx5e_dup_tun_info(const struct ip_tunnel_info *tun_info) 470*0d9f9647SVlad Buslov { 471*0d9f9647SVlad Buslov size_t tun_size = sizeof(*tun_info) + tun_info->options_len; 472*0d9f9647SVlad Buslov 473*0d9f9647SVlad Buslov return kmemdup(tun_info, tun_size, GFP_KERNEL); 474*0d9f9647SVlad Buslov } 475*0d9f9647SVlad Buslov 476*0d9f9647SVlad Buslov static bool is_duplicated_encap_entry(struct mlx5e_priv *priv, 477*0d9f9647SVlad Buslov struct mlx5e_tc_flow *flow, 478*0d9f9647SVlad Buslov int out_index, 479*0d9f9647SVlad Buslov struct mlx5e_encap_entry *e, 480*0d9f9647SVlad Buslov struct netlink_ext_ack *extack) 481*0d9f9647SVlad Buslov { 482*0d9f9647SVlad Buslov int i; 483*0d9f9647SVlad Buslov 484*0d9f9647SVlad Buslov for (i = 0; i < out_index; i++) { 485*0d9f9647SVlad Buslov if (flow->encaps[i].e != e) 486*0d9f9647SVlad Buslov continue; 487*0d9f9647SVlad Buslov NL_SET_ERR_MSG_MOD(extack, "can't duplicate encap action"); 488*0d9f9647SVlad Buslov netdev_err(priv->netdev, "can't duplicate encap action\n"); 489*0d9f9647SVlad Buslov return true; 490*0d9f9647SVlad Buslov } 491*0d9f9647SVlad Buslov 492*0d9f9647SVlad Buslov return false; 493*0d9f9647SVlad Buslov } 494*0d9f9647SVlad Buslov 495*0d9f9647SVlad Buslov static int mlx5e_set_vf_tunnel(struct mlx5_eswitch *esw, 496*0d9f9647SVlad Buslov struct mlx5_flow_attr *attr, 497*0d9f9647SVlad Buslov struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts, 498*0d9f9647SVlad Buslov struct net_device *out_dev, 499*0d9f9647SVlad Buslov int route_dev_ifindex, 500*0d9f9647SVlad Buslov int out_index) 501*0d9f9647SVlad Buslov { 502*0d9f9647SVlad Buslov struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr; 503*0d9f9647SVlad Buslov struct net_device *route_dev; 504*0d9f9647SVlad Buslov u16 vport_num; 505*0d9f9647SVlad Buslov int err = 0; 506*0d9f9647SVlad Buslov u32 data; 507*0d9f9647SVlad Buslov 508*0d9f9647SVlad Buslov route_dev = dev_get_by_index(dev_net(out_dev), route_dev_ifindex); 509*0d9f9647SVlad Buslov 510*0d9f9647SVlad Buslov if (!route_dev || route_dev->netdev_ops != &mlx5e_netdev_ops || 511*0d9f9647SVlad Buslov !mlx5e_tc_is_vf_tunnel(out_dev, route_dev)) 512*0d9f9647SVlad Buslov goto out; 513*0d9f9647SVlad Buslov 514*0d9f9647SVlad Buslov err = mlx5e_tc_query_route_vport(out_dev, route_dev, &vport_num); 515*0d9f9647SVlad Buslov if (err) 516*0d9f9647SVlad Buslov goto out; 517*0d9f9647SVlad Buslov 518*0d9f9647SVlad Buslov attr->dest_chain = 0; 519*0d9f9647SVlad Buslov attr->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR; 520*0d9f9647SVlad Buslov esw_attr->dests[out_index].flags |= MLX5_ESW_DEST_CHAIN_WITH_SRC_PORT_CHANGE; 521*0d9f9647SVlad Buslov data = mlx5_eswitch_get_vport_metadata_for_set(esw_attr->in_mdev->priv.eswitch, 522*0d9f9647SVlad Buslov vport_num); 523*0d9f9647SVlad Buslov err = mlx5e_tc_match_to_reg_set(esw->dev, mod_hdr_acts, 524*0d9f9647SVlad Buslov MLX5_FLOW_NAMESPACE_FDB, VPORT_TO_REG, data); 525*0d9f9647SVlad Buslov if (err) 526*0d9f9647SVlad Buslov goto out; 527*0d9f9647SVlad Buslov 528*0d9f9647SVlad Buslov out: 529*0d9f9647SVlad Buslov if (route_dev) 530*0d9f9647SVlad Buslov dev_put(route_dev); 531*0d9f9647SVlad Buslov return err; 532*0d9f9647SVlad Buslov } 533*0d9f9647SVlad Buslov 534*0d9f9647SVlad Buslov int mlx5e_attach_encap(struct mlx5e_priv *priv, 535*0d9f9647SVlad Buslov struct mlx5e_tc_flow *flow, 536*0d9f9647SVlad Buslov struct net_device *mirred_dev, 537*0d9f9647SVlad Buslov int out_index, 538*0d9f9647SVlad Buslov struct netlink_ext_ack *extack, 539*0d9f9647SVlad Buslov struct net_device **encap_dev, 540*0d9f9647SVlad Buslov bool *encap_valid) 541*0d9f9647SVlad Buslov { 542*0d9f9647SVlad Buslov struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 543*0d9f9647SVlad Buslov struct mlx5e_tc_flow_parse_attr *parse_attr; 544*0d9f9647SVlad Buslov struct mlx5_flow_attr *attr = flow->attr; 545*0d9f9647SVlad Buslov const struct ip_tunnel_info *tun_info; 546*0d9f9647SVlad Buslov struct encap_key key; 547*0d9f9647SVlad Buslov struct mlx5e_encap_entry *e; 548*0d9f9647SVlad Buslov unsigned short family; 549*0d9f9647SVlad Buslov uintptr_t hash_key; 550*0d9f9647SVlad Buslov int err = 0; 551*0d9f9647SVlad Buslov 552*0d9f9647SVlad Buslov parse_attr = attr->parse_attr; 553*0d9f9647SVlad Buslov tun_info = parse_attr->tun_info[out_index]; 554*0d9f9647SVlad Buslov family = ip_tunnel_info_af(tun_info); 555*0d9f9647SVlad Buslov key.ip_tun_key = &tun_info->key; 556*0d9f9647SVlad Buslov key.tc_tunnel = mlx5e_get_tc_tun(mirred_dev); 557*0d9f9647SVlad Buslov if (!key.tc_tunnel) { 558*0d9f9647SVlad Buslov NL_SET_ERR_MSG_MOD(extack, "Unsupported tunnel"); 559*0d9f9647SVlad Buslov return -EOPNOTSUPP; 560*0d9f9647SVlad Buslov } 561*0d9f9647SVlad Buslov 562*0d9f9647SVlad Buslov hash_key = hash_encap_info(&key); 563*0d9f9647SVlad Buslov 564*0d9f9647SVlad Buslov mutex_lock(&esw->offloads.encap_tbl_lock); 565*0d9f9647SVlad Buslov e = mlx5e_encap_get(priv, &key, hash_key); 566*0d9f9647SVlad Buslov 567*0d9f9647SVlad Buslov /* must verify if encap is valid or not */ 568*0d9f9647SVlad Buslov if (e) { 569*0d9f9647SVlad Buslov /* Check that entry was not already attached to this flow */ 570*0d9f9647SVlad Buslov if (is_duplicated_encap_entry(priv, flow, out_index, e, extack)) { 571*0d9f9647SVlad Buslov err = -EOPNOTSUPP; 572*0d9f9647SVlad Buslov goto out_err; 573*0d9f9647SVlad Buslov } 574*0d9f9647SVlad Buslov 575*0d9f9647SVlad Buslov mutex_unlock(&esw->offloads.encap_tbl_lock); 576*0d9f9647SVlad Buslov wait_for_completion(&e->res_ready); 577*0d9f9647SVlad Buslov 578*0d9f9647SVlad Buslov /* Protect against concurrent neigh update. */ 579*0d9f9647SVlad Buslov mutex_lock(&esw->offloads.encap_tbl_lock); 580*0d9f9647SVlad Buslov if (e->compl_result < 0) { 581*0d9f9647SVlad Buslov err = -EREMOTEIO; 582*0d9f9647SVlad Buslov goto out_err; 583*0d9f9647SVlad Buslov } 584*0d9f9647SVlad Buslov goto attach_flow; 585*0d9f9647SVlad Buslov } 586*0d9f9647SVlad Buslov 587*0d9f9647SVlad Buslov e = kzalloc(sizeof(*e), GFP_KERNEL); 588*0d9f9647SVlad Buslov if (!e) { 589*0d9f9647SVlad Buslov err = -ENOMEM; 590*0d9f9647SVlad Buslov goto out_err; 591*0d9f9647SVlad Buslov } 592*0d9f9647SVlad Buslov 593*0d9f9647SVlad Buslov refcount_set(&e->refcnt, 1); 594*0d9f9647SVlad Buslov init_completion(&e->res_ready); 595*0d9f9647SVlad Buslov 596*0d9f9647SVlad Buslov tun_info = mlx5e_dup_tun_info(tun_info); 597*0d9f9647SVlad Buslov if (!tun_info) { 598*0d9f9647SVlad Buslov err = -ENOMEM; 599*0d9f9647SVlad Buslov goto out_err_init; 600*0d9f9647SVlad Buslov } 601*0d9f9647SVlad Buslov e->tun_info = tun_info; 602*0d9f9647SVlad Buslov err = mlx5e_tc_tun_init_encap_attr(mirred_dev, priv, e, extack); 603*0d9f9647SVlad Buslov if (err) 604*0d9f9647SVlad Buslov goto out_err_init; 605*0d9f9647SVlad Buslov 606*0d9f9647SVlad Buslov INIT_LIST_HEAD(&e->flows); 607*0d9f9647SVlad Buslov hash_add_rcu(esw->offloads.encap_tbl, &e->encap_hlist, hash_key); 608*0d9f9647SVlad Buslov mutex_unlock(&esw->offloads.encap_tbl_lock); 609*0d9f9647SVlad Buslov 610*0d9f9647SVlad Buslov if (family == AF_INET) 611*0d9f9647SVlad Buslov err = mlx5e_tc_tun_create_header_ipv4(priv, mirred_dev, e); 612*0d9f9647SVlad Buslov else if (family == AF_INET6) 613*0d9f9647SVlad Buslov err = mlx5e_tc_tun_create_header_ipv6(priv, mirred_dev, e); 614*0d9f9647SVlad Buslov 615*0d9f9647SVlad Buslov /* Protect against concurrent neigh update. */ 616*0d9f9647SVlad Buslov mutex_lock(&esw->offloads.encap_tbl_lock); 617*0d9f9647SVlad Buslov complete_all(&e->res_ready); 618*0d9f9647SVlad Buslov if (err) { 619*0d9f9647SVlad Buslov e->compl_result = err; 620*0d9f9647SVlad Buslov goto out_err; 621*0d9f9647SVlad Buslov } 622*0d9f9647SVlad Buslov e->compl_result = 1; 623*0d9f9647SVlad Buslov 624*0d9f9647SVlad Buslov attach_flow: 625*0d9f9647SVlad Buslov err = mlx5e_set_vf_tunnel(esw, attr, &parse_attr->mod_hdr_acts, e->out_dev, 626*0d9f9647SVlad Buslov e->route_dev_ifindex, out_index); 627*0d9f9647SVlad Buslov if (err) 628*0d9f9647SVlad Buslov goto out_err; 629*0d9f9647SVlad Buslov 630*0d9f9647SVlad Buslov flow->encaps[out_index].e = e; 631*0d9f9647SVlad Buslov list_add(&flow->encaps[out_index].list, &e->flows); 632*0d9f9647SVlad Buslov flow->encaps[out_index].index = out_index; 633*0d9f9647SVlad Buslov *encap_dev = e->out_dev; 634*0d9f9647SVlad Buslov if (e->flags & MLX5_ENCAP_ENTRY_VALID) { 635*0d9f9647SVlad Buslov attr->esw_attr->dests[out_index].pkt_reformat = e->pkt_reformat; 636*0d9f9647SVlad Buslov attr->esw_attr->dests[out_index].flags |= MLX5_ESW_DEST_ENCAP_VALID; 637*0d9f9647SVlad Buslov *encap_valid = true; 638*0d9f9647SVlad Buslov } else { 639*0d9f9647SVlad Buslov *encap_valid = false; 640*0d9f9647SVlad Buslov } 641*0d9f9647SVlad Buslov mutex_unlock(&esw->offloads.encap_tbl_lock); 642*0d9f9647SVlad Buslov 643*0d9f9647SVlad Buslov return err; 644*0d9f9647SVlad Buslov 645*0d9f9647SVlad Buslov out_err: 646*0d9f9647SVlad Buslov mutex_unlock(&esw->offloads.encap_tbl_lock); 647*0d9f9647SVlad Buslov if (e) 648*0d9f9647SVlad Buslov mlx5e_encap_put(priv, e); 649*0d9f9647SVlad Buslov return err; 650*0d9f9647SVlad Buslov 651*0d9f9647SVlad Buslov out_err_init: 652*0d9f9647SVlad Buslov mutex_unlock(&esw->offloads.encap_tbl_lock); 653*0d9f9647SVlad Buslov kfree(tun_info); 654*0d9f9647SVlad Buslov kfree(e); 655*0d9f9647SVlad Buslov return err; 656*0d9f9647SVlad Buslov } 657*0d9f9647SVlad Buslov 658*0d9f9647SVlad Buslov int mlx5e_attach_decap(struct mlx5e_priv *priv, 659*0d9f9647SVlad Buslov struct mlx5e_tc_flow *flow, 660*0d9f9647SVlad Buslov struct netlink_ext_ack *extack) 661*0d9f9647SVlad Buslov { 662*0d9f9647SVlad Buslov struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; 663*0d9f9647SVlad Buslov struct mlx5_esw_flow_attr *attr = flow->attr->esw_attr; 664*0d9f9647SVlad Buslov struct mlx5e_tc_flow_parse_attr *parse_attr; 665*0d9f9647SVlad Buslov struct mlx5e_decap_entry *d; 666*0d9f9647SVlad Buslov struct mlx5e_decap_key key; 667*0d9f9647SVlad Buslov uintptr_t hash_key; 668*0d9f9647SVlad Buslov int err = 0; 669*0d9f9647SVlad Buslov 670*0d9f9647SVlad Buslov parse_attr = flow->attr->parse_attr; 671*0d9f9647SVlad Buslov if (sizeof(parse_attr->eth) > MLX5_CAP_ESW(priv->mdev, max_encap_header_size)) { 672*0d9f9647SVlad Buslov NL_SET_ERR_MSG_MOD(extack, 673*0d9f9647SVlad Buslov "encap header larger than max supported"); 674*0d9f9647SVlad Buslov return -EOPNOTSUPP; 675*0d9f9647SVlad Buslov } 676*0d9f9647SVlad Buslov 677*0d9f9647SVlad Buslov key.key = parse_attr->eth; 678*0d9f9647SVlad Buslov hash_key = hash_decap_info(&key); 679*0d9f9647SVlad Buslov mutex_lock(&esw->offloads.decap_tbl_lock); 680*0d9f9647SVlad Buslov d = mlx5e_decap_get(priv, &key, hash_key); 681*0d9f9647SVlad Buslov if (d) { 682*0d9f9647SVlad Buslov mutex_unlock(&esw->offloads.decap_tbl_lock); 683*0d9f9647SVlad Buslov wait_for_completion(&d->res_ready); 684*0d9f9647SVlad Buslov mutex_lock(&esw->offloads.decap_tbl_lock); 685*0d9f9647SVlad Buslov if (d->compl_result) { 686*0d9f9647SVlad Buslov err = -EREMOTEIO; 687*0d9f9647SVlad Buslov goto out_free; 688*0d9f9647SVlad Buslov } 689*0d9f9647SVlad Buslov goto found; 690*0d9f9647SVlad Buslov } 691*0d9f9647SVlad Buslov 692*0d9f9647SVlad Buslov d = kzalloc(sizeof(*d), GFP_KERNEL); 693*0d9f9647SVlad Buslov if (!d) { 694*0d9f9647SVlad Buslov err = -ENOMEM; 695*0d9f9647SVlad Buslov goto out_err; 696*0d9f9647SVlad Buslov } 697*0d9f9647SVlad Buslov 698*0d9f9647SVlad Buslov d->key = key; 699*0d9f9647SVlad Buslov refcount_set(&d->refcnt, 1); 700*0d9f9647SVlad Buslov init_completion(&d->res_ready); 701*0d9f9647SVlad Buslov INIT_LIST_HEAD(&d->flows); 702*0d9f9647SVlad Buslov hash_add_rcu(esw->offloads.decap_tbl, &d->hlist, hash_key); 703*0d9f9647SVlad Buslov mutex_unlock(&esw->offloads.decap_tbl_lock); 704*0d9f9647SVlad Buslov 705*0d9f9647SVlad Buslov d->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev, 706*0d9f9647SVlad Buslov MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2, 707*0d9f9647SVlad Buslov sizeof(parse_attr->eth), 708*0d9f9647SVlad Buslov &parse_attr->eth, 709*0d9f9647SVlad Buslov MLX5_FLOW_NAMESPACE_FDB); 710*0d9f9647SVlad Buslov if (IS_ERR(d->pkt_reformat)) { 711*0d9f9647SVlad Buslov err = PTR_ERR(d->pkt_reformat); 712*0d9f9647SVlad Buslov d->compl_result = err; 713*0d9f9647SVlad Buslov } 714*0d9f9647SVlad Buslov mutex_lock(&esw->offloads.decap_tbl_lock); 715*0d9f9647SVlad Buslov complete_all(&d->res_ready); 716*0d9f9647SVlad Buslov if (err) 717*0d9f9647SVlad Buslov goto out_free; 718*0d9f9647SVlad Buslov 719*0d9f9647SVlad Buslov found: 720*0d9f9647SVlad Buslov flow->decap_reformat = d; 721*0d9f9647SVlad Buslov attr->decap_pkt_reformat = d->pkt_reformat; 722*0d9f9647SVlad Buslov list_add(&flow->l3_to_l2_reformat, &d->flows); 723*0d9f9647SVlad Buslov mutex_unlock(&esw->offloads.decap_tbl_lock); 724*0d9f9647SVlad Buslov return 0; 725*0d9f9647SVlad Buslov 726*0d9f9647SVlad Buslov out_free: 727*0d9f9647SVlad Buslov mutex_unlock(&esw->offloads.decap_tbl_lock); 728*0d9f9647SVlad Buslov mlx5e_decap_put(priv, d); 729*0d9f9647SVlad Buslov return err; 730*0d9f9647SVlad Buslov 731*0d9f9647SVlad Buslov out_err: 732*0d9f9647SVlad Buslov mutex_unlock(&esw->offloads.decap_tbl_lock); 733*0d9f9647SVlad Buslov return err; 734*0d9f9647SVlad Buslov } 735