/* * $Id: simulate.c,v 2.2 2000/05/23 08:03:34 masaki Exp $ */ #include #include #include #include "bgpsim.h" extern simulation_t *SIMULATION; extern io_t *IO; extern gateway_t *local_gateway; extern trace_t *default_trace; #ifdef HAVE_IPV6 extern gateway_t *local_gateway6; #endif /* HAVE_IPV6 */ static void memadd (u_char * a, u_char * b, int l) { int i, c; int carry = 0; for (i = l - 1; i >= 0; i--) { c = a[i] + b[i] + carry; carry = (c >> 8); a[i] = (c & 0xff); } } static prefix_t * copy_prefix_plus (prefix_t * prefix) { int bitlen = prefix->bitlen; u_char plus1[16]; int len = 4; prefix = copy_prefix (prefix); if (bitlen == 0) return (prefix); if (prefix->family == AF_INET) { assert (0 <= bitlen && bitlen <= 32); } #ifdef HAVE_IPV6 else if (prefix->family == AF_INET6) { assert (0 <= bitlen && bitlen <= 128); len = 16; } #endif /* HAVE_IPV6 */ else assert (0); memset (plus1, 0, sizeof plus1); plus1[(bitlen - 1) / 8] |= (0x80 >> ((bitlen - 1) % 8)); memadd (prefix_touchar (prefix), plus1, len); return (prefix); } static int precmp (prefix_t * p1, prefix_t * p2) { int len = 4; #ifdef HAVE_IPV6 if (p1->family == AF_INET6) { len = 16; assert (p2->family == AF_INET6); } #endif /* HAVE_IPV6 */ return (memcmp (prefix_tochar (p1), prefix_tochar (p2), len)); } int show_simulation (uii_connection_t * uii) { char tmpx[MAXLINE]; u_int hours, minutes, seconds; seconds = time (NULL) - SIMULATION->time_start; minutes = seconds / 60; hours = minutes / 60; minutes = minutes - hours * 60; seconds = seconds - hours * 60 * 60 - minutes * 60; sprintf (tmpx, "%02d:%02d:%02d", hours, minutes, seconds); if (SIMULATION->on_off == 1) uii_send_data (uii, "BGP Simulation\t\t[Status: RUNNING]\n"); else uii_send_data (uii, "BGP Simulation\t\t[Status: STOPPED]\n"); uii_send_data (uii, "Time:%s\t\tEnd: Indefinite\n", tmpx); uii_send_data (uii, "Packets:0\t\tEnd Total: Indefinite\n"); return (1); } /* * if change == 1, use alternate aspath and nexthop * if change == -1, delete the route */ static void simulate_add_routes (network_t * network, int change) { bgp_attr_t *attr, *atto; #ifdef HAVE_IPV6 bgp_attr_t *attr6, *atto6; #endif /* HAVE_IPV6 */ bgp_route_t *route; prefix_t *prefix; range_t *range; int i, set = network->sets[network->current]; int count = 0; int all = 0; LINKED_LIST *ll_prefixes = LL_Create (LL_DestroyFunction, Deref_Prefix, 0); LINKED_LIST *ll_attrs = LL_Create (LL_DestroyFunction, bgp_deref_attr, 0); /* this is required to keep compatible to old versions */ /* if view is specified in network-list, inject into all views */ if (ifzero (&network->view_mask, sizeof (network->view_mask))) all++; /* use disk file */ if (network->filename != NULL) { load_rib_from_disk (network->filename); return; } if (change == 1 && network->max_set > 1) { do { if (++network->current > network->max_set) { network->current = 1; } set = network->sets[network->current]; } while (set <= 0); trace (TR_PACKET, SIMULATION->trace, "Simulating network list %d changed to set %d\n", network->num, set); } attr = bgp_new_attr (PROTO_BGP); if (network->gateway) attr->gateway = network->gateway; else attr->gateway = local_gateway; atto = bgp_copy_attr (attr); /* set 1 is default */ if (set != 1) attr = apply_route_map (1, attr, NULL, 1); attr = apply_route_map (set, attr, NULL, 1); #ifdef HAVE_IPV6 attr6 = bgp_new_attr (PROTO_BGP); if (network->gateway) attr6->gateway = network->gateway; else attr6->gateway = local_gateway6; atto6 = bgp_copy_attr (attr6); /* set 1 is default */ if (set != 1) attr6 = apply_route_map (1, attr6, NULL, 1); attr6 = apply_route_map (set, attr6, NULL, 1); #endif /* HAVE_IPV6 */ LL_Iterate (network->ll_range, range) { prefix = Ref_Prefix (range->start); while (precmp (prefix, range->end) <= 0) { prefix_t *ptmp; LL_Add (ll_prefixes, prefix); ptmp = copy_prefix_plus (prefix); prefix = ptmp; if (change >= 0) { bgp_attr_t *attx = NULL; if (set != 1) { if (apply_route_map_alist (1, prefix)) { if (attx == NULL) { #ifdef HAVE_IPV6 if (prefix->family == AF_INET6) attx = bgp_copy_attr (atto6); else #endif /* HAVE_IPV6 */ attx = bgp_copy_attr (atto); } attx = apply_route_map (1, attx, prefix, 1); } } if (apply_route_map_alist (set, prefix)) { if (attx == NULL) { #ifdef HAVE_IPV6 if (prefix->family == AF_INET6) attx = bgp_copy_attr (atto6); else #endif /* HAVE_IPV6 */ attx = bgp_copy_attr (atto); } attx = apply_route_map (set, attx, prefix, 1); } if (attx != NULL) { LL_Add (ll_attrs, attx); } else { #ifdef HAVE_IPV6 if (prefix->family == AF_INET6) LL_Add (ll_attrs, bgp_ref_attr (attr6)); else #endif /* HAVE_IPV6 */ LL_Add (ll_attrs, bgp_ref_attr (attr)); } } else { #ifdef HAVE_IPV6 if (prefix->family == AF_INET6) LL_Add (ll_attrs, bgp_ref_attr (attr6)); else #endif /* HAVE_IPV6 */ LL_Add (ll_attrs, bgp_ref_attr (attr)); } } Deref_Prefix (prefix); } bgp_deref_attr (attr); bgp_deref_attr (atto); #ifdef HAVE_IPV6 bgp_deref_attr (attr6); bgp_deref_attr (atto6); #endif /* HAVE_IPV6 */ for (i = 0; i < MAX_BGP_VIEWS; i++) { view_t *view = BGP->views[i]; if (view == NULL) continue; if (view->local_bgp == NULL) continue; if (!all && !BITX_TEST (&network->view_mask, i)) continue; /* this is not what the_as initially intented, though. -- masaki */ if (network->the_as > 0 && view->local_bgp->this_as != network->the_as) continue; view_open (view); attr = NULL; LL_Iterate (ll_prefixes, prefix) { if (view->afi != family2afi (prefix->family)) continue; attr = LL_GetNext (ll_attrs, attr); if (change >= 0) { route = bgp_add_route (view, prefix, attr); } else { #ifdef notdef route = view_find_bgp_active (view, prefix); view_delete_bgp_route (view, route); #else bgp_del_route (view, prefix, attr); #endif } /* spread out processing * don't block while generarting large changes * Masaki -- does this introduce any new bugs?? */ #define BGPSIM_COUNT 10 if (count++ > BGPSIM_COUNT) { bgp_process_changes (view); view_close (view); #ifndef HAVE_LIBPTHREAD /* force to switch */ mrt_switch_schedule (); #endif /* HAVE_LIBPTHREAD */ count = 0; view_open (view); } } bgp_process_changes (view); view_close (view); } LL_Destroy (ll_prefixes); LL_Destroy (ll_attrs); } static void simulate (void) { network_t *network; peer_flap_t *peer_flap; init_mrt_thread_signals (); LL_Iterate (SIMULATION->ll_networks, network) { network->current = 1; simulate_add_routes (network, 0); network->flag = 1; if (network->stability > 0) { Timer_Turn_ON (network->timer_stability); } if (network->change_interval > 0) { Timer_Turn_ON (network->timer_change); } } if (SIMULATION->ll_peer_flaps) { LL_Iterate (SIMULATION->ll_peer_flaps, peer_flap) { Timer_Turn_ON (peer_flap->timer); } } #ifdef HAVE_LIBPTHREAD while (1) schedule_wait_for_event (SIMULATION->schedule); /* NOT REACHED */ #endif /* HAVE_LIBPTHREAD */ } void start_simulation (trace_t * trace) { SIMULATION->schedule = New_Schedule ("BGP Simulation", trace); SIMULATION->trace = trace; SIMULATION->on_off = 1; SIMULATION->time_start = time (NULL); #ifdef notdef mrt_thread_create ("BGP Simulation", SIMULATION->schedule, (thread_fn_t) simulate, trace); #else mrt_thread_create2 ("BGP Simulation", SIMULATION->schedule, NULL, NULL); schedule_event2 ("simulate", SIMULATION->schedule, simulate, 0); #endif } static void stop_simulation (uii_connection_t * uii) { network_t *network; SIMULATION->on_off = 0; uii_send_data (uii, "\nStopping Simulation...\n"); LL_Iterate (SIMULATION->ll_networks, network) { Timer_Turn_OFF (network->timer_stability); Timer_Turn_OFF (network->timer_change); uii_send_data (uii, " Simulation network %d OFF\n", network->num); } } static void network_stability (network_t * network) { if (network->flag == 1) { trace (NORM, SIMULATION->trace, "Simulating network list %d being withdrawn\n", network->num); simulate_add_routes (network, -1); network->flag = 0; } else { trace (NORM, SIMULATION->trace, "Simulating network list %d being announced\n", network->num); simulate_add_routes (network, 0); network->flag = 1; } } static void network_change (network_t * network) { trace (NORM, SIMULATION->trace, "Simulating network list %d change\n", network->num); simulate_add_routes (network, 1); network->flag = 1; } int stop_simulation_schedule (uii_connection_t * uii) { schedule_event2 ("stop_simulation", SIMULATION->schedule, stop_simulation, 1, uii); return (1); } /* public */ void network_schedule_stability (mtimer_t * timer, network_t * network) { schedule_event2 ("network_stability", SIMULATION->schedule, network_stability, 1, network); } /* public */ void network_schedule_change (mtimer_t * timer, network_t * network) { schedule_event2 ("network_change", SIMULATION->schedule, network_change, 1, network); } void bgpsim_flap_peer (mtimer_t * timer, bgp_peer_t * peer) { trace (NORM, SIMULATION->trace, "Flapping peer\n"); /* make sure peer stays down for a while */ timer_set_flags (peer->timer_Start, TIMER_EXPONENT_SET, 6); bgp_stop_peer (peer); } .