int ipv4_restore_routes(struct tunnel *tunnel) { int ret; struct rtentry *def_rt = &tunnel->ipv4.def_rt; struct rtentry *gtw_rt = &tunnel->ipv4.gtw_rt; struct rtentry *ppp_rt = &tunnel->ipv4.ppp_rt; if (tunnel->ipv4.split_routes) return 0; ret = ipv4_del_route(ppp_rt); if (ret != 0) log_warn("Could not delete route through tunnel (%s).\n", err_ipv4_str(ret)); // Restore the default route // It seems to not be automatically restored on all linux distributions ret = ipv4_set_route(def_rt); if (ret != 0) log_warn("Could not restore default route (%s). Already restored?\n", err_ipv4_str(ret)); ret = ipv4_del_route(gtw_rt); if (ret != 0) log_warn("Could not delete route to gateway (%s).\n", err_ipv4_str(ret)); route_destroy(ppp_rt); route_destroy(def_rt); return 0; }
void _qos_test() { SRoute * pRoute1; SRoute * pRoute2; SRoute * pRoute3; SRoutes * pRoutes; SRoute * pAggrRoute; SPrefix sPrefix; int iIndex; sPrefix.tNetwork= 256; sPrefix.uMaskLen= 24; pRoute1= route_create(sPrefix, NULL, 1, ROUTE_ORIGIN_IGP); pRoute2= route_create(sPrefix, NULL, 2, ROUTE_ORIGIN_IGP); pRoute3= route_create(sPrefix, NULL, 3, ROUTE_ORIGIN_IGP); pRoute1->tDelay.tDelay= 5; pRoute1->tDelay.tMean= 5; pRoute1->tDelay.uWeight= 1; pRoute2->tDelay.tDelay= 5; pRoute2->tDelay.tMean= 7.5; pRoute2->tDelay.uWeight= 2; pRoute3->tDelay.tDelay= 10; pRoute3->tDelay.tMean= 10; pRoute3->tDelay.uWeight= 1; fprintf(stdout, "route-delay-compare: %d\n", qos_route_compare_delay(&pRoute1, &pRoute2, 0)); route_path_append(pRoute1, 1); route_path_append(pRoute2, 2); route_path_append(pRoute3, 3); pRoutes= ptr_array_create_ref(0); ptr_array_append(pRoutes, pRoute1); ptr_array_append(pRoutes, pRoute2); ptr_array_append(pRoutes, pRoute3); _array_sort((SArray *) pRoutes, qos_route_compare_delay); for (iIndex= 0; iIndex < ptr_array_length(pRoutes); iIndex++) { fprintf(stdout, "*** "); route_dump(stdout, (SRoute *) pRoutes->data[iIndex]); fprintf(stdout, "\n"); } pAggrRoute= qos_route_aggregate(pRoutes, pRoute1); route_dump(stdout, pAggrRoute); fprintf(stdout, "\n"); routes_list_destroy(&pRoutes); route_destroy(&pRoute1); route_destroy(&pRoute2); route_destroy(&pRoute3); route_destroy(&pAggrRoute); }
void qos_decision_process_disseminate_to_peer(SBGPRouter * pRouter, SPrefix sPrefix, SRoute * pRoute, SPeer * pPeer) { #ifndef __EXPERIMENTAL_WALTON__ SRoute * pNewRoute; if (pPeer->uSessionState == SESSION_STATE_ESTABLISHED) { LOG_DEBUG("\t->peer: AS%d\n", pPeer->uRemoteAS); if (pRoute == NULL) { // A route was advertised to this peer => explicit withdraw if (rib_find_exact(pPeer->pAdjRIBOut, sPrefix) != NULL) { rib_remove_route(pPeer->pAdjRIBOut, sPrefix); peer_withdraw_prefix(pPeer, sPrefix); LOG_DEBUG("\texplicit-withdraw\n"); } } else { route_copy_count++; pNewRoute= route_copy(pRoute); if (qos_advertise_to_peer(pRouter, pPeer, pNewRoute) == 0) { LOG_DEBUG("\treplaced\n"); rib_replace_route(pPeer->pAdjRIBOut, pNewRoute); } else { route_destroy_count++; route_destroy(&pNewRoute); LOG_DEBUG("\tfiltered\n"); if (rib_find_exact(pPeer->pAdjRIBOut, sPrefix) != NULL) { LOG_DEBUG("\texplicit-withdraw\n"); rib_remove_route(pPeer->pAdjRIBOut, sPrefix); peer_withdraw_prefix(pPeer, sPrefix); } } } } #endif }
static int ipv4_set_default_routes(struct tunnel *tunnel) { int ret; struct rtentry *def_rt = &tunnel->ipv4.def_rt; struct rtentry *gtw_rt = &tunnel->ipv4.gtw_rt; struct rtentry *ppp_rt = &tunnel->ipv4.ppp_rt; route_init(def_rt); route_init(ppp_rt); // Back up default route route_dest(def_rt).s_addr = inet_addr("0.0.0.0"); route_mask(def_rt).s_addr = inet_addr("0.0.0.0"); ret = ipv4_get_route(def_rt); if (ret != 0) { log_warn("Could not get current default route (%s).\n", err_ipv4_str(ret)); goto err_destroy; } // Set the default route as the route to the tunnel gateway memcpy(gtw_rt, def_rt, sizeof(*gtw_rt)); route_dest(gtw_rt).s_addr = tunnel->config->gateway_ip.s_addr; route_mask(gtw_rt).s_addr = inet_addr("255.255.255.255"); gtw_rt->rt_flags |= RTF_GATEWAY; gtw_rt->rt_metric = 0; log_debug("Setting route to tunnel gateway...\n"); ret = ipv4_set_route(gtw_rt); if (ret == ERR_IPV4_SEE_ERRNO && errno == EEXIST) log_warn("Route to gateway exists already.\n"); else if (ret != 0) log_warn("Could not set route to tunnel gateway (%s).\n", err_ipv4_str(ret)); // Delete the current default route log_debug("Deleting the current default route...\n"); ret = ipv4_del_route(def_rt); if (ret != 0) log_warn("Could not delete the current default route (%s).\n", err_ipv4_str(ret)); // Set the new default route // ip route add to 0/0 dev ppp0 route_dest(ppp_rt).s_addr = inet_addr("0.0.0.0"); route_mask(ppp_rt).s_addr = inet_addr("0.0.0.0"); route_gtw(ppp_rt).s_addr = inet_addr("0.0.0.0"); strncpy(route_iface(ppp_rt), tunnel->ppp_iface, ROUTE_IFACE_LEN - 1); log_debug("Setting new default route...\n"); ret = ipv4_set_route(ppp_rt); if (ret == ERR_IPV4_SEE_ERRNO && errno == EEXIST) log_warn("Default route exists already.\n"); else if (ret != 0) log_warn("Could not set the new default route (%s).\n", err_ipv4_str(ret)); return 0; err_destroy: route_destroy(ppp_rt); route_destroy(def_rt); return ret; }
/** * Phase I - Calculate degree of preference (LOCAL_PREF) for each * single route. Operate on separate Adj-RIB-Ins. * This phase is carried by 'peer_handle_message' (peer.c). * * Phase II - Selection of best route on the basis of the degree of * preference and then on tie-breaking rules (AS-Path * length, Origin, MED, ...). * * Phase III - Dissemination of routes. * * In our implementation, we distinguish two main cases: * - a withdraw has been received from a peer for a given prefix. In * this case, if the best route towards this prefix was received by * the given peer, the complete decision process has to be * run. Otherwise, nothing more is done (the route has been removed * from the peer's Adj-RIB-In by 'peer_handle_message'); * - an update has been received. The complete decision process has to * be run. */ int qos_decision_process(SBGPRouter * pRouter, SPeer * pOriginPeer, SPrefix sPrefix) { #ifndef __EXPERIMENTAL_WALTON__ SRoutes * pRoutes= routes_list_create(); SRoutes * pEBGPRoutes= routes_list_create(); int iIndex; SPeer * pPeer; SRoute * pRoute, * pOldRoute; AS_LOG_DEBUG(pRouter, " > qos_decision_process.begin\n"); LOG_DEBUG("\t<-peer: AS%d\n", pOriginPeer->uRemoteAS); pOldRoute= rib_find_exact(pRouter->pLocRIB, sPrefix); LOG_DEBUG("\tbest: "); LOG_ENABLED_DEBUG() route_dump(log_get_stream(pMainLog), pOldRoute); LOG_DEBUG("\n"); // *** lock all Adj-RIB-Ins *** // Build list of eligible routes and list of eligible eBGP routes for (iIndex= 0; iIndex < ptr_array_length(pRouter->pPeers); iIndex++) { pPeer= (SPeer*) pRouter->pPeers->data[iIndex]; pRoute= rib_find_exact(pPeer->pAdjRIBIn, sPrefix); if ((pRoute != NULL) && (route_flag_get(pRoute, ROUTE_FLAG_FEASIBLE))) { assert(ptr_array_append(pRoutes, pRoute) >= 0); LOG_DEBUG("\teligible: "); LOG_ENABLED_DEBUG() route_dump(log_get_stream(pMainLog), pRoute); LOG_DEBUG("\n"); if (route_peer_get(pRoute)->uRemoteAS != pRouter->uNumber) assert(ptr_array_append(pEBGPRoutes, pRoute) >= 0); } } // Keep routes with highest degree of preference if (ptr_array_length(pRoutes) > 1) as_decision_process_dop(pRouter, pRoutes); // Tie-break if (ptr_array_length(pRoutes) > 1) qos_decision_process_delay(pRouter, pRoutes, BGP_OPTIONS_QOS_AGGR_LIMIT); assert(ptr_array_length(pRoutes) <= 1); if (ptr_array_length(pRoutes) == 1) { LOG_DEBUG("\tselected: "); LOG_ENABLED_DEBUG() route_dump(log_get_stream(pMainLog), (SRoute *) pRoutes->data[0]); LOG_DEBUG("\n"); // Carry aggregated route ? if (((SRoute *) pRoutes->data[0])->pAggrRoute != NULL) { LOG_DEBUG("\taggregated: "); LOG_ENABLED_DEBUG() route_dump(log_get_stream(pMainLog), ((SRoute *) pRoutes->data[0])->pAggrRoute); LOG_DEBUG("\n"); } // If best route is iBGP or aggregate contains an iBGP route, then // find the best eBGP route (and aggregate: optional) if (qos_route_is_ibgp(pRouter, (SRoute *) pRoutes->data[0])) { // Keep eBGP routes with highest degree of preference if (ptr_array_length(pEBGPRoutes) > 1) as_decision_process_dop(pRouter, pEBGPRoutes); // Tie-break for eBGP routes if (ptr_array_length(pEBGPRoutes) > 1) qos_decision_process_delay(pRouter, pEBGPRoutes, BGP_OPTIONS_QOS_AGGR_LIMIT); assert(ptr_array_length(pRoutes) <= 1); if (ptr_array_length(pEBGPRoutes) == 1) ((SRoute *) pRoutes->data[0])->pEBGPRoute= (SRoute *) pEBGPRoutes->data[0]; } route_copy_count++; pRoute= route_copy((SRoute *) pRoutes->data[0]); route_flag_set(pRoute, ROUTE_FLAG_BEST, 1); LOG_DEBUG("\tnew best: "); LOG_ENABLED_DEBUG() route_dump(log_get_stream(pMainLog), pRoute); LOG_DEBUG("\n"); // New/updated route // => install in Loc-RIB // => advertise to peers if ((pOldRoute == NULL) || !route_equals(pOldRoute, pRoute)) { if (pOldRoute != NULL) route_flag_set(pOldRoute, ROUTE_FLAG_BEST, 0); assert(rib_add_route(pRouter->pLocRIB, pRoute) == 0); qos_decision_process_disseminate(pRouter, sPrefix, pRoute); } else { route_destroy(&pRoute); pRoute= pOldRoute; } } else if (ptr_array_length(pRoutes) == 0) { LOG_DEBUG("no best\n"); // If a route towards this prefix was previously installed, then // withdraw it. Otherwise, do nothing... if (pOldRoute != NULL) { //LOG_DEBUG("there was a previous best-route\n"); rib_remove_route(pRouter->pLocRIB, sPrefix); //LOG_DEBUG("previous best-route removed\n"); route_flag_set(pOldRoute, ROUTE_FLAG_BEST, 0); // Withdraw should ideally only be sent to peers that already // have received this route. Since we do not maintain // Adj-RIB-Outs, the 'withdraw' message is sent to all peers... qos_decision_process_disseminate(pRouter, sPrefix, NULL); } } // *** unlock all Adj-RIB-Ins *** routes_list_destroy(&pRoutes); routes_list_destroy(&pEBGPRoutes); AS_LOG_DEBUG(pRouter, " < qos_decision_process.end\n"); #endif return 0; }
/** * Advertise a route to a given peer: * * - do not redistribute a route learned through iBGP to an * iBGP peer BUT in this case, redistribute the best eBGP route * * !! THE ABOVE RULE SHOULD BE MOVED BEFORE INSERTION IN ADJ-RIB-OUT !! * * - avoid sending to originator peer * - avoid sending to a peer in AS-Path (SSLD) * - check standard communities (NO_ADVERTISE and NO_EXPORT) * - apply redistribution communities * - strip non-transitive extended communities * - update Next-Hop (next-hop-self) * - prepend AS-Path (if redistribution to an external peer) */ int qos_advertise_to_peer(SBGPRouter * pRouter, SPeer * pPeer, SRoute * pRoute) { SRoute * pNewRoute= NULL; int iExternalSession= (pRouter->uNumber != pPeer->uRemoteAS); AS_LOG_DEBUG(pRouter, " > qos_advertise_peer\n"); // If this route was learned through an iBGP session, do not // redistribute it to an internal peer if ((route_peer_get(pRoute)->uRemoteAS == pRouter->uNumber) && (!iExternalSession)) return -1; // Do not redistribute to peer that has announced this route if (pPeer->tAddr == pRoute->tNextHop) return -1; // Avoid loop creation (SSLD, Sender-Side Loop Detection) if ((iExternalSession) && (route_path_contains(pRoute, pPeer->uRemoteAS))) return -1; // Do not redistribute to other peers if (route_comm_contains(pRoute, COMM_NO_ADVERTISE)) return -1; // Do not redistribute outside confederation (here AS) if ((iExternalSession) && (route_comm_contains(pRoute, COMM_NO_EXPORT))) return -1; // Copy the route. This is required since the call to // as_ecomm_red_process can alter the route's attribute !! route_copy_count++; pNewRoute= route_copy(pRoute); // Check output filter and redistribution communities if (as_ecomm_red_process(pPeer, pNewRoute)) { route_ecomm_strip_non_transitive(pNewRoute); if (filter_apply(pPeer->pOutFilter, pRouter, pNewRoute)) { // The route's next-hop is this router (next-hop-self) route_nexthop_set(pNewRoute, pRouter->pNode->tAddr); // Append AS-Number if exteral peer (eBGP session) if (iExternalSession) route_path_append(pNewRoute, pRouter->uNumber); LOG_DEBUG("*** AS%d advertise to AS%d ***\n", pRouter->uNumber, pPeer->uRemoteAS); peer_announce_route(pPeer, pNewRoute); return 0; } } route_destroy_count++; route_destroy(&pNewRoute); return -1; }