Exemplo n.º 1
0
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;
}
Exemplo n.º 2
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);
}
Exemplo n.º 3
0
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
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
/**
 * 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;
}
Exemplo n.º 6
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;
}