/** * mul_route_select_single_and_purge_list - * @route_list : A route list * @rt_select_hint : The route number to select * * Grabs a route from route list as denoted by rt_select_hint and return to caller * If rt_select_hint > number of routes in route list it will return NULL */ static GSList * mul_route_select_single_and_purge_list(rt_list_t *route_list, size_t rt_select_hint) { GSList *route = NULL; rt_list_t *tmp; size_t rt_count = 0; if (!route_list) { return route; } while (route_list) { tmp = route_list; route_list = route_list->next; if (rt_count++ == rt_select_hint) { route = tmp->route; } else { mul_destroy_route(tmp->route); } free(tmp); } return route; }
/** * mul_route_list_free - * * Free a route list */ static void mul_route_list_free(rt_list_t *path_head, bool free_route) { rt_list_t *cur_path = path_head, *prev_path = NULL; while (cur_path) { prev_path = cur_path; cur_path = cur_path->next; if (free_route) { mul_destroy_route(prev_path->route); } free(prev_path); } }
/** * @name fab_route_get * * @brief Get a fabric route */ GSList * fab_route_get(void *rt_service, int src_sw, int dst_sw, fab_route_t *froute) { GSList *route = NULL; if (!fab_ctx->use_ecmp || !froute) { if (!(route = mul_route_get(rt_service, src_sw, dst_sw))) { return NULL; } } else { if (!(route = mul_route_get_mp(rt_service, src_sw, dst_sw, froute, fab_mp_select))) { return NULL; } } if (!g_slist_find_custom(route, froute, (GCompareFunc)fab_route_elem_valid)) { mul_destroy_route(route); return NULL; } return route; }
/** * mul_route_apsp_get_mp_sp - * * Get shortest path between src_sw and dest_sw. If multiple paths exists * it will select a path based of user provided mp_select function or the * first avaialbe route if mp_select is not provided */ static GSList * mul_route_apsp_get_mp_sp(void *rt_service, int src_sw, int dest_sw, void *u_arg, size_t (*mp_select)(void *u_arg, size_t max_routes)) { unsigned int lock, max_retries = 0; rt_apsp_t *rt_apsp_info = rt_service; GSList *route = NULL; rt_list_t *route_list = NULL; size_t mp_rt_hint = 0, num_mp_routes = 0; lweight_pair_t last_hop = { NEIGH_NO_LINK, NEIGH_NO_LINK, NEIGH_NO_PATH, false }; if (src_sw == dest_sw) { goto route_same_node; } retry: if (max_retries++ >= RT_MAX_GET_RETRIES) { c_log_err("Too much writer contention or service died"); return NULL; } lock = c_seq_rd_lock(&rt_apsp_info->state_info->lock); if (!rt_apsp_converged(rt_apsp_info)) { if (c_seq_rd_unlock(&rt_apsp_info->state_info->lock, lock)) { goto retry; } c_log_err("%s: Routes not yet converged", FN); return NULL; } if (rt_apsp_get_weight(rt_apsp_info, src_sw, dest_sw) == NEIGH_NO_PATH) { if (c_seq_rd_unlock(&rt_apsp_info->state_info->lock, lock)) { goto retry; } c_log_err("%s: Not a neigbour (%d:%d) %d", FN, src_sw, dest_sw, rt_apsp_get_weight(rt_apsp_info, src_sw, dest_sw)); return NULL; } route_list = mul_route_apsp_get_subp(rt_apsp_info, src_sw, dest_sw); if (mp_select) { num_mp_routes = mul_route_list_size(route_list); mp_rt_hint = mp_select(u_arg, num_mp_routes); if (mp_rt_hint >= num_mp_routes) { /* Silently ignore any user advice on multi-path selection */ mp_rt_hint = 0; } } route = mul_route_select_single_and_purge_list(route_list, mp_rt_hint); if (c_seq_rd_unlock(&rt_apsp_info->state_info->lock, lock)) { mul_destroy_route(route); goto retry; } route_same_node: add_route_path_elem(&route, dest_sw, &last_hop, true); mul_route_prep_out(route); return route; }
/** * tr_destroy_route - * * Destroy route. Utility wrapper over mul_destroy_route() */ void tr_destroy_route(GSList *route) { return mul_destroy_route(route); }