switch_status_t switch_api_nhop_delete(switch_device_t device, switch_handle_t nhop_handle) { switch_nhop_info_t *nhop_info = NULL; switch_interface_info_t *intf_info = NULL; switch_spath_info_t *spath_info = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; if (!SWITCH_NHOP_HANDLE_VALID(nhop_handle)) { return SWITCH_STATUS_INVALID_HANDLE; } nhop_info = switch_nhop_get(nhop_handle); if (!nhop_info) { return SWITCH_STATUS_INVALID_HANDLE; } if (nhop_info->type != SWITCH_NHOP_INDEX_TYPE_ONE_PATH) { return SWITCH_STATUS_INVALID_HANDLE; } if (nhop_info->ref_count) { return SWITCH_STATUS_RESOURCE_IN_USE; } spath_info = &(SWITCH_NHOP_SPATH_INFO(nhop_info)); intf_info = switch_api_interface_get(spath_info->nhop_key.intf_handle); if (!intf_info) { return SWITCH_STATUS_INVALID_INTERFACE; } nhop_info->valid = 0; if(nhop_info->u.spath.neighbor_handle == 0) { #ifdef SWITCH_PD status = switch_pd_nexthop_table_delete_entry(device, spath_info->hw_entry); if (status != SWITCH_STATUS_SUCCESS) { return status; } if (SWITCH_INTF_IS_PORT_L3(intf_info) && intf_info->bd_handle) { status = switch_pd_urpf_bd_table_delete_entry(device, spath_info->urpf_hw_entry); if (status != SWITCH_STATUS_SUCCESS) { return status; } } #endif switch_nhop_delete_hash(spath_info); switch_nhop_delete(nhop_handle); } return SWITCH_STATUS_SUCCESS; }
switch_nhop_index_type_t switch_api_nhop_type_get(switch_handle_t nhop_handle) { switch_nhop_info_t *nhop_info = NULL; if (!SWITCH_NHOP_HANDLE_VALID(nhop_handle)) { return SWITCH_NHOP_INDEX_TYPE_NONE; } nhop_info = switch_nhop_get(nhop_handle); if (!nhop_info) { return SWITCH_NHOP_INDEX_TYPE_NONE; } return nhop_info->type; }
switch_handle_t switch_api_neighbor_handle_get(switch_handle_t nhop_handle) { switch_nhop_info_t *nhop_info = NULL; switch_spath_info_t *spath_info = NULL; if (!SWITCH_NHOP_HANDLE_VALID(nhop_handle)) { return SWITCH_API_INVALID_HANDLE; } nhop_info = switch_nhop_get(nhop_handle); if (!nhop_info) { return SWITCH_API_INVALID_HANDLE; } spath_info = &(SWITCH_NHOP_SPATH_INFO(nhop_info)); return spath_info->neighbor_handle; }
switch_status_t switch_api_nhop_update(switch_device_t device, switch_handle_t nhop_handle) { switch_nhop_info_t *nhop_info = NULL; switch_interface_info_t *intf_info = NULL; switch_spath_info_t *spath_info = NULL; switch_ifindex_t ifindex = 0; bool flood = FALSE; uint32_t mc_index = 0; switch_status_t status = SWITCH_STATUS_SUCCESS; if (!SWITCH_NHOP_HANDLE_VALID(nhop_handle)) { return SWITCH_STATUS_INVALID_HANDLE; } nhop_info = switch_nhop_get(nhop_handle); if (!nhop_info) { return SWITCH_STATUS_INVALID_HANDLE; } status = switch_nhop_ifindex_get(nhop_handle, &ifindex, &flood, &mc_index); if (status != SWITCH_STATUS_SUCCESS) { return SWITCH_STATUS_INVALID_HANDLE; } spath_info = &(SWITCH_NHOP_SPATH_INFO(nhop_info)); intf_info = switch_api_interface_get(spath_info->nhop_key.intf_handle); if (!intf_info) { return SWITCH_STATUS_INVALID_INTERFACE; } #ifdef SWITCH_PD bool tunnel = (SWITCH_INTF_TYPE(intf_info) == SWITCH_API_INTERFACE_TUNNEL); status = switch_pd_nexthop_table_update_entry(device, handle_to_id(nhop_handle), handle_to_id(intf_info->bd_handle), ifindex, flood, mc_index, tunnel, &spath_info->hw_entry); if (status != SWITCH_STATUS_SUCCESS) { return SWITCH_API_INVALID_HANDLE; } #endif return SWITCH_STATUS_SUCCESS; }
switch_status_t switch_api_ecmp_delete(switch_device_t device, switch_handle_t handle) { switch_nhop_info_t *nhop_info = NULL; switch_ecmp_info_t *ecmp_info = NULL; tommy_node *node = NULL; switch_ecmp_member_t *ecmp_member = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; if (!SWITCH_NHOP_HANDLE_VALID(handle)) { return SWITCH_STATUS_INVALID_HANDLE; } nhop_info = switch_nhop_get(handle); if (!nhop_info) { return SWITCH_STATUS_INVALID_NHOP; } if (nhop_info->type != SWITCH_NHOP_INDEX_TYPE_ONE_PATH) { ecmp_info = &(SWITCH_NHOP_ECMP_INFO(nhop_info)); if (ecmp_info->count > 0) { node = tommy_list_head(&(ecmp_info->members)); while (node) { ecmp_member = (switch_ecmp_member_t *) node->data; nhop_info = switch_nhop_get(ecmp_member->nhop_handle); if (!nhop_info) { return SWITCH_STATUS_INVALID_NHOP; } nhop_info->ref_count--; node = node->next; } } #ifdef SWITCH_PD status = switch_pd_ecmp_group_delete(device, ecmp_info->pd_group_hdl); if (status != SWITCH_STATUS_SUCCESS) { return status; } #endif } return switch_nhop_delete(handle); }
switch_status_t switch_api_l3_route_add(switch_device_t device, switch_handle_t vrf, switch_ip_addr_t *ip_addr, switch_handle_t nhop_handle) { switch_l3_hash_t *hash_entry = NULL; switch_nhop_info_t *nhop_info = NULL; uint32_t nhop_index = 0; switch_status_t status = SWITCH_STATUS_SUCCESS; unsigned int v4_mask = 0; uint8_t v6_mask[16]; switch_ip_addr_t masked_ip; if (!SWITCH_VRF_HANDLE_VALID(vrf)) { return SWITCH_STATUS_INVALID_HANDLE; } if (!SWITCH_NHOP_HANDLE_VALID(nhop_handle)) { return SWITCH_STATUS_INVALID_HANDLE; } nhop_index = handle_to_id(nhop_handle); nhop_info = switch_nhop_get(nhop_handle); if (!nhop_info) { SWITCH_API_ERROR("%s:%d: Invalid nexthop!", __FUNCTION__, __LINE__); return SWITCH_STATUS_ITEM_NOT_FOUND; } hash_entry = switch_l3_search_hash(vrf, ip_addr); if (hash_entry) { hash_entry->nhop_handle = nhop_handle; #ifdef SWITCH_PD status = switch_pd_ip_fib_update_entry(device, handle_to_id(vrf), ip_addr, SWITCH_NHOP_TYPE_IS_ECMP(nhop_info), nhop_index, hash_entry->hw_entry); if (status != SWITCH_STATUS_SUCCESS) { return status; } status = switch_pd_urpf_update_entry(device, handle_to_id(vrf), ip_addr, handle_to_id(nhop_handle), hash_entry->urpf_entry); #endif } else { memcpy(&masked_ip, ip_addr, sizeof(switch_ip_addr_t)); if (ip_addr->type == SWITCH_API_IP_ADDR_V4) { v4_mask = prefix_to_v4_mask(ip_addr->prefix_len); masked_ip.ip.v4addr = ip_addr->ip.v4addr & v4_mask; } else { int i = 0; prefix_to_v6_mask(ip_addr->prefix_len, v6_mask); for (i = 0; i < 16; i++) { masked_ip.ip.v6addr[i] = ip_addr->ip.v6addr[i] & v6_mask[i]; } } hash_entry = switch_l3_insert_hash(vrf, ip_addr, nhop_handle); if (!hash_entry) { return SWITCH_STATUS_NO_MEMORY; } hash_entry->nhop_handle = nhop_handle; #ifdef SWITCH_PD // set the HW entry status = switch_pd_ip_fib_add_entry(device, handle_to_id(vrf), ip_addr, SWITCH_NHOP_TYPE_IS_ECMP(nhop_info), nhop_index, &hash_entry->hw_entry); if (status != SWITCH_STATUS_SUCCESS) { return status; } status = switch_pd_urpf_add_entry(device, handle_to_id(vrf), ip_addr, handle_to_id(nhop_handle), &hash_entry->urpf_entry); #endif } return status; }
switch_status_t switch_api_ecmp_member_delete(switch_device_t device, switch_handle_t ecmp_handle, uint16_t nhop_count, switch_handle_t *nhop_handle_list) { switch_nhop_info_t *nhop_info = NULL; switch_nhop_info_t *e_nhop_info = NULL; switch_spath_info_t *spath_info = NULL; switch_interface_info_t *intf_info = NULL; switch_ecmp_info_t *ecmp_info = NULL; switch_ecmp_member_t *ecmp_member = NULL; tommy_node *node = NULL; switch_handle_t nhop_handle; switch_status_t status = SWITCH_STATUS_SUCCESS; int count = 0; if (!SWITCH_NHOP_HANDLE_VALID(ecmp_handle)) { return SWITCH_STATUS_INVALID_HANDLE; } e_nhop_info = switch_nhop_get(ecmp_handle); if (!e_nhop_info) { return SWITCH_STATUS_INVALID_NHOP; } for (count = 0; count < nhop_count; count++) { nhop_handle = nhop_handle_list[count]; if (!SWITCH_NHOP_HANDLE_VALID(nhop_handle)) { return SWITCH_STATUS_INVALID_HANDLE; } nhop_info = switch_nhop_get(nhop_handle); if (!nhop_info) { return SWITCH_STATUS_INVALID_NHOP; } spath_info = &(SWITCH_NHOP_SPATH_INFO(nhop_info)); ecmp_info = &(SWITCH_NHOP_ECMP_INFO(e_nhop_info)); node = tommy_list_head(&(ecmp_info->members)); while (node) { ecmp_member = (switch_ecmp_member_t *) node->data; if (ecmp_member->nhop_handle == nhop_handle) { break; } node = node->next; } if (!node) { return SWITCH_STATUS_ITEM_NOT_FOUND; } intf_info = switch_api_interface_get(spath_info->nhop_key.intf_handle); if (!intf_info) { return SWITCH_STATUS_INVALID_INTERFACE; } nhop_info->ref_count--; #if SWITCH_PD if (ecmp_info->count == 1) { status = switch_pd_ecmp_group_table_delete_entry(device, ecmp_info->hw_entry); if (status != SWITCH_STATUS_SUCCESS) { return status; } } status = switch_pd_ecmp_member_delete(device, ecmp_info->pd_group_hdl, ecmp_member->mbr_hdl); if (status != SWITCH_STATUS_SUCCESS) { return status; } if (SWITCH_INTF_IS_PORT_L3(intf_info) && intf_info->bd_handle) { status = switch_pd_urpf_bd_table_delete_entry(device, ecmp_member->urpf_hw_entry); if (status != SWITCH_STATUS_SUCCESS) { return status; } } #endif ecmp_info->count--; ecmp_member = tommy_list_remove_existing(&(ecmp_info->members), node); switch_free(ecmp_member); } return status; }
switch_status_t switch_api_ecmp_member_add(switch_device_t device, switch_handle_t ecmp_handle, uint16_t nhop_count, switch_handle_t *nhop_handle_list) { switch_nhop_info_t *e_nhop_info = NULL; switch_nhop_info_t *nhop_info = NULL; switch_ecmp_info_t *ecmp_info = NULL; switch_ecmp_member_t *ecmp_member = NULL; switch_interface_info_t *intf_info = NULL; switch_spath_info_t *spath_info = NULL; switch_handle_t nhop_handle; switch_status_t status = SWITCH_STATUS_SUCCESS; int count = 0; if (!SWITCH_NHOP_HANDLE_VALID(ecmp_handle)) { return SWITCH_STATUS_INVALID_HANDLE; } e_nhop_info = switch_nhop_get(ecmp_handle); if (!e_nhop_info) { return SWITCH_STATUS_INVALID_NHOP; } ecmp_info = &(SWITCH_NHOP_ECMP_INFO(e_nhop_info)); for (count = 0; count < nhop_count; count++) { nhop_handle = nhop_handle_list[count]; if (!SWITCH_NHOP_HANDLE_VALID(nhop_handle)) { return SWITCH_STATUS_INVALID_HANDLE; } nhop_info = switch_nhop_get(nhop_handle); if (!nhop_info) { return SWITCH_STATUS_INVALID_NHOP; } spath_info = &(SWITCH_NHOP_SPATH_INFO(nhop_info)); ecmp_member = switch_malloc(sizeof(switch_ecmp_member_t), 1); if (!ecmp_member) { return SWITCH_STATUS_NO_MEMORY; } ecmp_member->nhop_handle = nhop_handle; intf_info = switch_api_interface_get(spath_info->nhop_key.intf_handle); if (!intf_info) { return SWITCH_STATUS_INVALID_INTERFACE; } nhop_info->ref_count++; #ifdef SWITCH_PD status = switch_pd_ecmp_member_add(device, ecmp_info->pd_group_hdl, handle_to_id(ecmp_member->nhop_handle), intf_info, &(ecmp_member->mbr_hdl)); if (status != SWITCH_STATUS_SUCCESS) { return status; } if (ecmp_info->count == 0) { status = switch_pd_ecmp_group_table_add_entry_with_selector(device, handle_to_id(ecmp_handle), ecmp_info->pd_group_hdl, &(ecmp_info->hw_entry)); if (status != SWITCH_STATUS_SUCCESS) { return status; } } if (SWITCH_INTF_IS_PORT_L3(intf_info) && intf_info->bd_handle) { status = switch_pd_urpf_bd_table_add_entry(device, handle_to_id(ecmp_handle), handle_to_id(intf_info->bd_handle), &(ecmp_member->urpf_hw_entry)); if (status != SWITCH_STATUS_SUCCESS) { return status; } } #endif ecmp_info->count++; tommy_list_insert_head(&ecmp_info->members, &(ecmp_member->node), ecmp_member); } return status; }
switch_handle_t switch_api_ecmp_create_with_members(switch_device_t device, uint32_t member_count, switch_handle_t *nhop_handle) { switch_nhop_info_t *nhop_info = NULL; switch_spath_info_t *spath_info = NULL; switch_interface_info_t *intf_info = NULL; switch_ecmp_info_t *ecmp_info = NULL; switch_ecmp_member_t *ecmp_member = NULL; switch_handle_t ecmp_handle; switch_status_t status = SWITCH_STATUS_SUCCESS; uint32_t index = 0; ecmp_handle = switch_api_ecmp_create(device); nhop_info = switch_nhop_get(ecmp_handle); if (!nhop_info) { return SWITCH_API_INVALID_HANDLE; } ecmp_info = &(SWITCH_NHOP_ECMP_INFO(nhop_info)); tommy_list_init(&ecmp_info->members); #ifdef SWITCH_PD status = switch_pd_ecmp_group_create(device, &(ecmp_info->pd_group_hdl)); if (status != SWITCH_STATUS_SUCCESS) { return SWITCH_API_INVALID_HANDLE; } #endif for (index = 0; index < member_count; index++) { if (!SWITCH_NHOP_HANDLE_VALID(nhop_handle[index])) { return SWITCH_STATUS_INVALID_HANDLE; } ecmp_member = switch_malloc(sizeof(switch_ecmp_member_t), 1); if (!ecmp_member) { // TODO: Cleanup memory return SWITCH_API_INVALID_HANDLE; } ecmp_member->nhop_handle = nhop_handle[index]; ecmp_member->mbr_hdl = 0; nhop_info = switch_nhop_get(ecmp_member->nhop_handle); if (!nhop_info) { return SWITCH_API_INVALID_HANDLE; } spath_info = &(SWITCH_NHOP_SPATH_INFO(nhop_info)); intf_info = switch_api_interface_get(spath_info->nhop_key.intf_handle); if (!intf_info) { return SWITCH_API_INVALID_HANDLE; } nhop_info->ref_count++; #ifdef SWITCH_PD status = switch_pd_ecmp_member_add(device, ecmp_info->pd_group_hdl, handle_to_id(ecmp_member->nhop_handle), intf_info, &(ecmp_member->mbr_hdl)); if (status != SWITCH_STATUS_SUCCESS) { return SWITCH_API_INVALID_HANDLE; } if (SWITCH_INTF_IS_PORT_L3(intf_info) && intf_info->bd_handle) { status = switch_pd_urpf_bd_table_add_entry(device, handle_to_id(ecmp_handle), handle_to_id(intf_info->bd_handle), &(ecmp_member->urpf_hw_entry)); if (status != SWITCH_STATUS_SUCCESS) { return SWITCH_API_INVALID_HANDLE; } } #endif tommy_list_insert_head(&ecmp_info->members, &(ecmp_member->node), ecmp_member); } #ifdef SWITCH_PD status = switch_pd_ecmp_group_table_add_entry_with_selector(device, handle_to_id(ecmp_handle), ecmp_info->pd_group_hdl, &(ecmp_info->hw_entry)); if (status != SWITCH_STATUS_SUCCESS) { return SWITCH_API_INVALID_HANDLE; } #endif ecmp_info->count = member_count; if (status != SWITCH_STATUS_SUCCESS) { return SWITCH_API_INVALID_HANDLE; } return ecmp_handle; }