/*---------------------------------------------------------------------------*/ void route_decay(struct route_entry *e) { /* If routes are not refreshed, they decay over time. This function is called to decay a route. The route can only be decayed once per second. */ PRINTF("route_decay: time %d last %d decay %d for entry to %d.%d with nexthop %d.%d and cost %d\n", e->time, e->time_last_decay, e->decay, e->dest.u8[0], e->dest.u8[1], e->nexthop.u8[0], e->nexthop.u8[1], e->cost); if(e->time != e->time_last_decay) { /* Do not decay a route too often - not more than once per second. */ e->time_last_decay = e->time; e->decay++; if(e->decay >= DECAY_THRESHOLD) { PRINTF("route_decay: removing entry to %d.%d with nexthop %d.%d and cost %d\n", e->dest.u8[0], e->dest.u8[1], e->nexthop.u8[0], e->nexthop.u8[1], e->cost); route_remove(e); } } }
/* Add route into kernel */ int route_add(ARPTAB_ENTRY* cur_entry) { char routecmd_str[ROUTE_CMD_LEN]; int success = 1; if (snprintf(routecmd_str, ROUTE_CMD_LEN-1, "ip route add %s/32 metric 50 dev %s scope link", inet_ntoa(cur_entry->ipaddr_ia), cur_entry->ifname) > ROUTE_CMD_LEN-1) { syslog(LOG_INFO, "ip route command too large to fit in buffer!"); } else { if (system(routecmd_str) != 0) { syslog(LOG_INFO, "'%s' unsuccessful, will try to remove!", routecmd_str); if (debug) printf("%s failed\n", routecmd_str); route_remove(cur_entry); success = 0; } else { if (debug) printf("%s success\n", routecmd_str); success = 1; } } if (success) cur_entry->route_added = 1; return success; }
int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) { Route *route = userdata; int r; assert(route); r = route_remove(route, route->link, route_expire_callback); if (r < 0) log_warning_errno(r, "Could not remove route: %m"); else route_free(route); return 1; }
void processarp(int in_cleanup) { ARPTAB_ENTRY *cur_entry=*arptab, *prev_entry=NULL; /* First loop to remove unwanted routes */ while (cur_entry != NULL) { if (debug && verbose) printf("Working on route %s(%s) tstamp %u want_route %d\n", inet_ntoa(cur_entry->ipaddr_ia), cur_entry->ifname, (int) cur_entry->tstamp, cur_entry->want_route); if ( !cur_entry->want_route || time(NULL) - cur_entry->tstamp > ARP_TABLE_ENTRY_TIMEOUT || in_cleanup) { if (cur_entry->route_added) route_remove(cur_entry); /* remove from arp list */ if (debug) printf("Delete arp %s(%s)\n", inet_ntoa(cur_entry->ipaddr_ia), cur_entry->ifname); if (prev_entry != NULL) { prev_entry->next = cur_entry->next; free(cur_entry); cur_entry=prev_entry->next; } else { *arptab = cur_entry->next; free(cur_entry); cur_entry=*arptab; } } else { prev_entry = cur_entry; cur_entry = cur_entry->next; } } /* while loop */ /* Now loop to add new routes */ cur_entry=*arptab; while (cur_entry != NULL) { if (time(NULL) - cur_entry->tstamp <= ARP_TABLE_ENTRY_TIMEOUT && cur_entry->want_route && !cur_entry->route_added && !in_cleanup) { /* add route to the kernel */ route_add(cur_entry); } cur_entry = cur_entry->next; } /* while loop */ }
static int ipv4ll_address_lost(Link *link) { _cleanup_address_free_ Address *address = NULL; _cleanup_route_free_ Route *route = NULL; struct in_addr addr; int r; assert(link); link->ipv4ll_route = false; link->ipv4ll_address = false; r = sd_ipv4ll_get_address(link->ipv4ll, &addr); if (r < 0) return 0; log_link_debug(link, "IPv4 link-local release %u.%u.%u.%u", ADDRESS_FMT_VAL(addr)); r = address_new(&address); if (r < 0) { log_link_error_errno(link, r, "Could not allocate address: %m"); return r; } address->family = AF_INET; address->in_addr.in = addr; address->prefixlen = 16; address->scope = RT_SCOPE_LINK; address_remove(address, link, &link_address_remove_handler); r = route_new(&route); if (r < 0) { log_link_error_errno(link, r, "Could not allocate route: %m"); return r; } route->family = AF_INET; route->scope = RT_SCOPE_LINK; route->priority = IPV4LL_ROUTE_METRIC; route_remove(route, link, &link_route_remove_handler); link_check_ready(link); return 0; }
int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) { Route *route = userdata; int r; assert(route); r = route_remove(route, route->link, route_expire_callback); if (r < 0) log_warning_errno(r, "Could not remove route: %m"); else { /* route may not be exist in kernel. If we fail still remove it */ route->link->link_messages++; route_free(route); } return 1; }
static int dhcp_lease_lost(Link *link) { _cleanup_address_free_ Address *address = NULL; struct in_addr addr; struct in_addr netmask; struct in_addr gateway; unsigned prefixlen = 0; int r; assert(link); assert(link->dhcp_lease); log_link_warning(link, "DHCP lease lost"); if (link->network->dhcp_use_routes) { _cleanup_free_ sd_dhcp_route **routes = NULL; int n, i; n = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes); if (n >= 0) { for (i = 0; i < n; i++) { _cleanup_route_free_ Route *route = NULL; r = route_new(&route); if (r >= 0) { route->family = AF_INET; assert_se(sd_dhcp_route_get_gateway(routes[i], &route->gw.in) >= 0); assert_se(sd_dhcp_route_get_destination(routes[i], &route->dst.in) >= 0); assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen) >= 0); route_remove(route, link, link_route_remove_handler); } } } } r = address_new(&address); if (r >= 0) { r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway); if (r >= 0) { _cleanup_route_free_ Route *route_gw = NULL; _cleanup_route_free_ Route *route = NULL; r = route_new(&route_gw); if (r >= 0) { route_gw->family = AF_INET; route_gw->dst.in = gateway; route_gw->dst_prefixlen = 32; route_gw->scope = RT_SCOPE_LINK; route_remove(route_gw, link, link_route_remove_handler); } r = route_new(&route); if (r >= 0) { route->family = AF_INET; route->gw.in = gateway; route_remove(route, link, link_route_remove_handler); } } r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr); if (r >= 0) { r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask); if (r >= 0) prefixlen = in_addr_netmask_to_prefixlen(&netmask); address->family = AF_INET; address->in_addr.in = addr; address->prefixlen = prefixlen; address_remove(address, link, link_address_remove_handler); } } if (link->network->dhcp_use_mtu) { uint16_t mtu; r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu); if (r >= 0 && link->original_mtu != mtu) { r = link_set_mtu(link, link->original_mtu); if (r < 0) { log_link_warning(link, "DHCP error: could not reset MTU"); link_enter_failed(link); return r; } } } if (link->network->dhcp_use_hostname) { const char *hostname = NULL; if (link->network->dhcp_hostname) hostname = link->network->dhcp_hostname; else (void) sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname); if (hostname) { /* If a hostname was set due to the lease, then unset it now. */ r = manager_set_hostname(link->manager, NULL); if (r < 0) log_link_warning_errno(link, r, "Failed to reset transient hostname: %m"); } } link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease); link_dirty(link); link->dhcp4_configured = false; return 0; }