1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2014-2021 Broadcom 3 * All rights reserved. 4 */ 5 6 #include <rte_malloc.h> 7 8 #include "ulp_tun.h" 9 #include "ulp_rte_parser.h" 10 #include "ulp_template_db_enum.h" 11 #include "ulp_template_struct.h" 12 #include "ulp_matcher.h" 13 #include "ulp_mapper.h" 14 #include "ulp_flow_db.h" 15 16 /* This function programs the outer tunnel flow in the hardware. */ 17 static int32_t 18 ulp_install_outer_tun_flow(struct ulp_rte_parser_params *params, 19 struct bnxt_tun_cache_entry *tun_entry, 20 uint16_t tun_idx) 21 { 22 struct bnxt_ulp_mapper_create_parms mparms = { 0 }; 23 int ret; 24 25 /* Reset the JUMP action bit in the action bitmap as we don't 26 * offload this action. 27 */ 28 ULP_BITMAP_RESET(params->act_bitmap.bits, BNXT_ULP_ACTION_BIT_JUMP); 29 30 ULP_BITMAP_SET(params->hdr_bitmap.bits, BNXT_ULP_HDR_BIT_F1); 31 32 ret = ulp_matcher_pattern_match(params, ¶ms->class_id); 33 if (ret != BNXT_TF_RC_SUCCESS) 34 goto err; 35 36 ret = ulp_matcher_action_match(params, ¶ms->act_tmpl); 37 if (ret != BNXT_TF_RC_SUCCESS) 38 goto err; 39 40 params->parent_flow = true; 41 bnxt_ulp_init_mapper_params(&mparms, params, 42 BNXT_ULP_FDB_TYPE_REGULAR); 43 mparms.tun_idx = tun_idx; 44 45 /* Call the ulp mapper to create the flow in the hardware. */ 46 ret = ulp_mapper_flow_create(params->ulp_ctx, &mparms); 47 if (ret) 48 goto err; 49 50 /* Store the tunnel dmac in the tunnel cache table and use it while 51 * programming tunnel flow F2. 52 */ 53 memcpy(tun_entry->t_dmac, 54 ¶ms->hdr_field[ULP_TUN_O_DMAC_HDR_FIELD_INDEX].spec, 55 RTE_ETHER_ADDR_LEN); 56 57 tun_entry->valid = true; 58 tun_entry->tun_flow_info[params->port_id].state = 59 BNXT_ULP_FLOW_STATE_TUN_O_OFFLD; 60 tun_entry->outer_tun_flow_id = params->fid; 61 62 /* F1 and it's related F2s are correlated based on 63 * Tunnel Destination IP Address. 64 */ 65 if (tun_entry->t_dst_ip_valid) 66 goto done; 67 if (ULP_BITMAP_ISSET(params->hdr_bitmap.bits, BNXT_ULP_HDR_BIT_O_IPV4)) 68 memcpy(&tun_entry->t_dst_ip, 69 ¶ms->hdr_field[ULP_TUN_O_IPV4_DIP_INDEX].spec, 70 sizeof(rte_be32_t)); 71 else 72 memcpy(tun_entry->t_dst_ip6, 73 ¶ms->hdr_field[ULP_TUN_O_IPV6_DIP_INDEX].spec, 74 sizeof(tun_entry->t_dst_ip6)); 75 tun_entry->t_dst_ip_valid = true; 76 77 done: 78 return BNXT_TF_RC_FID; 79 80 err: 81 memset(tun_entry, 0, sizeof(struct bnxt_tun_cache_entry)); 82 return BNXT_TF_RC_ERROR; 83 } 84 85 /* This function programs the inner tunnel flow in the hardware. */ 86 static void 87 ulp_install_inner_tun_flow(struct bnxt_tun_cache_entry *tun_entry, 88 struct ulp_rte_parser_params *tun_o_params) 89 { 90 struct bnxt_ulp_mapper_create_parms mparms = { 0 }; 91 struct ulp_per_port_flow_info *flow_info; 92 struct ulp_rte_parser_params *params; 93 int ret; 94 95 /* F2 doesn't have tunnel dmac, use the tunnel dmac that was 96 * stored during F1 programming. 97 */ 98 flow_info = &tun_entry->tun_flow_info[tun_o_params->port_id]; 99 params = &flow_info->first_inner_tun_params; 100 memcpy(¶ms->hdr_field[ULP_TUN_O_DMAC_HDR_FIELD_INDEX], 101 tun_entry->t_dmac, RTE_ETHER_ADDR_LEN); 102 params->parent_fid = tun_entry->outer_tun_flow_id; 103 params->fid = flow_info->first_tun_i_fid; 104 105 bnxt_ulp_init_mapper_params(&mparms, params, 106 BNXT_ULP_FDB_TYPE_REGULAR); 107 108 ret = ulp_mapper_flow_create(params->ulp_ctx, &mparms); 109 if (ret) 110 PMD_DRV_LOG(ERR, "Failed to create F2 flow."); 111 } 112 113 /* This function either install outer tunnel flow & inner tunnel flow 114 * or just the outer tunnel flow based on the flow state. 115 */ 116 static int32_t 117 ulp_post_process_outer_tun_flow(struct ulp_rte_parser_params *params, 118 struct bnxt_tun_cache_entry *tun_entry, 119 uint16_t tun_idx) 120 { 121 enum bnxt_ulp_tun_flow_state flow_state; 122 int ret; 123 124 flow_state = tun_entry->tun_flow_info[params->port_id].state; 125 ret = ulp_install_outer_tun_flow(params, tun_entry, tun_idx); 126 if (ret == BNXT_TF_RC_ERROR) { 127 PMD_DRV_LOG(ERR, "Failed to create outer tunnel flow."); 128 return ret; 129 } 130 131 /* If flow_state == BNXT_ULP_FLOW_STATE_NORMAL before installing 132 * F1, that means F2 is not deferred. Hence, no need to install F2. 133 */ 134 if (flow_state != BNXT_ULP_FLOW_STATE_NORMAL) 135 ulp_install_inner_tun_flow(tun_entry, params); 136 137 return BNXT_TF_RC_FID; 138 } 139 140 /* This function will be called if inner tunnel flow request comes before 141 * outer tunnel flow request. 142 */ 143 static int32_t 144 ulp_post_process_first_inner_tun_flow(struct ulp_rte_parser_params *params, 145 struct bnxt_tun_cache_entry *tun_entry) 146 { 147 struct ulp_per_port_flow_info *flow_info; 148 int ret; 149 150 ret = ulp_matcher_pattern_match(params, ¶ms->class_id); 151 if (ret != BNXT_TF_RC_SUCCESS) 152 return BNXT_TF_RC_ERROR; 153 154 ret = ulp_matcher_action_match(params, ¶ms->act_tmpl); 155 if (ret != BNXT_TF_RC_SUCCESS) 156 return BNXT_TF_RC_ERROR; 157 158 /* If Tunnel F2 flow comes first then we can't install it in the 159 * hardware, because, F2 flow will not have L2 context information. 160 * So, just cache the F2 information and program it in the context 161 * of F1 flow installation. 162 */ 163 flow_info = &tun_entry->tun_flow_info[params->port_id]; 164 memcpy(&flow_info->first_inner_tun_params, params, 165 sizeof(struct ulp_rte_parser_params)); 166 167 flow_info->first_tun_i_fid = params->fid; 168 flow_info->state = BNXT_ULP_FLOW_STATE_TUN_I_CACHED; 169 170 /* F1 and it's related F2s are correlated based on 171 * Tunnel Destination IP Address. It could be already set, if 172 * the inner flow got offloaded first. 173 */ 174 if (tun_entry->t_dst_ip_valid) 175 goto done; 176 if (ULP_BITMAP_ISSET(params->hdr_bitmap.bits, BNXT_ULP_HDR_BIT_O_IPV4)) 177 memcpy(&tun_entry->t_dst_ip, 178 ¶ms->hdr_field[ULP_TUN_O_IPV4_DIP_INDEX].spec, 179 sizeof(rte_be32_t)); 180 else 181 memcpy(tun_entry->t_dst_ip6, 182 ¶ms->hdr_field[ULP_TUN_O_IPV6_DIP_INDEX].spec, 183 sizeof(tun_entry->t_dst_ip6)); 184 tun_entry->t_dst_ip_valid = true; 185 186 done: 187 return BNXT_TF_RC_FID; 188 } 189 190 /* This function will be called if inner tunnel flow request comes after 191 * the outer tunnel flow request. 192 */ 193 static int32_t 194 ulp_post_process_inner_tun_flow(struct ulp_rte_parser_params *params, 195 struct bnxt_tun_cache_entry *tun_entry) 196 { 197 memcpy(¶ms->hdr_field[ULP_TUN_O_DMAC_HDR_FIELD_INDEX], 198 tun_entry->t_dmac, RTE_ETHER_ADDR_LEN); 199 200 params->parent_fid = tun_entry->outer_tun_flow_id; 201 202 return BNXT_TF_RC_NORMAL; 203 } 204 205 static int32_t 206 ulp_get_tun_entry(struct ulp_rte_parser_params *params, 207 struct bnxt_tun_cache_entry **tun_entry, 208 uint16_t *tun_idx) 209 { 210 int i, first_free_entry = BNXT_ULP_TUN_ENTRY_INVALID; 211 struct bnxt_tun_cache_entry *tun_tbl; 212 bool tun_entry_found = false, free_entry_found = false; 213 214 tun_tbl = bnxt_ulp_cntxt_ptr2_tun_tbl_get(params->ulp_ctx); 215 if (!tun_tbl) 216 return BNXT_TF_RC_ERROR; 217 218 for (i = 0; i < BNXT_ULP_MAX_TUN_CACHE_ENTRIES; i++) { 219 if (!memcmp(&tun_tbl[i].t_dst_ip, 220 ¶ms->hdr_field[ULP_TUN_O_IPV4_DIP_INDEX].spec, 221 sizeof(rte_be32_t)) || 222 !memcmp(&tun_tbl[i].t_dst_ip6, 223 ¶ms->hdr_field[ULP_TUN_O_IPV6_DIP_INDEX].spec, 224 16)) { 225 tun_entry_found = true; 226 break; 227 } 228 229 if (!tun_tbl[i].t_dst_ip_valid && !free_entry_found) { 230 first_free_entry = i; 231 free_entry_found = true; 232 } 233 } 234 235 if (tun_entry_found) { 236 *tun_entry = &tun_tbl[i]; 237 *tun_idx = i; 238 } else { 239 if (first_free_entry == BNXT_ULP_TUN_ENTRY_INVALID) 240 return BNXT_TF_RC_ERROR; 241 *tun_entry = &tun_tbl[first_free_entry]; 242 *tun_idx = first_free_entry; 243 } 244 245 return 0; 246 } 247 248 int32_t 249 ulp_post_process_tun_flow(struct ulp_rte_parser_params *params) 250 { 251 bool outer_tun_sig, inner_tun_sig, first_inner_tun_flow; 252 bool outer_tun_reject, inner_tun_reject, outer_tun_flow, inner_tun_flow; 253 enum bnxt_ulp_tun_flow_state flow_state; 254 struct bnxt_tun_cache_entry *tun_entry; 255 uint32_t l3_tun, l3_tun_decap; 256 uint16_t tun_idx; 257 int rc; 258 259 /* Computational fields that indicate it's a TUNNEL DECAP flow */ 260 l3_tun = ULP_COMP_FLD_IDX_RD(params, BNXT_ULP_CF_IDX_L3_TUN); 261 l3_tun_decap = ULP_COMP_FLD_IDX_RD(params, 262 BNXT_ULP_CF_IDX_L3_TUN_DECAP); 263 if (!l3_tun) 264 return BNXT_TF_RC_NORMAL; 265 266 rc = ulp_get_tun_entry(params, &tun_entry, &tun_idx); 267 if (rc == BNXT_TF_RC_ERROR) 268 return rc; 269 270 flow_state = tun_entry->tun_flow_info[params->port_id].state; 271 /* Outer tunnel flow validation */ 272 outer_tun_sig = BNXT_OUTER_TUN_SIGNATURE(l3_tun, params); 273 outer_tun_flow = BNXT_OUTER_TUN_FLOW(outer_tun_sig); 274 outer_tun_reject = BNXT_REJECT_OUTER_TUN_FLOW(flow_state, 275 outer_tun_sig); 276 277 /* Inner tunnel flow validation */ 278 inner_tun_sig = BNXT_INNER_TUN_SIGNATURE(l3_tun, l3_tun_decap, params); 279 first_inner_tun_flow = BNXT_FIRST_INNER_TUN_FLOW(flow_state, 280 inner_tun_sig); 281 inner_tun_flow = BNXT_INNER_TUN_FLOW(flow_state, inner_tun_sig); 282 inner_tun_reject = BNXT_REJECT_INNER_TUN_FLOW(flow_state, 283 inner_tun_sig); 284 285 if (outer_tun_reject) { 286 tun_entry->outer_tun_rej_cnt++; 287 BNXT_TF_DBG(ERR, 288 "Tunnel F1 flow rejected, COUNT: %d\n", 289 tun_entry->outer_tun_rej_cnt); 290 /* Inner tunnel flow is rejected if it comes between first inner 291 * tunnel flow and outer flow requests. 292 */ 293 } else if (inner_tun_reject) { 294 tun_entry->inner_tun_rej_cnt++; 295 BNXT_TF_DBG(ERR, 296 "Tunnel F2 flow rejected, COUNT: %d\n", 297 tun_entry->inner_tun_rej_cnt); 298 } 299 300 if (outer_tun_reject || inner_tun_reject) 301 return BNXT_TF_RC_ERROR; 302 else if (first_inner_tun_flow) 303 return ulp_post_process_first_inner_tun_flow(params, tun_entry); 304 else if (outer_tun_flow) 305 return ulp_post_process_outer_tun_flow(params, tun_entry, 306 tun_idx); 307 else if (inner_tun_flow) 308 return ulp_post_process_inner_tun_flow(params, tun_entry); 309 else 310 return BNXT_TF_RC_NORMAL; 311 } 312 313 void 314 ulp_clear_tun_entry(struct bnxt_tun_cache_entry *tun_tbl, uint8_t tun_idx) 315 { 316 memset(&tun_tbl[tun_idx], 0, 317 sizeof(struct bnxt_tun_cache_entry)); 318 } 319 320 /* When a dpdk application offloads the same tunnel inner flow 321 * on all the uplink ports, a tunnel inner flow entry is cached 322 * even if it is not for the right uplink port. Such tunnel 323 * inner flows will eventually get aged out as there won't be 324 * any traffic on these ports. When such a flow destroy is 325 * called, cleanup the tunnel inner flow entry. 326 */ 327 void 328 ulp_clear_tun_inner_entry(struct bnxt_tun_cache_entry *tun_tbl, uint32_t fid) 329 { 330 struct ulp_per_port_flow_info *flow_info; 331 int i, j; 332 333 for (i = 0; i < BNXT_ULP_MAX_TUN_CACHE_ENTRIES ; i++) { 334 for (j = 0; j < RTE_MAX_ETHPORTS; j++) { 335 flow_info = &tun_tbl[i].tun_flow_info[j]; 336 if (flow_info->first_tun_i_fid == fid && 337 flow_info->state == BNXT_ULP_FLOW_STATE_TUN_I_CACHED) 338 memset(flow_info, 0, sizeof(*flow_info)); 339 } 340 } 341 } 342