flexflow_vpn.c (12605B)
1 /* 2 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 3 * 4 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 5 */ 6 7 8 #include <sal/core/libc.h> 9 #if defined(INCLUDE_L3) 10 11 #include <bcm/flow.h> 12 #include <bcm_int/esw/flow.h> 13 #include <bcm/error.h> 14 #include <soc/drv.h> 15 #include <bcm_int/esw/vpn.h> 16 #include <bcm_int/esw/virtual.h> 17 #include <bcm_int/esw/trx.h> 18 #include <bcm_int/common/multicast.h> 19 #include <bcm_int/esw/trident3.h> 20 21 /* Function: 22 * bcmi_esw_flow_vpn_is_valid 23 * Purpose: 24 * Find if given FLOW VPN is Valid 25 * Parameters: 26 * unit - Device Number 27 * vpn - FLOW VPN 28 * Returns: 29 * BCM_E_XXXX 30 */ 31 int 32 bcmi_esw_flow_vpn_is_valid( int unit, bcm_vpn_t vpn) 33 { 34 bcm_vpn_t flow_vpn_min=0; 35 int vfi_index=-1, num_vfi=0; 36 37 num_vfi = soc_mem_index_count(unit, VFIm); 38 39 /* Check for Valid vpn */ 40 _BCM_FLOW_VPN_SET(flow_vpn_min, _BCM_VPN_TYPE_VFI, 0); 41 if ( vpn < flow_vpn_min || vpn > (flow_vpn_min+num_vfi-1) ) { 42 return BCM_E_PARAM; 43 } 44 45 _BCM_FLOW_VPN_GET(vfi_index, _BCM_VPN_TYPE_VFI, vpn); 46 47 if (!_bcm_vfi_used_get(unit, vfi_index, _bcmVfiTypeFlow)) { 48 return BCM_E_NOT_FOUND; 49 } 50 return BCM_E_NONE; 51 } 52 53 /* Function: 54 * bcmi_esw_flow_vpn_is_eline 55 * Purpose: 56 * Find if given FLOW VPN is ELINE 57 * Parameters: 58 * unit - Device Number 59 * vpn - FLOW VPN 60 * isEline - Flag 61 * Returns: 62 * BCM_E_XXXX 63 * Assumes: 64 * vpn is valid 65 */ 66 67 int 68 bcmi_esw_flow_vpn_is_eline( int unit, bcm_vpn_t vpn, uint8 *isEline) 69 { 70 int vfi_index=-1; 71 vfi_entry_t vfi_entry; 72 73 BCM_IF_ERROR_RETURN(bcmi_esw_flow_vpn_is_valid(unit, vpn)); 74 75 _BCM_FLOW_VPN_GET(vfi_index, _BCM_VPN_TYPE_VFI, vpn); 76 BCM_IF_ERROR_RETURN(READ_VFIm(unit, MEM_BLOCK_ALL, vfi_index, &vfi_entry)); 77 78 /* Set the returned VPN id */ 79 if (soc_VFIm_field32_get(unit, &vfi_entry, PT2PT_ENf)) { 80 *isEline = 1; /* ELINE */ 81 } else { 82 *isEline = 0; /* ELAN */ 83 } 84 return BCM_E_NONE; 85 } 86 87 /* 88 * Function: 89 * bcmi_esw_flow_vpn_create 90 * Purpose: 91 * Create an L2 Flow VPN. This is a service plane and is 92 * independent of the connectivity protocol. 93 * Parameters: 94 * unit - (IN) Unit ID. 95 * info - (IN/OUT) VPN structure 96 */ 97 int bcmi_esw_flow_vpn_create(int unit, bcm_vpn_t *vpn, 98 bcm_flow_vpn_config_t *info) 99 { 100 int rv = BCM_E_NONE; 101 vfi_entry_t vfi_entry; 102 int vfi_index=-1; 103 int bc_group=0, umc_group=0, uuc_group=0; 104 int bc_group_type=0, umc_group_type=0, uuc_group_type=0; 105 uint8 vpn_alloc_flag=0; 106 int proto_pkt_idx = 0; 107 uint32 profile_idx = 0; 108 109 if (!vpn) { 110 return BCM_E_PARAM; 111 } 112 113 /*Allocate VFI*/ 114 if (info->flags & BCM_FLOW_VPN_REPLACE) { 115 BCM_IF_ERROR_RETURN(bcmi_esw_flow_vpn_is_valid(unit, *vpn)); 116 _BCM_FLOW_VPN_GET(vfi_index, _BCM_VPN_TYPE_VFI, *vpn); 117 } else if (info->flags & BCM_FLOW_VPN_WITH_ID) { 118 rv = bcmi_esw_flow_vpn_is_valid(unit, *vpn); 119 if (BCM_E_NONE == rv) { 120 return BCM_E_EXISTS; 121 } else if (BCM_E_NOT_FOUND != rv) { 122 return rv; 123 } 124 _BCM_FLOW_VPN_GET(vfi_index, _BCM_VPN_TYPE_VFI, *vpn); 125 BCM_IF_ERROR_RETURN(_bcm_vfi_alloc_with_id(unit, VFIm, _bcmVfiTypeFlow, vfi_index)); 126 vpn_alloc_flag = 1; 127 } else { 128 BCM_IF_ERROR_RETURN(_bcm_vfi_alloc(unit, VFIm, _bcmVfiTypeFlow, &vfi_index)); 129 _BCM_FLOW_VPN_SET(*vpn, _BCM_VPN_TYPE_VFI, vfi_index); 130 vpn_alloc_flag = 1; 131 } 132 133 /*Initial and configure VFI*/ 134 BCM_IF_ERROR_RETURN(READ_VFIm(unit, MEM_BLOCK_ALL, vfi_index, &vfi_entry)); 135 if (info->flags & BCM_FLOW_VPN_ELINE) { 136 soc_VFIm_field32_set(unit, &vfi_entry, PT2PT_ENf, 0x1); 137 } else if (info->flags & BCM_FLOW_VPN_ELAN) { 138 /* Check that the groups are valid. */ 139 bc_group_type = _BCM_MULTICAST_TYPE_GET(info->broadcast_group); 140 bc_group = _BCM_MULTICAST_ID_GET(info->broadcast_group); 141 umc_group_type = _BCM_MULTICAST_TYPE_GET(info->unknown_multicast_group); 142 umc_group = _BCM_MULTICAST_ID_GET(info->unknown_multicast_group); 143 uuc_group_type = _BCM_MULTICAST_TYPE_GET(info->unknown_unicast_group); 144 uuc_group = _BCM_MULTICAST_ID_GET(info->unknown_unicast_group); 145 146 if ((bc_group_type != _BCM_MULTICAST_TYPE_FLOW) || 147 (umc_group_type != _BCM_MULTICAST_TYPE_FLOW) || 148 (uuc_group_type != _BCM_MULTICAST_TYPE_FLOW) || 149 (bc_group >= soc_mem_index_count(unit, L3_IPMCm)) || 150 (umc_group >= soc_mem_index_count(unit, L3_IPMCm)) || 151 (uuc_group >= soc_mem_index_count(unit, L3_IPMCm))) { 152 rv = BCM_E_PARAM; 153 _BCM_FLOW_CLEANUP(rv) 154 } 155 156 /* Commit the entry to HW */ 157 soc_mem_field32_dest_set(unit, VFIm, &vfi_entry, 158 UMC_DESTINATIONf, SOC_MEM_FIF_DEST_IPMC, umc_group); 159 soc_mem_field32_dest_set(unit, VFIm, &vfi_entry, 160 UUC_DESTINATIONf, SOC_MEM_FIF_DEST_IPMC, uuc_group); 161 soc_mem_field32_dest_set(unit, VFIm, &vfi_entry, 162 BC_DESTINATIONf, SOC_MEM_FIF_DEST_IPMC, bc_group); 163 } 164 rv = _bcm_td3_def_vfi_profile_add(unit, 165 info->flags & BCM_FLOW_VPN_ELINE, &profile_idx); 166 if (BCM_E_NONE == rv) { 167 soc_VFIm_field32_set(unit, &vfi_entry, VFI_PROFILE_PTRf, profile_idx); 168 } 169 _BCM_FLOW_CLEANUP(rv) 170 171 /* Configure protocol packet control */ 172 rv = _bcm_xgs3_protocol_packet_actions_validate(unit, &info->protocol_pkt); 173 _BCM_FLOW_CLEANUP(rv) 174 proto_pkt_idx = soc_VFIm_field32_get(unit, &vfi_entry, PROTOCOL_PKT_INDEXf); 175 rv = _bcm_xgs3_protocol_pkt_ctrl_set(unit, proto_pkt_idx, &info->protocol_pkt, &proto_pkt_idx); 176 _BCM_FLOW_CLEANUP(rv) 177 soc_VFIm_field32_set(unit, &vfi_entry, PROTOCOL_PKT_INDEXf, proto_pkt_idx); 178 179 /*Write VFI to ASIC*/ 180 rv = WRITE_VFIm(unit, MEM_BLOCK_ALL, vfi_index, &vfi_entry); 181 _BCM_FLOW_CLEANUP(rv) 182 183 return BCM_E_NONE; 184 185 cleanup: 186 if (vpn_alloc_flag) { 187 (void) _bcm_vfi_free(unit, _bcmVfiTypeFlow, vfi_index); 188 } 189 190 return rv; 191 } 192 193 /* 194 * Function: 195 * bcmi_esw_flow_vpn_destroy 196 * Purpose: 197 * Delete L2/L3 VPN 198 * Parameters: 199 * unit - (IN) Unit ID. 200 * vpn - (IN) VPN Id 201 */ 202 int bcmi_esw_flow_vpn_destroy(int unit, bcm_vpn_t vpn) 203 { 204 int vfi = 0; 205 vfi_entry_t vfi_entry; 206 uint8 isEline = 0; 207 #if 0 208 uint32 stat_counter_id; 209 int num_ctr = 0; 210 #endif 211 int ref_count; 212 int index; 213 214 /* Get vfi index */ 215 BCM_IF_ERROR_RETURN(bcmi_esw_flow_vpn_is_eline(unit, vpn, &isEline)); 216 if (isEline == 0x1 ) { 217 _BCM_FLOW_VPN_GET(vfi, _BCM_FLOW_VPN_TYPE_ELINE, vpn); 218 } else if (isEline == 0x0 ) { 219 _BCM_FLOW_VPN_GET(vfi, _BCM_FLOW_VPN_TYPE_ELAN, vpn); 220 } 221 222 /* Delete all FLOW ports on this VPN */ 223 BCM_IF_ERROR_RETURN(bcmi_esw_flow_port_delete_all(unit, vpn)); 224 225 #if 0 226 /* TBD: Need to check on this piece of code */ 227 /* Check counters before delete vpn */ 228 if (bcm_esw_vxlan_stat_id_get(unit, BCM_GPORT_INVALID, vpn, 229 bcmVxlanOutPackets, &stat_counter_id) == BCM_E_NONE) { 230 num_ctr++; 231 } 232 if (bcm_esw_vxlan_stat_id_get(unit, BCM_GPORT_INVALID, vpn, 233 bcmVxlanInPackets, &stat_counter_id) == BCM_E_NONE) { 234 num_ctr++; 235 } 236 237 if (num_ctr != 0) { 238 BCM_IF_ERROR_RETURN( 239 bcm_esw_vxlan_stat_detach(unit, BCM_GPORT_INVALID, vpn)); 240 } 241 #endif 242 243 /* Delete protocol packet control */ 244 sal_memset(&vfi_entry, 0, sizeof(vfi_entry_t)); 245 BCM_IF_ERROR_RETURN(READ_VFIm(unit, MEM_BLOCK_ALL, vfi, &vfi_entry)); 246 index = soc_VFIm_field32_get(unit, &vfi_entry, PROTOCOL_PKT_INDEXf); 247 BCM_IF_ERROR_RETURN( 248 _bcm_prot_pkt_ctrl_ref_count_get(unit, index, &ref_count)); 249 if (ref_count > 0) { 250 BCM_IF_ERROR_RETURN(_bcm_prot_pkt_ctrl_delete(unit, index)); 251 } 252 253 /* Reset VFI table */ 254 (void)_bcm_vfi_free(unit, _bcmVfiTypeFlow, vfi); 255 256 return BCM_E_NONE; 257 } 258 259 /* 260 * Function: 261 * bcmi_esw_flow_vpn_destroy_all 262 * Purpose: 263 * Delete all VPN's 264 * Parameters: 265 * unit - (IN) Unit ID. 266 */ 267 int bcmi_esw_flow_vpn_destroy_all(int unit) 268 { 269 int num_vfi = 0, idx = 0; 270 bcm_vpn_t vpn = 0; 271 272 /* Destroy all FLOW VPNs */ 273 num_vfi = soc_mem_index_count(unit, VFIm); 274 for (idx = 0; idx < num_vfi; idx++) { 275 if (_bcm_vfi_used_get(unit, idx, _bcmVfiTypeFlow)) { 276 _BCM_FLOW_VPN_SET(vpn, _BCM_VPN_TYPE_VFI, idx); 277 BCM_IF_ERROR_RETURN(bcmi_esw_flow_vpn_destroy(unit, vpn)); 278 } 279 } 280 return BCM_E_NONE; 281 282 } 283 284 /* 285 * Function: 286 * bcmi_esw_flow_vpn_get 287 * Purpose: 288 * Get VPN properties 289 * Parameters: 290 * unit - (IN) Unit ID. 291 * vpn - (IN) VPN Id 292 * info - (IN/OUT) VPN structure 293 */ 294 int bcmi_esw_flow_vpn_get(int unit, bcm_vpn_t vpn, 295 bcm_flow_vpn_config_t *info) 296 { 297 int rv = BCM_E_NONE; 298 int vfi_index = -1; 299 vfi_entry_t vfi_entry; 300 uint8 isEline=0; 301 int proto_pkt_inx; 302 uint32 dt, dv; 303 304 /*Get vfi table*/ 305 BCM_IF_ERROR_RETURN(bcmi_esw_flow_vpn_is_eline(unit, vpn, &isEline)); 306 if (isEline == 0x1 ) { 307 _BCM_FLOW_VPN_GET(vfi_index, _BCM_FLOW_VPN_TYPE_ELINE, vpn); 308 } else if (isEline == 0x0 ) { 309 _BCM_FLOW_VPN_GET(vfi_index, _BCM_FLOW_VPN_TYPE_ELAN, vpn); 310 } 311 BCM_IF_ERROR_RETURN(READ_VFIm(unit, MEM_BLOCK_ALL, vfi_index, &vfi_entry)); 312 313 /* Get info associated with vfi table */ 314 if (isEline) { 315 info->flags = BCM_FLOW_VPN_ELINE; 316 } else { 317 info->flags = BCM_FLOW_VPN_ELAN; 318 319 320 dv = soc_mem_field32_dest_get(unit, VFIm, 321 &vfi_entry, BC_DESTINATIONf, &dt); 322 if (dt == SOC_MEM_FIF_DEST_IPMC) { 323 _BCM_MULTICAST_GROUP_SET(info->broadcast_group, 324 _BCM_MULTICAST_TYPE_FLOW, dv); 325 } else { 326 return BCM_E_INTERNAL; 327 } 328 329 dv = soc_mem_field32_dest_get(unit, VFIm, 330 &vfi_entry, UUC_DESTINATIONf, &dt); 331 if (dt == SOC_MEM_FIF_DEST_IPMC) { 332 _BCM_MULTICAST_GROUP_SET(info->unknown_unicast_group, 333 _BCM_MULTICAST_TYPE_FLOW, dv); 334 } else { 335 return BCM_E_INTERNAL; 336 } 337 338 dv = soc_mem_field32_dest_get(unit, VFIm, 339 &vfi_entry, UMC_DESTINATIONf, &dt); 340 if (dt == SOC_MEM_FIF_DEST_IPMC) { 341 _BCM_MULTICAST_GROUP_SET(info->unknown_multicast_group, 342 _BCM_MULTICAST_TYPE_FLOW, dv); 343 } else { 344 return BCM_E_INTERNAL; 345 } 346 } 347 /*Get protocol packet control*/ 348 proto_pkt_inx = soc_VFIm_field32_get(unit, &vfi_entry, PROTOCOL_PKT_INDEXf); 349 BCM_IF_ERROR_RETURN(_bcm_xgs3_protocol_pkt_ctrl_get(unit,proto_pkt_inx, &info->protocol_pkt)); 350 351 return rv; 352 } 353 354 /* 355 * Function: 356 * bcmi_esw_flow_vpn_traverse 357 * Purpose: 358 * Traverse VPN's 359 * Parameters: 360 * unit - (IN) Unit ID. 361 * cb - (IN) callback function 362 * user_data - (IN) User context data 363 */ 364 int bcmi_esw_flow_vpn_traverse(int unit, 365 bcm_flow_vpn_traverse_cb cb, 366 void *user_data) 367 { 368 int idx, num_vfi; 369 int vpn; 370 bcm_flow_vpn_config_t info; 371 372 if (cb == NULL) { 373 return BCM_E_PARAM; 374 } 375 376 /* FLOW VPNs */ 377 num_vfi = soc_mem_index_count(unit, VFIm); 378 for (idx = 0; idx < num_vfi; idx++) { 379 if (_bcm_vfi_used_get(unit, idx, _bcmVfiTypeFlow)) { 380 _BCM_FLOW_VPN_SET(vpn, _BCM_VPN_TYPE_VFI, idx); 381 bcm_flow_vpn_config_t_init(&info); 382 BCM_IF_ERROR_RETURN(bcmi_esw_flow_vpn_get(unit, vpn, &info)); 383 BCM_IF_ERROR_RETURN(cb(unit, vpn, &info, user_data)); 384 } 385 } 386 return BCM_E_NONE; 387 } 388 389 /* Function: 390 * bcmi_flow_vpnid_get 391 * Purpose: 392 * Get L2-VPN instance for FLOW VPN 393 * Parameters: 394 * unit - Device Number 395 * vfi_index - vfi_index 396 * vid (OUT) VLAN Id (l2vpn id) 397 398 * Returns: 399 * BCM_E_XXXX 400 */ 401 int 402 bcmi_esw_flow_vpnid_get(int unit, int vfi_index, bcm_vlan_t *vid) 403 { 404 vfi_entry_t vfi_entry; 405 406 BCM_IF_ERROR_RETURN 407 (READ_VFIm(unit, MEM_BLOCK_ALL, vfi_index, &vfi_entry)); 408 409 if (soc_VFIm_field32_get(unit, &vfi_entry, PT2PT_ENf)) { 410 _BCM_FLOW_VPN_SET(*vid, _BCM_FLOW_VPN_TYPE_ELINE, vfi_index); 411 } else { 412 _BCM_FLOW_VPN_SET(*vid, _BCM_FLOW_VPN_TYPE_ELAN, vfi_index); 413 } 414 return BCM_E_NONE; 415 } 416 #endif