table.c revision 186119
118316Swollman/* 218316Swollman * Copyright (c) 1983, 1988, 1993 318316Swollman * The Regents of the University of California. All rights reserved. 418316Swollman * 518316Swollman * Redistribution and use in source and binary forms, with or without 618316Swollman * modification, are permitted provided that the following conditions 718316Swollman * are met: 818316Swollman * 1. Redistributions of source code must retain the above copyright 918316Swollman * notice, this list of conditions and the following disclaimer. 1018316Swollman * 2. Redistributions in binary form must reproduce the above copyright 1118316Swollman * notice, this list of conditions and the following disclaimer in the 1218316Swollman * documentation and/or other materials provided with the distribution. 1318316Swollman * 4. Neither the name of the University nor the names of its contributors 1418316Swollman * may be used to endorse or promote products derived from this software 1518316Swollman * without specific prior written permission. 1618316Swollman * 1718316Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1818316Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1918316Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2018316Swollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2118316Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2218316Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2318316Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2418316Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2518316Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2618316Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2718316Swollman * SUCH DAMAGE. 2846303Smarkm * 2950476Speter * $FreeBSD: head/sbin/routed/table.c 186119 2008-12-15 06:10:57Z qingli $ 3018316Swollman */ 3118316Swollman 3246303Smarkm#include "defs.h" 3346303Smarkm 34126250Sbms#ifdef __NetBSD__ 3546303Smarkm__RCSID("$NetBSD$"); 36126250Sbms#elif defined(__FreeBSD__) 37126250Sbms__RCSID("$FreeBSD: head/sbin/routed/table.c 186119 2008-12-15 06:10:57Z qingli $"); 38126250Sbms#else 39126250Sbms__RCSID("$Revision: 2.27 $"); 40126250Sbms#ident "$Revision: 2.27 $" 4118316Swollman#endif 4218316Swollman 4318316Swollmanstatic struct rt_spare *rts_better(struct rt_entry *); 4446303Smarkmstatic struct rt_spare rts_empty = {0,0,0,HOPCNT_INFINITY,0,0,0}; 4546303Smarkmstatic void set_need_flash(void); 4646303Smarkm#ifdef _HAVE_SIN_LEN 4746303Smarkmstatic void masktrim(struct sockaddr_in *ap); 4846303Smarkm#else 4946303Smarkmstatic void masktrim(struct sockaddr_in_new *ap); 5046303Smarkm#endif 5118316Swollman 5246303Smarkm 5318316Swollmanstruct radix_node_head *rhead; /* root of the radix tree */ 5418316Swollman 5518316Swollmanint need_flash = 1; /* flash update needed 5618316Swollman * start =1 to suppress the 1st 5718316Swollman */ 5818316Swollman 5918316Swollmanstruct timeval age_timer; /* next check of old routes */ 6018316Swollmanstruct timeval need_kern = { /* need to update kernel table */ 6164131Ssheldonh EPOCH+MIN_WAITTIME-1, 0 6218316Swollman}; 6318316Swollman 6418316Swollmanint stopint; 6518316Swollman 6618316Swollmanint total_routes; 6718316Swollman 6819885Swollman/* zap any old routes through this gateway */ 6918316Swollmannaddr age_bad_gate; 7018316Swollman 7118316Swollman 7218316Swollman/* It is desirable to "aggregate" routes, to combine differing routes of 7318316Swollman * the same metric and next hop into a common route with a smaller netmask 7418316Swollman * or to suppress redundant routes, routes that add no information to 7518316Swollman * routes with smaller netmasks. 7618316Swollman * 7718316Swollman * A route is redundant if and only if any and all routes with smaller 7818316Swollman * but matching netmasks and nets are the same. Since routes are 7918316Swollman * kept sorted in the radix tree, redundant routes always come second. 8018316Swollman * 8118316Swollman * There are two kinds of aggregations. First, two routes of the same bit 8218316Swollman * mask and differing only in the least significant bit of the network 8318316Swollman * number can be combined into a single route with a coarser mask. 8418316Swollman * 8518316Swollman * Second, a route can be suppressed in favor of another route with a more 8618316Swollman * coarse mask provided no incompatible routes with intermediate masks 8718316Swollman * are present. The second kind of aggregation involves suppressing routes. 8818316Swollman * A route must not be suppressed if an incompatible route exists with 8918316Swollman * an intermediate mask, since the suppressed route would be covered 9018316Swollman * by the intermediate. 9118316Swollman * 9218316Swollman * This code relies on the radix tree walk encountering routes 9318316Swollman * sorted first by address, with the smallest address first. 9418316Swollman */ 9518316Swollman 9618316Swollmanstruct ag_info ag_slots[NUM_AG_SLOTS], *ag_avail, *ag_corsest, *ag_finest; 9718316Swollman 9818316Swollman/* #define DEBUG_AG */ 9918316Swollman#ifdef DEBUG_AG 10018316Swollman#define CHECK_AG() {int acnt = 0; struct ag_info *cag; \ 10118316Swollman for (cag = ag_avail; cag != 0; cag = cag->ag_fine) \ 10218316Swollman acnt++; \ 10318316Swollman for (cag = ag_corsest; cag != 0; cag = cag->ag_fine) \ 10418316Swollman acnt++; \ 10518316Swollman if (acnt != NUM_AG_SLOTS) { \ 10618316Swollman (void)fflush(stderr); \ 10718316Swollman abort(); \ 10818316Swollman } \ 10918316Swollman} 11018316Swollman#else 11118316Swollman#define CHECK_AG() 11218316Swollman#endif 11318316Swollman 11418316Swollman 11518316Swollman/* Output the contents of an aggregation table slot. 11618316Swollman * This function must always be immediately followed with the deletion 11718316Swollman * of the target slot. 11818316Swollman */ 11918316Swollmanstatic void 12018316Swollmanag_out(struct ag_info *ag, 12118316Swollman void (*out)(struct ag_info *)) 12218316Swollman{ 12318316Swollman struct ag_info *ag_cors; 12418316Swollman naddr bit; 12518316Swollman 12618316Swollman 12746303Smarkm /* Forget it if this route should not be output for split-horizon. */ 12846303Smarkm if (ag->ag_state & AGS_SPLIT_HZ) 12946303Smarkm return; 13046303Smarkm 13118316Swollman /* If we output both the even and odd twins, then the immediate parent, 13218316Swollman * if it is present, is redundant, unless the parent manages to 13318316Swollman * aggregate into something coarser. 13418316Swollman * On successive calls, this code detects the even and odd twins, 13518316Swollman * and marks the parent. 13618316Swollman * 13718316Swollman * Note that the order in which the radix tree code emits routes 13818316Swollman * ensures that the twins are seen before the parent is emitted. 13918316Swollman */ 14018316Swollman ag_cors = ag->ag_cors; 14118316Swollman if (ag_cors != 0 14218316Swollman && ag_cors->ag_mask == ag->ag_mask<<1 14318316Swollman && ag_cors->ag_dst_h == (ag->ag_dst_h & ag_cors->ag_mask)) { 14418316Swollman ag_cors->ag_state |= ((ag_cors->ag_dst_h == ag->ag_dst_h) 14518316Swollman ? AGS_REDUN0 14618316Swollman : AGS_REDUN1); 14718316Swollman } 14818316Swollman 14918316Swollman /* Skip it if this route is itself redundant. 15018316Swollman * 15118316Swollman * It is ok to change the contents of the slot here, since it is 15218316Swollman * always deleted next. 15318316Swollman */ 15418316Swollman if (ag->ag_state & AGS_REDUN0) { 15518316Swollman if (ag->ag_state & AGS_REDUN1) 15646303Smarkm return; /* quit if fully redundant */ 15746303Smarkm /* make it finer if it is half-redundant */ 15818316Swollman bit = (-ag->ag_mask) >> 1; 15918316Swollman ag->ag_dst_h |= bit; 16018316Swollman ag->ag_mask |= bit; 16118316Swollman 16218316Swollman } else if (ag->ag_state & AGS_REDUN1) { 16346303Smarkm /* make it finer if it is half-redundant */ 16418316Swollman bit = (-ag->ag_mask) >> 1; 16518316Swollman ag->ag_mask |= bit; 16618316Swollman } 16718316Swollman out(ag); 16818316Swollman} 16918316Swollman 17018316Swollman 17118316Swollmanstatic void 17218316Swollmanag_del(struct ag_info *ag) 17318316Swollman{ 17418316Swollman CHECK_AG(); 17518316Swollman 17618316Swollman if (ag->ag_cors == 0) 17718316Swollman ag_corsest = ag->ag_fine; 17818316Swollman else 17918316Swollman ag->ag_cors->ag_fine = ag->ag_fine; 18018316Swollman 18118316Swollman if (ag->ag_fine == 0) 18218316Swollman ag_finest = ag->ag_cors; 18318316Swollman else 18418316Swollman ag->ag_fine->ag_cors = ag->ag_cors; 18518316Swollman 18618316Swollman ag->ag_fine = ag_avail; 18718316Swollman ag_avail = ag; 18818316Swollman 18918316Swollman CHECK_AG(); 19018316Swollman} 19118316Swollman 19218316Swollman 19337908Scharnier/* Flush routes waiting for aggregation. 19418316Swollman * This must not suppress a route unless it is known that among all 19518316Swollman * routes with coarser masks that match it, the one with the longest 19618316Swollman * mask is appropriate. This is ensured by scanning the routes 19737908Scharnier * in lexical order, and with the most restrictive mask first 19818316Swollman * among routes to the same destination. 19918316Swollman */ 20018316Swollmanvoid 20118316Swollmanag_flush(naddr lim_dst_h, /* flush routes to here */ 20218316Swollman naddr lim_mask, /* matching this mask */ 20318316Swollman void (*out)(struct ag_info *)) 20418316Swollman{ 20518316Swollman struct ag_info *ag, *ag_cors; 20618316Swollman naddr dst_h; 20718316Swollman 20818316Swollman 20918316Swollman for (ag = ag_finest; 21018316Swollman ag != 0 && ag->ag_mask >= lim_mask; 21118316Swollman ag = ag_cors) { 21218316Swollman ag_cors = ag->ag_cors; 21318316Swollman 21418316Swollman /* work on only the specified routes */ 21518316Swollman dst_h = ag->ag_dst_h; 21618316Swollman if ((dst_h & lim_mask) != lim_dst_h) 21718316Swollman continue; 21818316Swollman 21918316Swollman if (!(ag->ag_state & AGS_SUPPRESS)) 22018316Swollman ag_out(ag, out); 22118316Swollman 22218316Swollman else for ( ; ; ag_cors = ag_cors->ag_cors) { 22318316Swollman /* Look for a route that can suppress the 22418316Swollman * current route */ 22518316Swollman if (ag_cors == 0) { 22618316Swollman /* failed, so output it and look for 22718316Swollman * another route to work on 22818316Swollman */ 22918316Swollman ag_out(ag, out); 23018316Swollman break; 23118316Swollman } 23218316Swollman 23318316Swollman if ((dst_h & ag_cors->ag_mask) == ag_cors->ag_dst_h) { 23418316Swollman /* We found a route with a coarser mask that 23518316Swollman * aggregates the current target. 23618316Swollman * 23718316Swollman * If it has a different next hop, it 23818316Swollman * cannot replace the target, so output 23918316Swollman * the target. 24018316Swollman */ 24118316Swollman if (ag->ag_gate != ag_cors->ag_gate 24218316Swollman && !(ag->ag_state & AGS_FINE_GATE) 24318316Swollman && !(ag_cors->ag_state & AGS_CORS_GATE)) { 24418316Swollman ag_out(ag, out); 24518316Swollman break; 24618316Swollman } 24718316Swollman 24818316Swollman /* If the coarse route has a good enough 24918316Swollman * metric, it suppresses the target. 25046303Smarkm * If the suppressed target was redundant, 25146303Smarkm * then mark the suppressor redundant. 25218316Swollman */ 25318316Swollman if (ag_cors->ag_pref <= ag->ag_pref) { 25418316Swollman if (AG_IS_REDUN(ag->ag_state) 25518316Swollman && ag_cors->ag_mask==ag->ag_mask<<1) { 25618316Swollman if (ag_cors->ag_dst_h == dst_h) 25718316Swollman ag_cors->ag_state |= AGS_REDUN0; 25818316Swollman else 25918316Swollman ag_cors->ag_state |= AGS_REDUN1; 26018316Swollman } 26118316Swollman if (ag->ag_tag != ag_cors->ag_tag) 26218316Swollman ag_cors->ag_tag = 0; 26318316Swollman if (ag->ag_nhop != ag_cors->ag_nhop) 26418316Swollman ag_cors->ag_nhop = 0; 26518316Swollman break; 26618316Swollman } 26718316Swollman } 26818316Swollman } 26918316Swollman 27018316Swollman /* That route has either been output or suppressed */ 27118316Swollman ag_cors = ag->ag_cors; 27218316Swollman ag_del(ag); 27318316Swollman } 27418316Swollman 27518316Swollman CHECK_AG(); 27618316Swollman} 27718316Swollman 27818316Swollman 27918316Swollman/* Try to aggregate a route with previous routes. 28018316Swollman */ 28118316Swollmanvoid 28218316Swollmanag_check(naddr dst, 28318316Swollman naddr mask, 28418316Swollman naddr gate, 28518316Swollman naddr nhop, 28618316Swollman char metric, 28718316Swollman char pref, 288126250Sbms u_int new_seqno, 28918316Swollman u_short tag, 29018316Swollman u_short state, 29118316Swollman void (*out)(struct ag_info *)) /* output using this */ 29218316Swollman{ 29318316Swollman struct ag_info *ag, *nag, *ag_cors; 29418316Swollman naddr xaddr; 29518316Swollman int x; 29618316Swollman 29790868Smike dst = ntohl(dst); 29818316Swollman 29918316Swollman /* Punt non-contiguous subnet masks. 30018316Swollman * 30118316Swollman * (X & -X) contains a single bit if and only if X is a power of 2. 30218316Swollman * (X + (X & -X)) == 0 if and only if X is a power of 2. 30318316Swollman */ 30418316Swollman if ((mask & -mask) + mask != 0) { 30518316Swollman struct ag_info nc_ag; 30618316Swollman 30718316Swollman nc_ag.ag_dst_h = dst; 30818316Swollman nc_ag.ag_mask = mask; 30918316Swollman nc_ag.ag_gate = gate; 31018316Swollman nc_ag.ag_nhop = nhop; 31118316Swollman nc_ag.ag_metric = metric; 31218316Swollman nc_ag.ag_pref = pref; 31318316Swollman nc_ag.ag_tag = tag; 31418316Swollman nc_ag.ag_state = state; 315126250Sbms nc_ag.ag_seqno = new_seqno; 31618316Swollman out(&nc_ag); 31718316Swollman return; 31818316Swollman } 31918316Swollman 32018316Swollman /* Search for the right slot in the aggregation table. 32118316Swollman */ 32218316Swollman ag_cors = 0; 32318316Swollman ag = ag_corsest; 32418316Swollman while (ag != 0) { 32518316Swollman if (ag->ag_mask >= mask) 32618316Swollman break; 32718316Swollman 32818316Swollman /* Suppress old routes (i.e. combine with compatible routes 32918316Swollman * with coarser masks) as we look for the right slot in the 33018316Swollman * aggregation table for the new route. 33118316Swollman * A route to an address less than the current destination 33218316Swollman * will not be affected by the current route or any route 33318316Swollman * seen hereafter. That means it is safe to suppress it. 33437908Scharnier * This check keeps poor routes (e.g. with large hop counts) 33537908Scharnier * from preventing suppression of finer routes. 33618316Swollman */ 33718316Swollman if (ag_cors != 0 33818316Swollman && ag->ag_dst_h < dst 33918316Swollman && (ag->ag_state & AGS_SUPPRESS) 34018316Swollman && ag_cors->ag_pref <= ag->ag_pref 34118316Swollman && (ag->ag_dst_h & ag_cors->ag_mask) == ag_cors->ag_dst_h 34218316Swollman && (ag_cors->ag_gate == ag->ag_gate 34318316Swollman || (ag->ag_state & AGS_FINE_GATE) 34418316Swollman || (ag_cors->ag_state & AGS_CORS_GATE))) { 34546303Smarkm /* If the suppressed target was redundant, 34646303Smarkm * then mark the suppressor redundant. 34746303Smarkm */ 34818316Swollman if (AG_IS_REDUN(ag->ag_state) 34964131Ssheldonh && ag_cors->ag_mask == ag->ag_mask<<1) { 35018316Swollman if (ag_cors->ag_dst_h == dst) 35118316Swollman ag_cors->ag_state |= AGS_REDUN0; 35218316Swollman else 35318316Swollman ag_cors->ag_state |= AGS_REDUN1; 35418316Swollman } 35518316Swollman if (ag->ag_tag != ag_cors->ag_tag) 35618316Swollman ag_cors->ag_tag = 0; 35718316Swollman if (ag->ag_nhop != ag_cors->ag_nhop) 35818316Swollman ag_cors->ag_nhop = 0; 35918316Swollman ag_del(ag); 36018316Swollman CHECK_AG(); 36118316Swollman } else { 36218316Swollman ag_cors = ag; 36318316Swollman } 36418316Swollman ag = ag_cors->ag_fine; 36518316Swollman } 36618316Swollman 36718316Swollman /* If we find the even/odd twin of the new route, and if the 36818316Swollman * masks and so forth are equal, we can aggregate them. 36918316Swollman * We can probably promote one of the pair. 37018316Swollman * 37118316Swollman * Since the routes are encountered in lexical order, 37218316Swollman * the new route must be odd. However, the second or later 37318316Swollman * times around this loop, it could be the even twin promoted 37418316Swollman * from the even/odd pair of twins of the finer route. 37518316Swollman */ 37618316Swollman while (ag != 0 37718316Swollman && ag->ag_mask == mask 37818316Swollman && ((ag->ag_dst_h ^ dst) & (mask<<1)) == 0) { 37918316Swollman 38018316Swollman /* Here we know the target route and the route in the current 38118316Swollman * slot have the same netmasks and differ by at most the 38218316Swollman * last bit. They are either for the same destination, or 38318316Swollman * for an even/odd pair of destinations. 38418316Swollman */ 38518316Swollman if (ag->ag_dst_h == dst) { 38618316Swollman /* We have two routes to the same destination. 38718316Swollman * Routes are encountered in lexical order, so a 38818316Swollman * route is never promoted until the parent route is 38918316Swollman * already present. So we know that the new route is 39046303Smarkm * a promoted (or aggregated) pair and the route 39146303Smarkm * already in the slot is the explicit route. 39218316Swollman * 39318316Swollman * Prefer the best route if their metrics differ, 39446303Smarkm * or the aggregated one if not, following a sort 39518316Swollman * of longest-match rule. 39618316Swollman */ 39718316Swollman if (pref <= ag->ag_pref) { 39818316Swollman ag->ag_gate = gate; 39918316Swollman ag->ag_nhop = nhop; 40018316Swollman ag->ag_tag = tag; 40118316Swollman ag->ag_metric = metric; 40218316Swollman ag->ag_pref = pref; 403126250Sbms if (ag->ag_seqno < new_seqno) 404126250Sbms ag->ag_seqno = new_seqno; 40518316Swollman x = ag->ag_state; 40618316Swollman ag->ag_state = state; 40718316Swollman state = x; 40818316Swollman } 40918316Swollman 41046303Smarkm /* Some bits are set if they are set on either route, 41146303Smarkm * except when the route is for an interface. 41246303Smarkm */ 41346303Smarkm if (!(ag->ag_state & AGS_IF)) 41446303Smarkm ag->ag_state |= (state & (AGS_AGGREGATE_EITHER 41546303Smarkm | AGS_REDUN0 41646303Smarkm | AGS_REDUN1)); 41718316Swollman return; 41818316Swollman } 41918316Swollman 42018316Swollman /* If one of the routes can be promoted and the other can 42118316Swollman * be suppressed, it may be possible to combine them or 42218316Swollman * worthwhile to promote one. 42318316Swollman * 42446303Smarkm * Any route that can be promoted is always 42518316Swollman * marked to be eligible to be suppressed. 42618316Swollman */ 42746303Smarkm if (!((state & AGS_AGGREGATE) 42818316Swollman && (ag->ag_state & AGS_SUPPRESS)) 42946303Smarkm && !((ag->ag_state & AGS_AGGREGATE) 43018316Swollman && (state & AGS_SUPPRESS))) 43118316Swollman break; 43218316Swollman 43318316Swollman /* A pair of even/odd twin routes can be combined 43418316Swollman * if either is redundant, or if they are via the 43518316Swollman * same gateway and have the same metric. 43618316Swollman */ 43718316Swollman if (AG_IS_REDUN(ag->ag_state) 43818316Swollman || AG_IS_REDUN(state) 43918316Swollman || (ag->ag_gate == gate 44018316Swollman && ag->ag_pref == pref 44146303Smarkm && (state & ag->ag_state & AGS_AGGREGATE) != 0)) { 44218316Swollman 44318316Swollman /* We have both the even and odd pairs. 44418316Swollman * Since the routes are encountered in order, 44518316Swollman * the route in the slot must be the even twin. 44618316Swollman * 44746303Smarkm * Combine and promote (aggregate) the pair of routes. 44818316Swollman */ 449126250Sbms if (new_seqno < ag->ag_seqno) 450126250Sbms new_seqno = ag->ag_seqno; 45118316Swollman if (!AG_IS_REDUN(state)) 45218316Swollman state &= ~AGS_REDUN1; 45318316Swollman if (AG_IS_REDUN(ag->ag_state)) 45418316Swollman state |= AGS_REDUN0; 45518316Swollman else 45618316Swollman state &= ~AGS_REDUN0; 45746303Smarkm state |= (ag->ag_state & AGS_AGGREGATE_EITHER); 45818316Swollman if (ag->ag_tag != tag) 45918316Swollman tag = 0; 46018316Swollman if (ag->ag_nhop != nhop) 46118316Swollman nhop = 0; 46218316Swollman 46318316Swollman /* Get rid of the even twin that was already 46418316Swollman * in the slot. 46518316Swollman */ 46618316Swollman ag_del(ag); 46718316Swollman 46818316Swollman } else if (ag->ag_pref >= pref 46946303Smarkm && (ag->ag_state & AGS_AGGREGATE)) { 47018316Swollman /* If we cannot combine the pair, maybe the route 47118316Swollman * with the worse metric can be promoted. 47218316Swollman * 47318316Swollman * Promote the old, even twin, by giving its slot 47418316Swollman * in the table to the new, odd twin. 47518316Swollman */ 47618316Swollman ag->ag_dst_h = dst; 47718316Swollman 47818316Swollman xaddr = ag->ag_gate; 47918316Swollman ag->ag_gate = gate; 48018316Swollman gate = xaddr; 48118316Swollman 48218316Swollman xaddr = ag->ag_nhop; 48318316Swollman ag->ag_nhop = nhop; 48418316Swollman nhop = xaddr; 48518316Swollman 48618316Swollman x = ag->ag_tag; 48718316Swollman ag->ag_tag = tag; 48818316Swollman tag = x; 48918316Swollman 49046303Smarkm /* The promoted route is even-redundant only if the 49146303Smarkm * even twin was fully redundant. It is not 49246303Smarkm * odd-redundant because the odd-twin will still be 49346303Smarkm * in the table. 49446303Smarkm */ 49518316Swollman x = ag->ag_state; 49646303Smarkm if (!AG_IS_REDUN(x)) 49746303Smarkm x &= ~AGS_REDUN0; 49846303Smarkm x &= ~AGS_REDUN1; 49918316Swollman ag->ag_state = state; 50018316Swollman state = x; 50118316Swollman 50218316Swollman x = ag->ag_metric; 50318316Swollman ag->ag_metric = metric; 50418316Swollman metric = x; 50518316Swollman 50618316Swollman x = ag->ag_pref; 50718316Swollman ag->ag_pref = pref; 50818316Swollman pref = x; 50918316Swollman 51046303Smarkm /* take the newest sequence number */ 511126250Sbms if (new_seqno <= ag->ag_seqno) 512126250Sbms new_seqno = ag->ag_seqno; 51318316Swollman else 514126250Sbms ag->ag_seqno = new_seqno; 51518316Swollman 51618316Swollman } else { 51746303Smarkm if (!(state & AGS_AGGREGATE)) 51818316Swollman break; /* cannot promote either twin */ 51918316Swollman 52046303Smarkm /* Promote the new, odd twin by shaving its 52118316Swollman * mask and address. 52246303Smarkm * The promoted route is odd-redundant only if the 52346303Smarkm * odd twin was fully redundant. It is not 52446303Smarkm * even-redundant because the even twin is still in 52546303Smarkm * the table. 52618316Swollman */ 52746303Smarkm if (!AG_IS_REDUN(state)) 52846303Smarkm state &= ~AGS_REDUN1; 52946303Smarkm state &= ~AGS_REDUN0; 530126250Sbms if (new_seqno < ag->ag_seqno) 531126250Sbms new_seqno = ag->ag_seqno; 53218316Swollman else 533126250Sbms ag->ag_seqno = new_seqno; 53418316Swollman } 53518316Swollman 53618316Swollman mask <<= 1; 53718316Swollman dst &= mask; 53818316Swollman 53918316Swollman if (ag_cors == 0) { 54018316Swollman ag = ag_corsest; 54118316Swollman break; 54218316Swollman } 54318316Swollman ag = ag_cors; 54418316Swollman ag_cors = ag->ag_cors; 54518316Swollman } 54618316Swollman 54718316Swollman /* When we can no longer promote and combine routes, 54818316Swollman * flush the old route in the target slot. Also flush 54918316Swollman * any finer routes that we know will never be aggregated by 55018316Swollman * the new route. 55118316Swollman * 55218316Swollman * In case we moved toward coarser masks, 55318316Swollman * get back where we belong 55418316Swollman */ 55518316Swollman if (ag != 0 55618316Swollman && ag->ag_mask < mask) { 55718316Swollman ag_cors = ag; 55818316Swollman ag = ag->ag_fine; 55918316Swollman } 56018316Swollman 56118316Swollman /* Empty the target slot 56218316Swollman */ 56318316Swollman if (ag != 0 && ag->ag_mask == mask) { 56418316Swollman ag_flush(ag->ag_dst_h, ag->ag_mask, out); 56518316Swollman ag = (ag_cors == 0) ? ag_corsest : ag_cors->ag_fine; 56618316Swollman } 56718316Swollman 56818316Swollman#ifdef DEBUG_AG 56918316Swollman (void)fflush(stderr); 57018316Swollman if (ag == 0 && ag_cors != ag_finest) 57118316Swollman abort(); 57218316Swollman if (ag_cors == 0 && ag != ag_corsest) 57318316Swollman abort(); 57418316Swollman if (ag != 0 && ag->ag_cors != ag_cors) 57518316Swollman abort(); 57618316Swollman if (ag_cors != 0 && ag_cors->ag_fine != ag) 57718316Swollman abort(); 57818316Swollman CHECK_AG(); 57918316Swollman#endif 58018316Swollman 58118316Swollman /* Save the new route on the end of the table. 58218316Swollman */ 58318316Swollman nag = ag_avail; 58418316Swollman ag_avail = nag->ag_fine; 58518316Swollman 58618316Swollman nag->ag_dst_h = dst; 58718316Swollman nag->ag_mask = mask; 58818316Swollman nag->ag_gate = gate; 58918316Swollman nag->ag_nhop = nhop; 59018316Swollman nag->ag_metric = metric; 59118316Swollman nag->ag_pref = pref; 59218316Swollman nag->ag_tag = tag; 59318316Swollman nag->ag_state = state; 594126250Sbms nag->ag_seqno = new_seqno; 59518316Swollman 59618316Swollman nag->ag_fine = ag; 59718316Swollman if (ag != 0) 59818316Swollman ag->ag_cors = nag; 59918316Swollman else 60018316Swollman ag_finest = nag; 60118316Swollman nag->ag_cors = ag_cors; 60218316Swollman if (ag_cors == 0) 60318316Swollman ag_corsest = nag; 60418316Swollman else 60518316Swollman ag_cors->ag_fine = nag; 60618316Swollman CHECK_AG(); 60718316Swollman} 60818316Swollman 60918316Swollman 61058805Sshin#define NAME0_LEN 14 61146303Smarkmstatic const char * 61218316Swollmanrtm_type_name(u_char type) 61318316Swollman{ 61446303Smarkm static const char *rtm_types[] = { 61518316Swollman "RTM_ADD", 61618316Swollman "RTM_DELETE", 61718316Swollman "RTM_CHANGE", 61818316Swollman "RTM_GET", 61918316Swollman "RTM_LOSING", 62018316Swollman "RTM_REDIRECT", 62118316Swollman "RTM_MISS", 62218316Swollman "RTM_LOCK", 62318316Swollman "RTM_OLDADD", 62418316Swollman "RTM_OLDDEL", 62518316Swollman "RTM_RESOLVE", 62618316Swollman "RTM_NEWADDR", 62718316Swollman "RTM_DELADDR", 628126250Sbms#ifdef RTM_OIFINFO 629126250Sbms "RTM_OIFINFO", 630126250Sbms#endif 63158821Sshin "RTM_IFINFO", 63258821Sshin "RTM_NEWMADDR", 63358821Sshin "RTM_DELMADDR" 63418316Swollman }; 63564483Ssheldonh#define NEW_RTM_PAT "RTM type %#x" 63664483Ssheldonh static char name0[sizeof(NEW_RTM_PAT)+2]; 63718316Swollman 63818316Swollman 63918316Swollman if (type > sizeof(rtm_types)/sizeof(rtm_types[0]) 64018316Swollman || type == 0) { 64164483Ssheldonh snprintf(name0, sizeof(name0), NEW_RTM_PAT, type); 64218316Swollman return name0; 64318316Swollman } else { 64418316Swollman return rtm_types[type-1]; 64518316Swollman } 64664483Ssheldonh#undef NEW_RTM_PAT 64718316Swollman} 64818316Swollman 64918316Swollman 65018316Swollman/* Trim a mask in a sockaddr 65146303Smarkm * Produce a length of 0 for an address of 0. 65246303Smarkm * Otherwise produce the index of the first zero byte. 65318316Swollman */ 65418316Swollmanvoid 65518316Swollman#ifdef _HAVE_SIN_LEN 65618316Swollmanmasktrim(struct sockaddr_in *ap) 65718316Swollman#else 65818316Swollmanmasktrim(struct sockaddr_in_new *ap) 65918316Swollman#endif 66018316Swollman{ 66146303Smarkm char *cp; 66218316Swollman 66346303Smarkm if (ap->sin_addr.s_addr == 0) { 66446303Smarkm ap->sin_len = 0; 66546303Smarkm return; 66646303Smarkm } 66718316Swollman cp = (char *)(&ap->sin_addr.s_addr+1); 66818316Swollman while (*--cp == 0) 66918316Swollman continue; 67018316Swollman ap->sin_len = cp - (char*)ap + 1; 67118316Swollman} 67218316Swollman 67318316Swollman 67418316Swollman/* Tell the kernel to add, delete or change a route 67518316Swollman */ 67618316Swollmanstatic void 67718316Swollmanrtioctl(int action, /* RTM_DELETE, etc */ 67818316Swollman naddr dst, 67918316Swollman naddr gate, 68018316Swollman naddr mask, 68118316Swollman int metric, 68218316Swollman int flags) 68318316Swollman{ 68418316Swollman struct { 68518316Swollman struct rt_msghdr w_rtm; 68618316Swollman struct sockaddr_in w_dst; 68718316Swollman struct sockaddr_in w_gate; 68818316Swollman#ifdef _HAVE_SA_LEN 68918316Swollman struct sockaddr_in w_mask; 69018316Swollman#else 69118316Swollman struct sockaddr_in_new w_mask; 69218316Swollman#endif 69318316Swollman } w; 69418316Swollman long cc; 69546303Smarkm# define PAT " %-10s %s metric=%d flags=%#x" 69646303Smarkm# define ARGS rtm_type_name(action), rtname(dst,mask,gate), metric, flags 69718316Swollman 69818316Swollmanagain: 69946303Smarkm memset(&w, 0, sizeof(w)); 70018316Swollman w.w_rtm.rtm_msglen = sizeof(w); 70118316Swollman w.w_rtm.rtm_version = RTM_VERSION; 70218316Swollman w.w_rtm.rtm_type = action; 70318316Swollman w.w_rtm.rtm_flags = flags; 70418316Swollman w.w_rtm.rtm_seq = ++rt_sock_seqno; 70518316Swollman w.w_rtm.rtm_addrs = RTA_DST|RTA_GATEWAY; 70646303Smarkm if (metric != 0 || action == RTM_CHANGE) { 70718316Swollman w.w_rtm.rtm_rmx.rmx_hopcount = metric; 70818316Swollman w.w_rtm.rtm_inits |= RTV_HOPCOUNT; 70918316Swollman } 71018316Swollman w.w_dst.sin_family = AF_INET; 71118316Swollman w.w_dst.sin_addr.s_addr = dst; 71218316Swollman w.w_gate.sin_family = AF_INET; 71318316Swollman w.w_gate.sin_addr.s_addr = gate; 71418316Swollman#ifdef _HAVE_SA_LEN 71518316Swollman w.w_dst.sin_len = sizeof(w.w_dst); 71618316Swollman w.w_gate.sin_len = sizeof(w.w_gate); 71718316Swollman#endif 71818316Swollman if (mask == HOST_MASK) { 71918316Swollman w.w_rtm.rtm_flags |= RTF_HOST; 72018316Swollman w.w_rtm.rtm_msglen -= sizeof(w.w_mask); 72118316Swollman } else { 72218316Swollman w.w_rtm.rtm_addrs |= RTA_NETMASK; 72318316Swollman w.w_mask.sin_addr.s_addr = htonl(mask); 72418316Swollman#ifdef _HAVE_SA_LEN 72518316Swollman masktrim(&w.w_mask); 72646303Smarkm if (w.w_mask.sin_len == 0) 72746303Smarkm w.w_mask.sin_len = sizeof(long); 72818316Swollman w.w_rtm.rtm_msglen -= (sizeof(w.w_mask) - w.w_mask.sin_len); 72918316Swollman#endif 73018316Swollman } 73118316Swollman 73218316Swollman#ifndef NO_INSTALL 73318316Swollman cc = write(rt_sock, &w, w.w_rtm.rtm_msglen); 73418316Swollman if (cc < 0) { 73518316Swollman if (errno == ESRCH 73618316Swollman && (action == RTM_CHANGE || action == RTM_DELETE)) { 73746303Smarkm trace_act("route disappeared before" PAT, ARGS); 73818316Swollman if (action == RTM_CHANGE) { 73918316Swollman action = RTM_ADD; 74018316Swollman goto again; 74118316Swollman } 74218316Swollman return; 74318316Swollman } 74446303Smarkm msglog("write(rt_sock)" PAT ": %s", ARGS, strerror(errno)); 74546303Smarkm return; 74646303Smarkm } else if (cc != w.w_rtm.rtm_msglen) { 74746303Smarkm msglog("write(rt_sock) wrote %ld instead of %d for" PAT, 74846303Smarkm cc, w.w_rtm.rtm_msglen, ARGS); 74946303Smarkm return; 75018316Swollman } 75118316Swollman#endif 75246303Smarkm if (TRACEKERNEL) 75346303Smarkm trace_misc("write kernel" PAT, ARGS); 75446303Smarkm#undef PAT 75546303Smarkm#undef ARGS 75618316Swollman} 75718316Swollman 75818316Swollman 75918316Swollman#define KHASH_SIZE 71 /* should be prime */ 76018316Swollman#define KHASH(a,m) khash_bins[((a) ^ (m)) % KHASH_SIZE] 76118316Swollmanstatic struct khash { 76218316Swollman struct khash *k_next; 76318316Swollman naddr k_dst; 76418316Swollman naddr k_mask; 76518316Swollman naddr k_gate; 76618316Swollman short k_metric; 76718316Swollman u_short k_state; 76818316Swollman#define KS_NEW 0x001 76946303Smarkm#define KS_DELETE 0x002 /* need to delete the route */ 77018316Swollman#define KS_ADD 0x004 /* add to the kernel */ 77118316Swollman#define KS_CHANGE 0x008 /* tell kernel to change the route */ 77218316Swollman#define KS_DEL_ADD 0x010 /* delete & add to change the kernel */ 77318316Swollman#define KS_STATIC 0x020 /* Static flag in kernel */ 77418316Swollman#define KS_GATEWAY 0x040 /* G flag in kernel */ 77518316Swollman#define KS_DYNAMIC 0x080 /* result of redirect */ 77646303Smarkm#define KS_DELETED 0x100 /* already deleted from kernel */ 77746303Smarkm#define KS_CHECK 0x200 77818316Swollman time_t k_keep; 77918316Swollman#define K_KEEP_LIM 30 78020342Swollman time_t k_redirect_time; /* when redirected route 1st seen */ 78118316Swollman} *khash_bins[KHASH_SIZE]; 78218316Swollman 78318316Swollman 78418316Swollmanstatic struct khash* 78518316Swollmankern_find(naddr dst, naddr mask, struct khash ***ppk) 78618316Swollman{ 78718316Swollman struct khash *k, **pk; 78818316Swollman 78918316Swollman for (pk = &KHASH(dst,mask); (k = *pk) != 0; pk = &k->k_next) { 79018316Swollman if (k->k_dst == dst && k->k_mask == mask) 79118316Swollman break; 79218316Swollman } 79318316Swollman if (ppk != 0) 79418316Swollman *ppk = pk; 79518316Swollman return k; 79618316Swollman} 79718316Swollman 79818316Swollman 79918316Swollmanstatic struct khash* 80018316Swollmankern_add(naddr dst, naddr mask) 80118316Swollman{ 80218316Swollman struct khash *k, **pk; 80318316Swollman 80418316Swollman k = kern_find(dst, mask, &pk); 80518316Swollman if (k != 0) 80618316Swollman return k; 80718316Swollman 80837908Scharnier k = (struct khash *)rtmalloc(sizeof(*k), "kern_add"); 80918316Swollman 81046303Smarkm memset(k, 0, sizeof(*k)); 81118316Swollman k->k_dst = dst; 81218316Swollman k->k_mask = mask; 81318316Swollman k->k_state = KS_NEW; 81418316Swollman k->k_keep = now.tv_sec; 81518316Swollman *pk = k; 81618316Swollman 81718316Swollman return k; 81818316Swollman} 81918316Swollman 82018316Swollman 82118316Swollman/* If a kernel route has a non-zero metric, check that it is still in the 82218316Swollman * daemon table, and not deleted by interfaces coming and going. 82318316Swollman */ 82418316Swollmanstatic void 82518316Swollmankern_check_static(struct khash *k, 82618316Swollman struct interface *ifp) 82718316Swollman{ 82818316Swollman struct rt_entry *rt; 82946303Smarkm struct rt_spare new; 83018316Swollman 83118316Swollman if (k->k_metric == 0) 83218316Swollman return; 83318316Swollman 83446303Smarkm memset(&new, 0, sizeof(new)); 83546303Smarkm new.rts_ifp = ifp; 83646303Smarkm new.rts_gate = k->k_gate; 83746303Smarkm new.rts_router = (ifp != 0) ? ifp->int_addr : loopaddr; 83846303Smarkm new.rts_metric = k->k_metric; 83946303Smarkm new.rts_time = now.tv_sec; 84018316Swollman 84118316Swollman rt = rtget(k->k_dst, k->k_mask); 84218316Swollman if (rt != 0) { 84318316Swollman if (!(rt->rt_state & RS_STATIC)) 84446303Smarkm rtchange(rt, rt->rt_state | RS_STATIC, &new, 0); 84518316Swollman } else { 84646303Smarkm rtadd(k->k_dst, k->k_mask, RS_STATIC, &new); 84718316Swollman } 84818316Swollman} 84918316Swollman 85018316Swollman 85146303Smarkm/* operate on a kernel entry 85246303Smarkm */ 85346303Smarkmstatic void 85446303Smarkmkern_ioctl(struct khash *k, 85546303Smarkm int action, /* RTM_DELETE, etc */ 85646303Smarkm int flags) 85746303Smarkm 85846303Smarkm{ 85946303Smarkm switch (action) { 86046303Smarkm case RTM_DELETE: 86146303Smarkm k->k_state &= ~KS_DYNAMIC; 86246303Smarkm if (k->k_state & KS_DELETED) 86346303Smarkm return; 86446303Smarkm k->k_state |= KS_DELETED; 86546303Smarkm break; 86646303Smarkm case RTM_ADD: 86746303Smarkm k->k_state &= ~KS_DELETED; 86846303Smarkm break; 86946303Smarkm case RTM_CHANGE: 87046303Smarkm if (k->k_state & KS_DELETED) { 87146303Smarkm action = RTM_ADD; 87246303Smarkm k->k_state &= ~KS_DELETED; 87346303Smarkm } 87446303Smarkm break; 87546303Smarkm } 87646303Smarkm 87746303Smarkm rtioctl(action, k->k_dst, k->k_gate, k->k_mask, k->k_metric, flags); 87846303Smarkm} 87946303Smarkm 88046303Smarkm 88118316Swollman/* add a route the kernel told us 88218316Swollman */ 88318316Swollmanstatic void 88418316Swollmanrtm_add(struct rt_msghdr *rtm, 88518316Swollman struct rt_addrinfo *info, 88618316Swollman time_t keep) 88718316Swollman{ 88818316Swollman struct khash *k; 88918316Swollman struct interface *ifp; 89018316Swollman naddr mask; 89118316Swollman 89218316Swollman 89318316Swollman if (rtm->rtm_flags & RTF_HOST) { 89418316Swollman mask = HOST_MASK; 89518316Swollman } else if (INFO_MASK(info) != 0) { 89618316Swollman mask = ntohl(S_ADDR(INFO_MASK(info))); 89718316Swollman } else { 89820342Swollman msglog("ignore %s without mask", rtm_type_name(rtm->rtm_type)); 89918316Swollman return; 90018316Swollman } 90118316Swollman 90218316Swollman k = kern_add(S_ADDR(INFO_DST(info)), mask); 90318316Swollman if (k->k_state & KS_NEW) 90418316Swollman k->k_keep = now.tv_sec+keep; 90546303Smarkm if (INFO_GATE(info) == 0) { 90646303Smarkm trace_act("note %s without gateway", 90746303Smarkm rtm_type_name(rtm->rtm_type)); 90846303Smarkm k->k_metric = HOPCNT_INFINITY; 90946303Smarkm } else if (INFO_GATE(info)->sa_family != AF_INET) { 91046303Smarkm trace_act("note %s with gateway AF=%d", 91146303Smarkm rtm_type_name(rtm->rtm_type), 91246303Smarkm INFO_GATE(info)->sa_family); 91346303Smarkm k->k_metric = HOPCNT_INFINITY; 91446303Smarkm } else { 91546303Smarkm k->k_gate = S_ADDR(INFO_GATE(info)); 91646303Smarkm k->k_metric = rtm->rtm_rmx.rmx_hopcount; 91746303Smarkm if (k->k_metric < 0) 91846303Smarkm k->k_metric = 0; 91946303Smarkm else if (k->k_metric > HOPCNT_INFINITY-1) 92046303Smarkm k->k_metric = HOPCNT_INFINITY-1; 92146303Smarkm } 92246303Smarkm k->k_state &= ~(KS_DELETE | KS_ADD | KS_CHANGE | KS_DEL_ADD 92346303Smarkm | KS_DELETED | KS_GATEWAY | KS_STATIC 92446303Smarkm | KS_NEW | KS_CHECK); 92518316Swollman if (rtm->rtm_flags & RTF_GATEWAY) 92618316Swollman k->k_state |= KS_GATEWAY; 92718316Swollman if (rtm->rtm_flags & RTF_STATIC) 92818316Swollman k->k_state |= KS_STATIC; 92918316Swollman 93018316Swollman if (0 != (rtm->rtm_flags & (RTF_DYNAMIC | RTF_MODIFIED))) { 93120342Swollman if (INFO_AUTHOR(info) != 0 93220342Swollman && INFO_AUTHOR(info)->sa_family == AF_INET) 93320342Swollman ifp = iflookup(S_ADDR(INFO_AUTHOR(info))); 93420342Swollman else 93520342Swollman ifp = 0; 93620342Swollman if (supplier 93720342Swollman && (ifp == 0 || !(ifp->int_state & IS_REDIRECT_OK))) { 93818316Swollman /* Routers are not supposed to listen to redirects, 93920342Swollman * so delete it if it came via an unknown interface 94020342Swollman * or the interface does not have special permission. 94118316Swollman */ 94218316Swollman k->k_state &= ~KS_DYNAMIC; 94318316Swollman k->k_state |= KS_DELETE; 94418316Swollman LIM_SEC(need_kern, 0); 94520342Swollman trace_act("mark for deletion redirected %s --> %s" 94620342Swollman " via %s", 94718316Swollman addrname(k->k_dst, k->k_mask, 0), 94820342Swollman naddr_ntoa(k->k_gate), 94920342Swollman ifp ? ifp->int_name : "unknown interface"); 95018316Swollman } else { 95118316Swollman k->k_state |= KS_DYNAMIC; 95218316Swollman k->k_redirect_time = now.tv_sec; 95320342Swollman trace_act("accept redirected %s --> %s via %s", 95420342Swollman addrname(k->k_dst, k->k_mask, 0), 95520342Swollman naddr_ntoa(k->k_gate), 95620342Swollman ifp ? ifp->int_name : "unknown interface"); 95718316Swollman } 95818316Swollman return; 95918316Swollman } 96018316Swollman 96118316Swollman /* If it is not a static route, quit until the next comparison 96218316Swollman * between the kernel and daemon tables, when it will be deleted. 96318316Swollman */ 96418316Swollman if (!(k->k_state & KS_STATIC)) { 96518316Swollman k->k_state |= KS_DELETE; 96618316Swollman LIM_SEC(need_kern, k->k_keep); 96718316Swollman return; 96818316Swollman } 96918316Swollman 97018316Swollman /* Put static routes with real metrics into the daemon table so 97118316Swollman * they can be advertised. 97218316Swollman * 97319885Swollman * Find the interface toward the gateway. 97418316Swollman */ 97518316Swollman ifp = iflookup(k->k_gate); 97620342Swollman if (ifp == 0) 97720342Swollman msglog("static route %s --> %s impossibly lacks ifp", 97820342Swollman addrname(S_ADDR(INFO_DST(info)), mask, 0), 97920342Swollman naddr_ntoa(k->k_gate)); 98018316Swollman 98118316Swollman kern_check_static(k, ifp); 98218316Swollman} 98318316Swollman 98418316Swollman 98518316Swollman/* deal with packet loss 98618316Swollman */ 98718316Swollmanstatic void 98818316Swollmanrtm_lose(struct rt_msghdr *rtm, 98918316Swollman struct rt_addrinfo *info) 99018316Swollman{ 99118316Swollman if (INFO_GATE(info) == 0 99218316Swollman || INFO_GATE(info)->sa_family != AF_INET) { 99320342Swollman trace_act("ignore %s without gateway", 99420342Swollman rtm_type_name(rtm->rtm_type)); 99518316Swollman return; 99618316Swollman } 99718316Swollman 99846303Smarkm if (rdisc_ok) 99918316Swollman rdisc_age(S_ADDR(INFO_GATE(info))); 100018316Swollman age(S_ADDR(INFO_GATE(info))); 100118316Swollman} 100218316Swollman 100318316Swollman 100446303Smarkm/* Make the gateway slot of an info structure point to something 100546303Smarkm * useful. If it is not already useful, but it specifies an interface, 100646303Smarkm * then fill in the sockaddr_in provided and point it there. 100746303Smarkm */ 100846303Smarkmstatic int 100946303Smarkmget_info_gate(struct sockaddr **sap, 1010126250Sbms struct sockaddr_in *rsin) 101146303Smarkm{ 101246303Smarkm struct sockaddr_dl *sdl = (struct sockaddr_dl *)*sap; 101346303Smarkm struct interface *ifp; 101446303Smarkm 101546303Smarkm if (sdl == 0) 101646303Smarkm return 0; 101746303Smarkm if ((sdl)->sdl_family == AF_INET) 101846303Smarkm return 1; 101946303Smarkm if ((sdl)->sdl_family != AF_LINK) 102046303Smarkm return 0; 102146303Smarkm 102246303Smarkm ifp = ifwithindex(sdl->sdl_index, 1); 102346303Smarkm if (ifp == 0) 102446303Smarkm return 0; 102546303Smarkm 1026126250Sbms rsin->sin_addr.s_addr = ifp->int_addr; 102746303Smarkm#ifdef _HAVE_SA_LEN 1028126250Sbms rsin->sin_len = sizeof(*rsin); 102946303Smarkm#endif 1030126250Sbms rsin->sin_family = AF_INET; 1031126250Sbms *sap = (struct sockaddr*)rsin; 103246303Smarkm 103346303Smarkm return 1; 103446303Smarkm} 103546303Smarkm 103646303Smarkm 103718316Swollman/* Clean the kernel table by copying it to the daemon image. 103818316Swollman * Eventually the daemon will delete any extra routes. 103918316Swollman */ 104018316Swollmanvoid 104118316Swollmanflush_kern(void) 104218316Swollman{ 104346303Smarkm static char *sysctl_buf; 104446303Smarkm static size_t sysctl_buf_size = 0; 104518316Swollman size_t needed; 104618316Swollman int mib[6]; 104746303Smarkm char *next, *lim; 104818316Swollman struct rt_msghdr *rtm; 104946303Smarkm struct sockaddr_in gate_sin; 105018316Swollman struct rt_addrinfo info; 105146303Smarkm int i; 105246303Smarkm struct khash *k; 105318316Swollman 105418316Swollman 105546303Smarkm for (i = 0; i < KHASH_SIZE; i++) { 105646303Smarkm for (k = khash_bins[i]; k != 0; k = k->k_next) { 105746303Smarkm k->k_state |= KS_CHECK; 105846303Smarkm } 105946303Smarkm } 106046303Smarkm 106118316Swollman mib[0] = CTL_NET; 106218316Swollman mib[1] = PF_ROUTE; 106318316Swollman mib[2] = 0; /* protocol */ 106418316Swollman mib[3] = 0; /* wildcard address family */ 106518316Swollman mib[4] = NET_RT_DUMP; 106618316Swollman mib[5] = 0; /* no flags */ 106746303Smarkm for (;;) { 106846303Smarkm if ((needed = sysctl_buf_size) != 0) { 106946303Smarkm if (sysctl(mib, 6, sysctl_buf,&needed, 0, 0) >= 0) 107046303Smarkm break; 107146303Smarkm if (errno != ENOMEM && errno != EFAULT) 107246303Smarkm BADERR(1,"flush_kern: sysctl(RT_DUMP)"); 107346303Smarkm free(sysctl_buf); 107446303Smarkm needed = 0; 107546303Smarkm } 107646303Smarkm if (sysctl(mib, 6, 0, &needed, 0, 0) < 0) 107746303Smarkm BADERR(1,"flush_kern: sysctl(RT_DUMP) estimate"); 107846303Smarkm /* Kludge around the habit of some systems, such as 107946303Smarkm * BSD/OS 3.1, to not admit how many routes are in the 108046303Smarkm * kernel, or at least to be quite wrong. 108146303Smarkm */ 108246303Smarkm needed += 50*(sizeof(*rtm)+5*sizeof(struct sockaddr)); 108346303Smarkm sysctl_buf = rtmalloc(sysctl_buf_size = needed, 108446303Smarkm "flush_kern sysctl(RT_DUMP)"); 108518316Swollman } 108646303Smarkm 108746303Smarkm lim = sysctl_buf + needed; 108846303Smarkm for (next = sysctl_buf; next < lim; next += rtm->rtm_msglen) { 108918316Swollman rtm = (struct rt_msghdr *)next; 109046303Smarkm if (rtm->rtm_msglen == 0) { 109146303Smarkm msglog("zero length kernel route at " 109246303Smarkm " %#lx in buffer %#lx before %#lx", 109346303Smarkm (u_long)rtm, (u_long)sysctl_buf, (u_long)lim); 109446303Smarkm break; 109546303Smarkm } 109618316Swollman 109718316Swollman rt_xaddrs(&info, 109818316Swollman (struct sockaddr *)(rtm+1), 109918316Swollman (struct sockaddr *)(next + rtm->rtm_msglen), 110018316Swollman rtm->rtm_addrs); 110118316Swollman 110218316Swollman if (INFO_DST(&info) == 0 110318316Swollman || INFO_DST(&info)->sa_family != AF_INET) 110418316Swollman continue; 110518316Swollman 1106186119Sqingli#if defined (RTF_LLINFO) 110718316Swollman /* ignore ARP table entries on systems with a merged route 110818316Swollman * and ARP table. 110918316Swollman */ 111018316Swollman if (rtm->rtm_flags & RTF_LLINFO) 111118316Swollman continue; 1112186119Sqingli#endif 1113130498Sbms#if defined(RTF_WASCLONED) && defined(__FreeBSD__) 1114126250Sbms /* ignore cloned routes 1115126250Sbms */ 1116130498Sbms if (rtm->rtm_flags & RTF_WASCLONED) 1117126250Sbms continue; 1118126250Sbms#endif 1119126250Sbms 112018316Swollman /* ignore multicast addresses 112118316Swollman */ 112218316Swollman if (IN_MULTICAST(ntohl(S_ADDR(INFO_DST(&info))))) 112318316Swollman continue; 112418316Swollman 112546303Smarkm if (!get_info_gate(&INFO_GATE(&info), &gate_sin)) 112646303Smarkm continue; 112746303Smarkm 112818316Swollman /* Note static routes and interface routes, and also 112918316Swollman * preload the image of the kernel table so that 113018316Swollman * we can later clean it, as well as avoid making 113118316Swollman * unneeded changes. Keep the old kernel routes for a 113218316Swollman * few seconds to allow a RIP or router-discovery 113318316Swollman * response to be heard. 113418316Swollman */ 113518316Swollman rtm_add(rtm,&info,MIN_WAITTIME); 113618316Swollman } 113746303Smarkm 113846303Smarkm for (i = 0; i < KHASH_SIZE; i++) { 113946303Smarkm for (k = khash_bins[i]; k != 0; k = k->k_next) { 114046303Smarkm if (k->k_state & KS_CHECK) { 114146303Smarkm msglog("%s --> %s disappeared from kernel", 114246303Smarkm addrname(k->k_dst, k->k_mask, 0), 114346303Smarkm naddr_ntoa(k->k_gate)); 114446303Smarkm del_static(k->k_dst, k->k_mask, k->k_gate, 1); 114546303Smarkm } 114646303Smarkm } 114746303Smarkm } 114818316Swollman} 114918316Swollman 115018316Swollman 115118316Swollman/* Listen to announcements from the kernel 115218316Swollman */ 115318316Swollmanvoid 115418316Swollmanread_rt(void) 115518316Swollman{ 115618316Swollman long cc; 115718316Swollman struct interface *ifp; 115846303Smarkm struct sockaddr_in gate_sin; 115946303Smarkm naddr mask, gate; 116018316Swollman union { 116118316Swollman struct { 116218316Swollman struct rt_msghdr rtm; 116318316Swollman struct sockaddr addrs[RTAX_MAX]; 116418316Swollman } r; 116518316Swollman struct if_msghdr ifm; 116618316Swollman } m; 116718316Swollman char str[100], *strp; 116818316Swollman struct rt_addrinfo info; 116918316Swollman 117018316Swollman 117118316Swollman for (;;) { 117218316Swollman cc = read(rt_sock, &m, sizeof(m)); 117318316Swollman if (cc <= 0) { 117418316Swollman if (cc < 0 && errno != EWOULDBLOCK) 117518316Swollman LOGERR("read(rt_sock)"); 117618316Swollman return; 117718316Swollman } 117818316Swollman 117918316Swollman if (m.r.rtm.rtm_version != RTM_VERSION) { 118018316Swollman msglog("bogus routing message version %d", 118118316Swollman m.r.rtm.rtm_version); 118218316Swollman continue; 118318316Swollman } 118418316Swollman 118518316Swollman /* Ignore our own results. 118618316Swollman */ 118718316Swollman if (m.r.rtm.rtm_type <= RTM_CHANGE 118818316Swollman && m.r.rtm.rtm_pid == mypid) { 118918316Swollman static int complained = 0; 119018316Swollman if (!complained) { 119118316Swollman msglog("receiving our own change messages"); 119218316Swollman complained = 1; 119318316Swollman } 119418316Swollman continue; 119518316Swollman } 119618316Swollman 119718316Swollman if (m.r.rtm.rtm_type == RTM_IFINFO 119818316Swollman || m.r.rtm.rtm_type == RTM_NEWADDR 119918316Swollman || m.r.rtm.rtm_type == RTM_DELADDR) { 120046303Smarkm ifp = ifwithindex(m.ifm.ifm_index, 120146303Smarkm m.r.rtm.rtm_type != RTM_DELADDR); 120218316Swollman if (ifp == 0) 120318316Swollman trace_act("note %s with flags %#x" 120446303Smarkm " for unknown interface index #%d", 120518316Swollman rtm_type_name(m.r.rtm.rtm_type), 120618316Swollman m.ifm.ifm_flags, 120718316Swollman m.ifm.ifm_index); 120818316Swollman else 120919885Swollman trace_act("note %s with flags %#x for %s", 121018316Swollman rtm_type_name(m.r.rtm.rtm_type), 121118316Swollman m.ifm.ifm_flags, 121218316Swollman ifp->int_name); 121318316Swollman 121418316Swollman /* After being informed of a change to an interface, 121518316Swollman * check them all now if the check would otherwise 121618316Swollman * be a long time from now, if the interface is 121718316Swollman * not known, or if the interface has been turned 121818316Swollman * off or on. 121918316Swollman */ 122018316Swollman if (ifinit_timer.tv_sec-now.tv_sec>=CHECK_BAD_INTERVAL 122118316Swollman || ifp == 0 122218316Swollman || ((ifp->int_if_flags ^ m.ifm.ifm_flags) 122346303Smarkm & IFF_UP) != 0) 122418316Swollman ifinit_timer.tv_sec = now.tv_sec; 122518316Swollman continue; 122618316Swollman } 1227126250Sbms#ifdef RTM_OIFINFO 1228126250Sbms if (m.r.rtm.rtm_type == RTM_OIFINFO) 1229126250Sbms continue; /* ignore compat message */ 1230126250Sbms#endif 123118316Swollman 123218316Swollman strcpy(str, rtm_type_name(m.r.rtm.rtm_type)); 123318316Swollman strp = &str[strlen(str)]; 123418316Swollman if (m.r.rtm.rtm_type <= RTM_CHANGE) 123518316Swollman strp += sprintf(strp," from pid %d",m.r.rtm.rtm_pid); 123618316Swollman 123718316Swollman rt_xaddrs(&info, m.r.addrs, &m.r.addrs[RTAX_MAX], 123818316Swollman m.r.rtm.rtm_addrs); 123918316Swollman 124018316Swollman if (INFO_DST(&info) == 0) { 124119885Swollman trace_act("ignore %s without dst", str); 124218316Swollman continue; 124318316Swollman } 124418316Swollman 124518316Swollman if (INFO_DST(&info)->sa_family != AF_INET) { 124619885Swollman trace_act("ignore %s for AF %d", str, 124718316Swollman INFO_DST(&info)->sa_family); 124818316Swollman continue; 124918316Swollman } 125018316Swollman 125118316Swollman mask = ((INFO_MASK(&info) != 0) 125218316Swollman ? ntohl(S_ADDR(INFO_MASK(&info))) 125318316Swollman : (m.r.rtm.rtm_flags & RTF_HOST) 125418316Swollman ? HOST_MASK 125518316Swollman : std_mask(S_ADDR(INFO_DST(&info)))); 125618316Swollman 125718316Swollman strp += sprintf(strp, ": %s", 125818316Swollman addrname(S_ADDR(INFO_DST(&info)), mask, 0)); 125918316Swollman 126018316Swollman if (IN_MULTICAST(ntohl(S_ADDR(INFO_DST(&info))))) { 126119885Swollman trace_act("ignore multicast %s", str); 126218316Swollman continue; 126318316Swollman } 126418316Swollman 1265186119Sqingli#if defined(RTF_LLINFO) 126646303Smarkm if (m.r.rtm.rtm_flags & RTF_LLINFO) { 126746303Smarkm trace_act("ignore ARP %s", str); 126846303Smarkm continue; 126946303Smarkm } 1270186119Sqingli#endif 1271186119Sqingli 1272130498Sbms#if defined(RTF_WASCLONED) && defined(__FreeBSD__) 1273130498Sbms if (m.r.rtm.rtm_flags & RTF_WASCLONED) { 1274126250Sbms trace_act("ignore cloned %s", str); 1275126250Sbms continue; 1276126250Sbms } 1277126250Sbms#endif 1278126250Sbms 127946303Smarkm if (get_info_gate(&INFO_GATE(&info), &gate_sin)) { 128046303Smarkm gate = S_ADDR(INFO_GATE(&info)); 128146303Smarkm strp += sprintf(strp, " --> %s", naddr_ntoa(gate)); 128246303Smarkm } else { 128346303Smarkm gate = 0; 128446303Smarkm } 128546303Smarkm 128618316Swollman if (INFO_AUTHOR(&info) != 0) 128718316Swollman strp += sprintf(strp, " by authority of %s", 128818316Swollman saddr_ntoa(INFO_AUTHOR(&info))); 128918316Swollman 129018316Swollman switch (m.r.rtm.rtm_type) { 129118316Swollman case RTM_ADD: 129218316Swollman case RTM_CHANGE: 129318316Swollman case RTM_REDIRECT: 129418316Swollman if (m.r.rtm.rtm_errno != 0) { 129519885Swollman trace_act("ignore %s with \"%s\" error", 129618316Swollman str, strerror(m.r.rtm.rtm_errno)); 129718316Swollman } else { 129819885Swollman trace_act("%s", str); 129918316Swollman rtm_add(&m.r.rtm,&info,0); 130018316Swollman } 130118316Swollman break; 130218316Swollman 130318316Swollman case RTM_DELETE: 130446303Smarkm if (m.r.rtm.rtm_errno != 0 130546303Smarkm && m.r.rtm.rtm_errno != ESRCH) { 130619885Swollman trace_act("ignore %s with \"%s\" error", 130718316Swollman str, strerror(m.r.rtm.rtm_errno)); 130818316Swollman } else { 130919885Swollman trace_act("%s", str); 131046303Smarkm del_static(S_ADDR(INFO_DST(&info)), mask, 131146303Smarkm gate, 1); 131218316Swollman } 131318316Swollman break; 131418316Swollman 131518316Swollman case RTM_LOSING: 131619885Swollman trace_act("%s", str); 131718316Swollman rtm_lose(&m.r.rtm,&info); 131818316Swollman break; 131918316Swollman 132018316Swollman default: 132119885Swollman trace_act("ignore %s", str); 132218316Swollman break; 132318316Swollman } 132418316Swollman } 132518316Swollman} 132618316Swollman 132718316Swollman 132818316Swollman/* after aggregating, note routes that belong in the kernel 132918316Swollman */ 133018316Swollmanstatic void 133118316Swollmankern_out(struct ag_info *ag) 133218316Swollman{ 133318316Swollman struct khash *k; 133418316Swollman 133518316Swollman 133618316Swollman /* Do not install bad routes if they are not already present. 133718316Swollman * This includes routes that had RS_NET_SYN for interfaces that 133818316Swollman * recently died. 133918316Swollman */ 134018316Swollman if (ag->ag_metric == HOPCNT_INFINITY) { 134118316Swollman k = kern_find(htonl(ag->ag_dst_h), ag->ag_mask, 0); 134218316Swollman if (k == 0) 134318316Swollman return; 134418316Swollman } else { 134518316Swollman k = kern_add(htonl(ag->ag_dst_h), ag->ag_mask); 134618316Swollman } 134718316Swollman 134818316Swollman if (k->k_state & KS_NEW) { 134918316Swollman /* will need to add new entry to the kernel table */ 135018316Swollman k->k_state = KS_ADD; 135118316Swollman if (ag->ag_state & AGS_GATEWAY) 135218316Swollman k->k_state |= KS_GATEWAY; 135318316Swollman k->k_gate = ag->ag_gate; 135418316Swollman k->k_metric = ag->ag_metric; 135518316Swollman return; 135618316Swollman } 135718316Swollman 135818316Swollman if (k->k_state & KS_STATIC) 135918316Swollman return; 136018316Swollman 136118316Swollman /* modify existing kernel entry if necessary */ 136218316Swollman if (k->k_gate != ag->ag_gate 136318316Swollman || k->k_metric != ag->ag_metric) { 136446303Smarkm /* Must delete bad interface routes etc. to change them. */ 136546303Smarkm if (k->k_metric == HOPCNT_INFINITY) 136646303Smarkm k->k_state |= KS_DEL_ADD; 136718316Swollman k->k_gate = ag->ag_gate; 136818316Swollman k->k_metric = ag->ag_metric; 136918316Swollman k->k_state |= KS_CHANGE; 137018316Swollman } 137118316Swollman 137246303Smarkm /* If the daemon thinks the route should exist, forget 137346303Smarkm * about any redirections. 137446303Smarkm * If the daemon thinks the route should exist, eventually 137546303Smarkm * override manual intervention by the operator. 137646303Smarkm */ 137746303Smarkm if ((k->k_state & (KS_DYNAMIC | KS_DELETED)) != 0) { 137818316Swollman k->k_state &= ~KS_DYNAMIC; 137918316Swollman k->k_state |= (KS_ADD | KS_DEL_ADD); 138018316Swollman } 138118316Swollman 138218316Swollman if ((k->k_state & KS_GATEWAY) 138318316Swollman && !(ag->ag_state & AGS_GATEWAY)) { 138418316Swollman k->k_state &= ~KS_GATEWAY; 138518316Swollman k->k_state |= (KS_ADD | KS_DEL_ADD); 138618316Swollman } else if (!(k->k_state & KS_GATEWAY) 138718316Swollman && (ag->ag_state & AGS_GATEWAY)) { 138818316Swollman k->k_state |= KS_GATEWAY; 138918316Swollman k->k_state |= (KS_ADD | KS_DEL_ADD); 139018316Swollman } 139118316Swollman 139218316Swollman /* Deleting-and-adding is necessary to change aspects of a route. 139318316Swollman * Just delete instead of deleting and then adding a bad route. 139418316Swollman * Otherwise, we want to keep the route in the kernel. 139518316Swollman */ 139618316Swollman if (k->k_metric == HOPCNT_INFINITY 139718316Swollman && (k->k_state & KS_DEL_ADD)) 139818316Swollman k->k_state |= KS_DELETE; 139918316Swollman else 140018316Swollman k->k_state &= ~KS_DELETE; 140118316Swollman#undef RT 140218316Swollman} 140318316Swollman 140418316Swollman 140518316Swollman/* ARGSUSED */ 140618316Swollmanstatic int 140718316Swollmanwalk_kern(struct radix_node *rn, 140846303Smarkm struct walkarg *argp UNUSED) 140918316Swollman{ 141018316Swollman#define RT ((struct rt_entry *)rn) 141118316Swollman char metric, pref; 141218316Swollman u_int ags = 0; 141318316Swollman 141418316Swollman 141518316Swollman /* Do not install synthetic routes */ 141618316Swollman if (RT->rt_state & RS_NET_SYN) 141718316Swollman return 0; 141818316Swollman 141918316Swollman if (!(RT->rt_state & RS_IF)) { 142046303Smarkm /* This is an ordinary route, not for an interface. 142146303Smarkm */ 142218316Swollman 142346303Smarkm /* aggregate, ordinary good routes without regard to 142446303Smarkm * their metric 142546303Smarkm */ 142646303Smarkm pref = 1; 142746303Smarkm ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_AGGREGATE); 142846303Smarkm 142946303Smarkm /* Do not install host routes directly to hosts, to avoid 143046303Smarkm * interfering with ARP entries in the kernel table. 143146303Smarkm */ 143246303Smarkm if (RT_ISHOST(RT) 143346303Smarkm && ntohl(RT->rt_dst) == RT->rt_gate) 143446303Smarkm return 0; 143546303Smarkm 143618316Swollman } else { 143746303Smarkm /* This is an interface route. 143846303Smarkm * Do not install routes for "external" remote interfaces. 143918316Swollman */ 144018316Swollman if (RT->rt_ifp != 0 && (RT->rt_ifp->int_state & IS_EXTERNAL)) 144118316Swollman return 0; 144218316Swollman 144346303Smarkm /* Interfaces should override received routes. 144446303Smarkm */ 144546303Smarkm pref = 0; 144646303Smarkm ags |= (AGS_IF | AGS_CORS_GATE); 144718316Swollman 144818316Swollman /* If it is not an interface, or an alias for an interface, 144918316Swollman * it must be a "gateway." 145018316Swollman * 145118316Swollman * If it is a "remote" interface, it is also a "gateway" to 1452108533Sschweikh * the kernel if is not an alias. 145318316Swollman */ 145418316Swollman if (RT->rt_ifp == 0 145519885Swollman || (RT->rt_ifp->int_state & IS_REMOTE)) 145646303Smarkm ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_AGGREGATE); 145718316Swollman } 145818316Swollman 145946303Smarkm /* If RIP is off and IRDP is on, let the route to the discovered 146046303Smarkm * route suppress any RIP routes. Eventually the RIP routes 146146303Smarkm * will time-out and be deleted. This reaches the steady-state 146246303Smarkm * quicker. 146346303Smarkm */ 146446303Smarkm if ((RT->rt_state & RS_RDISC) && rip_sock < 0) 146518316Swollman ags |= AGS_CORS_GATE; 146618316Swollman 146718316Swollman metric = RT->rt_metric; 146818316Swollman if (metric == HOPCNT_INFINITY) { 146918316Swollman /* if the route is dead, so try hard to aggregate. */ 147018316Swollman pref = HOPCNT_INFINITY; 147118316Swollman ags |= (AGS_FINE_GATE | AGS_SUPPRESS); 147246303Smarkm ags &= ~(AGS_IF | AGS_CORS_GATE); 147318316Swollman } 147418316Swollman 147518316Swollman ag_check(RT->rt_dst, RT->rt_mask, RT->rt_gate, 0, 147618316Swollman metric,pref, 0, 0, ags, kern_out); 147718316Swollman return 0; 147818316Swollman#undef RT 147918316Swollman} 148018316Swollman 148118316Swollman 148218316Swollman/* Update the kernel table to match the daemon table. 148318316Swollman */ 148418316Swollmanstatic void 148518316Swollmanfix_kern(void) 148618316Swollman{ 148746303Smarkm int i; 148818316Swollman struct khash *k, **pk; 148918316Swollman 149018316Swollman 149118316Swollman need_kern = age_timer; 149218316Swollman 149318316Swollman /* Walk daemon table, updating the copy of the kernel table. 149418316Swollman */ 149518316Swollman (void)rn_walktree(rhead, walk_kern, 0); 149618316Swollman ag_flush(0,0,kern_out); 149718316Swollman 149818316Swollman for (i = 0; i < KHASH_SIZE; i++) { 149918316Swollman for (pk = &khash_bins[i]; (k = *pk) != 0; ) { 150018316Swollman /* Do not touch static routes */ 150118316Swollman if (k->k_state & KS_STATIC) { 150218316Swollman kern_check_static(k,0); 150318316Swollman pk = &k->k_next; 150418316Swollman continue; 150518316Swollman } 150618316Swollman 150718316Swollman /* check hold on routes deleted by the operator */ 150818316Swollman if (k->k_keep > now.tv_sec) { 150946303Smarkm /* ensure we check when the hold is over */ 151018316Swollman LIM_SEC(need_kern, k->k_keep); 151146303Smarkm /* mark for the next cycle */ 151218316Swollman k->k_state |= KS_DELETE; 151318316Swollman pk = &k->k_next; 151418316Swollman continue; 151518316Swollman } 151618316Swollman 151746303Smarkm if ((k->k_state & KS_DELETE) 151846303Smarkm && !(k->k_state & KS_DYNAMIC)) { 151946303Smarkm kern_ioctl(k, RTM_DELETE, 0); 152018316Swollman *pk = k->k_next; 152118316Swollman free(k); 152218316Swollman continue; 152318316Swollman } 152418316Swollman 152546303Smarkm if (k->k_state & KS_DEL_ADD) 152646303Smarkm kern_ioctl(k, RTM_DELETE, 0); 152718316Swollman 152846303Smarkm if (k->k_state & KS_ADD) { 152946303Smarkm kern_ioctl(k, RTM_ADD, 153046303Smarkm ((0 != (k->k_state & (KS_GATEWAY 153146303Smarkm | KS_DYNAMIC))) 153246303Smarkm ? RTF_GATEWAY : 0)); 153346303Smarkm } else if (k->k_state & KS_CHANGE) { 153446303Smarkm kern_ioctl(k, RTM_CHANGE, 153546303Smarkm ((0 != (k->k_state & (KS_GATEWAY 153646303Smarkm | KS_DYNAMIC))) 153746303Smarkm ? RTF_GATEWAY : 0)); 153818316Swollman } 153946303Smarkm k->k_state &= ~(KS_ADD|KS_CHANGE|KS_DEL_ADD); 154018316Swollman 154118316Swollman /* Mark this route to be deleted in the next cycle. 154218316Swollman * This deletes routes that disappear from the 154318316Swollman * daemon table, since the normal aging code 154418316Swollman * will clear the bit for routes that have not 154518316Swollman * disappeared from the daemon table. 154618316Swollman */ 154718316Swollman k->k_state |= KS_DELETE; 154818316Swollman pk = &k->k_next; 154918316Swollman } 155018316Swollman } 155118316Swollman} 155218316Swollman 155318316Swollman 155418316Swollman/* Delete a static route in the image of the kernel table. 155518316Swollman */ 155618316Swollmanvoid 155718316Swollmandel_static(naddr dst, 155818316Swollman naddr mask, 155946303Smarkm naddr gate, 156018316Swollman int gone) 156118316Swollman{ 156218316Swollman struct khash *k; 156318316Swollman struct rt_entry *rt; 156418316Swollman 156518316Swollman /* Just mark it in the table to be deleted next time the kernel 156618316Swollman * table is updated. 156718316Swollman * If it has already been deleted, mark it as such, and set its 156818316Swollman * keep-timer so that it will not be deleted again for a while. 156918316Swollman * This lets the operator delete a route added by the daemon 157018316Swollman * and add a replacement. 157118316Swollman */ 157218316Swollman k = kern_find(dst, mask, 0); 157346303Smarkm if (k != 0 && (gate == 0 || k->k_gate == gate)) { 157446303Smarkm k->k_state &= ~(KS_STATIC | KS_DYNAMIC | KS_CHECK); 157518316Swollman k->k_state |= KS_DELETE; 157618316Swollman if (gone) { 157718316Swollman k->k_state |= KS_DELETED; 157818316Swollman k->k_keep = now.tv_sec + K_KEEP_LIM; 157918316Swollman } 158018316Swollman } 158118316Swollman 158218316Swollman rt = rtget(dst, mask); 158318316Swollman if (rt != 0 && (rt->rt_state & RS_STATIC)) 158418316Swollman rtbad(rt); 158518316Swollman} 158618316Swollman 158718316Swollman 158818316Swollman/* Delete all routes generated from ICMP Redirects that use a given gateway, 158918316Swollman * as well as old redirected routes. 159018316Swollman */ 159118316Swollmanvoid 159218316Swollmandel_redirects(naddr bad_gate, 159318316Swollman time_t old) 159418316Swollman{ 159518316Swollman int i; 159618316Swollman struct khash *k; 159718316Swollman 159818316Swollman 159918316Swollman for (i = 0; i < KHASH_SIZE; i++) { 160018316Swollman for (k = khash_bins[i]; k != 0; k = k->k_next) { 160118316Swollman if (!(k->k_state & KS_DYNAMIC) 160218316Swollman || (k->k_state & KS_STATIC)) 160318316Swollman continue; 160418316Swollman 160518316Swollman if (k->k_gate != bad_gate 160618316Swollman && k->k_redirect_time > old 160718316Swollman && !supplier) 160818316Swollman continue; 160918316Swollman 161018316Swollman k->k_state |= KS_DELETE; 161118316Swollman k->k_state &= ~KS_DYNAMIC; 161218316Swollman need_kern.tv_sec = now.tv_sec; 161319885Swollman trace_act("mark redirected %s --> %s for deletion", 161418316Swollman addrname(k->k_dst, k->k_mask, 0), 161518316Swollman naddr_ntoa(k->k_gate)); 161618316Swollman } 161718316Swollman } 161818316Swollman} 161918316Swollman 162018316Swollman 162118316Swollman/* Start the daemon tables. 162218316Swollman */ 162346303Smarkmextern int max_keylen; 162446303Smarkm 162518316Swollmanvoid 162618316Swollmanrtinit(void) 162718316Swollman{ 162818316Swollman int i; 162918316Swollman struct ag_info *ag; 163018316Swollman 163118316Swollman /* Initialize the radix trees */ 163218316Swollman max_keylen = sizeof(struct sockaddr_in); 163318316Swollman rn_init(); 163418316Swollman rn_inithead((void**)&rhead, 32); 163518316Swollman 163618316Swollman /* mark all of the slots in the table free */ 163718316Swollman ag_avail = ag_slots; 163818316Swollman for (ag = ag_slots, i = 1; i < NUM_AG_SLOTS; i++) { 163918316Swollman ag->ag_fine = ag+1; 164018316Swollman ag++; 164118316Swollman } 164218316Swollman} 164318316Swollman 164418316Swollman 164518316Swollman#ifdef _HAVE_SIN_LEN 164664131Ssheldonhstatic struct sockaddr_in dst_sock = {sizeof(dst_sock), AF_INET, 0, {0}, {0}}; 164764131Ssheldonhstatic struct sockaddr_in mask_sock = {sizeof(mask_sock), AF_INET, 0, {0}, {0}}; 164818316Swollman#else 164918316Swollmanstatic struct sockaddr_in_new dst_sock = {_SIN_ADDR_SIZE, AF_INET}; 165018316Swollmanstatic struct sockaddr_in_new mask_sock = {_SIN_ADDR_SIZE, AF_INET}; 165118316Swollman#endif 165218316Swollman 165318316Swollman 165446303Smarkmstatic void 165518316Swollmanset_need_flash(void) 165618316Swollman{ 165718316Swollman if (!need_flash) { 165818316Swollman need_flash = 1; 165918316Swollman /* Do not send the flash update immediately. Wait a little 166018316Swollman * while to hear from other routers. 166118316Swollman */ 166218316Swollman no_flash.tv_sec = now.tv_sec + MIN_WAITTIME; 166318316Swollman } 166418316Swollman} 166518316Swollman 166618316Swollman 166718316Swollman/* Get a particular routing table entry 166818316Swollman */ 166918316Swollmanstruct rt_entry * 167018316Swollmanrtget(naddr dst, naddr mask) 167118316Swollman{ 167218316Swollman struct rt_entry *rt; 167318316Swollman 167418316Swollman dst_sock.sin_addr.s_addr = dst; 167564131Ssheldonh mask_sock.sin_addr.s_addr = htonl(mask); 167618316Swollman masktrim(&mask_sock); 167718316Swollman rt = (struct rt_entry *)rhead->rnh_lookup(&dst_sock,&mask_sock,rhead); 167818316Swollman if (!rt 167918316Swollman || rt->rt_dst != dst 168018316Swollman || rt->rt_mask != mask) 168118316Swollman return 0; 168218316Swollman 168318316Swollman return rt; 168418316Swollman} 168518316Swollman 168618316Swollman 168718316Swollman/* Find a route to dst as the kernel would. 168818316Swollman */ 168918316Swollmanstruct rt_entry * 169018316Swollmanrtfind(naddr dst) 169118316Swollman{ 169218316Swollman dst_sock.sin_addr.s_addr = dst; 169318316Swollman return (struct rt_entry *)rhead->rnh_matchaddr(&dst_sock, rhead); 169418316Swollman} 169518316Swollman 169618316Swollman 169718316Swollman/* add a route to the table 169818316Swollman */ 169918316Swollmanvoid 170018316Swollmanrtadd(naddr dst, 170118316Swollman naddr mask, 170246303Smarkm u_int state, /* rt_state for the entry */ 170346303Smarkm struct rt_spare *new) 170418316Swollman{ 170518316Swollman struct rt_entry *rt; 170618316Swollman naddr smask; 170718316Swollman int i; 170818316Swollman struct rt_spare *rts; 170918316Swollman 171018316Swollman rt = (struct rt_entry *)rtmalloc(sizeof (*rt), "rtadd"); 171146303Smarkm memset(rt, 0, sizeof(*rt)); 171218316Swollman for (rts = rt->rt_spares, i = NUM_SPARES; i != 0; i--, rts++) 171318316Swollman rts->rts_metric = HOPCNT_INFINITY; 171418316Swollman 171518316Swollman rt->rt_nodes->rn_key = (caddr_t)&rt->rt_dst_sock; 171618316Swollman rt->rt_dst = dst; 171718316Swollman rt->rt_dst_sock.sin_family = AF_INET; 171818316Swollman#ifdef _HAVE_SIN_LEN 171918316Swollman rt->rt_dst_sock.sin_len = dst_sock.sin_len; 172018316Swollman#endif 172118316Swollman if (mask != HOST_MASK) { 172218316Swollman smask = std_mask(dst); 172318316Swollman if ((smask & ~mask) == 0 && mask > smask) 172418316Swollman state |= RS_SUBNET; 172518316Swollman } 172664131Ssheldonh mask_sock.sin_addr.s_addr = htonl(mask); 172718316Swollman masktrim(&mask_sock); 172818316Swollman rt->rt_mask = mask; 172918316Swollman rt->rt_state = state; 173046303Smarkm rt->rt_spares[0] = *new; 173118316Swollman rt->rt_time = now.tv_sec; 173218316Swollman rt->rt_poison_metric = HOPCNT_INFINITY; 173318316Swollman rt->rt_seqno = update_seqno; 173418316Swollman 173518316Swollman if (++total_routes == MAX_ROUTES) 173618316Swollman msglog("have maximum (%d) routes", total_routes); 173718316Swollman if (TRACEACTIONS) 173818316Swollman trace_add_del("Add", rt); 173918316Swollman 174018316Swollman need_kern.tv_sec = now.tv_sec; 174118316Swollman set_need_flash(); 174218316Swollman 174318316Swollman if (0 == rhead->rnh_addaddr(&rt->rt_dst_sock, &mask_sock, 174418316Swollman rhead, rt->rt_nodes)) { 174546303Smarkm msglog("rnh_addaddr() failed for %s mask=%#lx", 174646303Smarkm naddr_ntoa(dst), (u_long)mask); 174761186Sjlemon free(rt); 174818316Swollman } 174918316Swollman} 175018316Swollman 175118316Swollman 175218316Swollman/* notice a changed route 175318316Swollman */ 175418316Swollmanvoid 175518316Swollmanrtchange(struct rt_entry *rt, 175618316Swollman u_int state, /* new state bits */ 175746303Smarkm struct rt_spare *new, 175818316Swollman char *label) 175918316Swollman{ 176046303Smarkm if (rt->rt_metric != new->rts_metric) { 176118316Swollman /* Fix the kernel immediately if it seems the route 176218316Swollman * has gone bad, since there may be a working route that 176318316Swollman * aggregates this route. 176418316Swollman */ 176546303Smarkm if (new->rts_metric == HOPCNT_INFINITY) { 176618316Swollman need_kern.tv_sec = now.tv_sec; 176746303Smarkm if (new->rts_time >= now.tv_sec - EXPIRE_TIME) 176846303Smarkm new->rts_time = now.tv_sec - EXPIRE_TIME; 176918316Swollman } 177018316Swollman rt->rt_seqno = update_seqno; 177118316Swollman set_need_flash(); 177218316Swollman } 177318316Swollman 177446303Smarkm if (rt->rt_gate != new->rts_gate) { 177518316Swollman need_kern.tv_sec = now.tv_sec; 177618316Swollman rt->rt_seqno = update_seqno; 177718316Swollman set_need_flash(); 177818316Swollman } 177918316Swollman 178018316Swollman state |= (rt->rt_state & RS_SUBNET); 178118316Swollman 178218316Swollman /* Keep various things from deciding ageless routes are stale. 178318316Swollman */ 178446303Smarkm if (!AGE_RT(state, new->rts_ifp)) 178546303Smarkm new->rts_time = now.tv_sec; 178618316Swollman 178718316Swollman if (TRACEACTIONS) 178846303Smarkm trace_change(rt, state, new, 178918316Swollman label ? label : "Chg "); 179018316Swollman 179118316Swollman rt->rt_state = state; 179246303Smarkm rt->rt_spares[0] = *new; 179318316Swollman} 179418316Swollman 179518316Swollman 179618316Swollman/* check for a better route among the spares 179718316Swollman */ 179818316Swollmanstatic struct rt_spare * 179918316Swollmanrts_better(struct rt_entry *rt) 180018316Swollman{ 180118316Swollman struct rt_spare *rts, *rts1; 180218316Swollman int i; 180318316Swollman 180418316Swollman /* find the best alternative among the spares */ 180518316Swollman rts = rt->rt_spares+1; 180618316Swollman for (i = NUM_SPARES, rts1 = rts+1; i > 2; i--, rts1++) { 180718316Swollman if (BETTER_LINK(rt,rts1,rts)) 180818316Swollman rts = rts1; 180918316Swollman } 181018316Swollman 181118316Swollman return rts; 181218316Swollman} 181318316Swollman 181418316Swollman 181518316Swollman/* switch to a backup route 181618316Swollman */ 181718316Swollmanvoid 181818316Swollmanrtswitch(struct rt_entry *rt, 181918316Swollman struct rt_spare *rts) 182018316Swollman{ 182118316Swollman struct rt_spare swap; 182218316Swollman char label[10]; 182318316Swollman 182418316Swollman 182518316Swollman /* Do not change permanent routes */ 182618316Swollman if (0 != (rt->rt_state & (RS_MHOME | RS_STATIC | RS_RDISC 182718316Swollman | RS_NET_SYN | RS_IF))) 182818316Swollman return; 182918316Swollman 183018316Swollman /* find the best alternative among the spares */ 183118316Swollman if (rts == 0) 183218316Swollman rts = rts_better(rt); 183318316Swollman 183418316Swollman /* Do not bother if it is not worthwhile. 183518316Swollman */ 183618316Swollman if (!BETTER_LINK(rt, rts, rt->rt_spares)) 183718316Swollman return; 183818316Swollman 183918316Swollman swap = rt->rt_spares[0]; 184046303Smarkm (void)sprintf(label, "Use #%d", (int)(rts - rt->rt_spares)); 184146303Smarkm rtchange(rt, rt->rt_state & ~(RS_NET_SYN | RS_RDISC), rts, label); 184246303Smarkm if (swap.rts_metric == HOPCNT_INFINITY) { 184346303Smarkm *rts = rts_empty; 184446303Smarkm } else { 184546303Smarkm *rts = swap; 184646303Smarkm } 184718316Swollman} 184818316Swollman 184918316Swollman 185018316Swollmanvoid 185118316Swollmanrtdelete(struct rt_entry *rt) 185218316Swollman{ 185318316Swollman struct khash *k; 185418316Swollman 185518316Swollman 185618316Swollman if (TRACEACTIONS) 185718316Swollman trace_add_del("Del", rt); 185818316Swollman 185918316Swollman k = kern_find(rt->rt_dst, rt->rt_mask, 0); 186018316Swollman if (k != 0) { 186118316Swollman k->k_state |= KS_DELETE; 186218316Swollman need_kern.tv_sec = now.tv_sec; 186318316Swollman } 186418316Swollman 186518316Swollman dst_sock.sin_addr.s_addr = rt->rt_dst; 186664131Ssheldonh mask_sock.sin_addr.s_addr = htonl(rt->rt_mask); 186718316Swollman masktrim(&mask_sock); 186818316Swollman if (rt != (struct rt_entry *)rhead->rnh_deladdr(&dst_sock, &mask_sock, 186918316Swollman rhead)) { 187018316Swollman msglog("rnh_deladdr() failed"); 187118316Swollman } else { 187218316Swollman free(rt); 187318316Swollman total_routes--; 187418316Swollman } 187518316Swollman} 187618316Swollman 187718316Swollman 187846303Smarkmvoid 187946303Smarkmrts_delete(struct rt_entry *rt, 188046303Smarkm struct rt_spare *rts) 188146303Smarkm{ 188246303Smarkm trace_upslot(rt, rts, &rts_empty); 188346303Smarkm *rts = rts_empty; 188446303Smarkm} 188546303Smarkm 188646303Smarkm 188718316Swollman/* Get rid of a bad route, and try to switch to a replacement. 188818316Swollman */ 188918316Swollmanvoid 189018316Swollmanrtbad(struct rt_entry *rt) 189118316Swollman{ 189246303Smarkm struct rt_spare new; 189346303Smarkm 189418316Swollman /* Poison the route */ 189546303Smarkm new = rt->rt_spares[0]; 189646303Smarkm new.rts_metric = HOPCNT_INFINITY; 189746303Smarkm rtchange(rt, rt->rt_state & ~(RS_IF | RS_LOCAL | RS_STATIC), &new, 0); 189818316Swollman rtswitch(rt, 0); 189918316Swollman} 190018316Swollman 190118316Swollman 190218316Swollman/* Junk a RS_NET_SYN or RS_LOCAL route, 190318316Swollman * unless it is needed by another interface. 190418316Swollman */ 190518316Swollmanvoid 190618316Swollmanrtbad_sub(struct rt_entry *rt) 190718316Swollman{ 190818316Swollman struct interface *ifp, *ifp1; 190918316Swollman struct intnet *intnetp; 191018316Swollman u_int state; 191118316Swollman 191218316Swollman 191318316Swollman ifp1 = 0; 191418316Swollman state = 0; 191518316Swollman 191618316Swollman if (rt->rt_state & RS_LOCAL) { 191718316Swollman /* Is this the route through loopback for the interface? 191818316Swollman * If so, see if it is used by any other interfaces, such 191918316Swollman * as a point-to-point interface with the same local address. 192018316Swollman */ 192118316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 192218316Swollman /* Retain it if another interface needs it. 192318316Swollman */ 192418316Swollman if (ifp->int_addr == rt->rt_ifp->int_addr) { 192518316Swollman state |= RS_LOCAL; 192618316Swollman ifp1 = ifp; 192718316Swollman break; 192818316Swollman } 192918316Swollman } 193018316Swollman 193118316Swollman } 193218316Swollman 193318316Swollman if (!(state & RS_LOCAL)) { 193418316Swollman /* Retain RIPv1 logical network route if there is another 193518316Swollman * interface that justifies it. 193618316Swollman */ 193718316Swollman if (rt->rt_state & RS_NET_SYN) { 193818316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 193918316Swollman if ((ifp->int_state & IS_NEED_NET_SYN) 194018316Swollman && rt->rt_mask == ifp->int_std_mask 194118316Swollman && rt->rt_dst == ifp->int_std_addr) { 194218316Swollman state |= RS_NET_SYN; 194318316Swollman ifp1 = ifp; 194418316Swollman break; 194518316Swollman } 194618316Swollman } 194718316Swollman } 194818316Swollman 194918316Swollman /* or if there is an authority route that needs it. */ 195018316Swollman for (intnetp = intnets; 195118316Swollman intnetp != 0; 195218316Swollman intnetp = intnetp->intnet_next) { 195318316Swollman if (intnetp->intnet_addr == rt->rt_dst 195418316Swollman && intnetp->intnet_mask == rt->rt_mask) { 195518316Swollman state |= (RS_NET_SYN | RS_NET_INT); 195618316Swollman break; 195718316Swollman } 195818316Swollman } 195918316Swollman } 196018316Swollman 196118316Swollman if (ifp1 != 0 || (state & RS_NET_SYN)) { 196246303Smarkm struct rt_spare new = rt->rt_spares[0]; 196346303Smarkm new.rts_ifp = ifp1; 196446303Smarkm rtchange(rt, ((rt->rt_state & ~(RS_NET_SYN|RS_LOCAL)) | state), 196546303Smarkm &new, 0); 196618316Swollman } else { 196718316Swollman rtbad(rt); 196818316Swollman } 196918316Swollman} 197018316Swollman 197118316Swollman 197218316Swollman/* Called while walking the table looking for sick interfaces 197318316Swollman * or after a time change. 197418316Swollman */ 197518316Swollman/* ARGSUSED */ 197618316Swollmanint 197718316Swollmanwalk_bad(struct radix_node *rn, 197846303Smarkm struct walkarg *argp UNUSED) 197918316Swollman{ 198018316Swollman#define RT ((struct rt_entry *)rn) 198118316Swollman struct rt_spare *rts; 198218316Swollman int i; 198318316Swollman 198418316Swollman 198518316Swollman /* fix any spare routes through the interface 198618316Swollman */ 198718316Swollman rts = RT->rt_spares; 198818316Swollman for (i = NUM_SPARES; i != 1; i--) { 198918316Swollman rts++; 199046303Smarkm if (rts->rts_metric < HOPCNT_INFINITY 199146303Smarkm && (rts->rts_ifp == 0 199246303Smarkm || (rts->rts_ifp->int_state & IS_BROKE))) 199346303Smarkm rts_delete(RT, rts); 199418316Swollman } 199518316Swollman 199618316Swollman /* Deal with the main route 199718316Swollman */ 199818316Swollman /* finished if it has been handled before or if its interface is ok 199918316Swollman */ 200018316Swollman if (RT->rt_ifp == 0 || !(RT->rt_ifp->int_state & IS_BROKE)) 200118316Swollman return 0; 200218316Swollman 200318316Swollman /* Bad routes for other than interfaces are easy. 200418316Swollman */ 200518316Swollman if (0 == (RT->rt_state & (RS_IF | RS_NET_SYN | RS_LOCAL))) { 200618316Swollman rtbad(RT); 200718316Swollman return 0; 200818316Swollman } 200918316Swollman 201018316Swollman rtbad_sub(RT); 201118316Swollman return 0; 201218316Swollman#undef RT 201318316Swollman} 201418316Swollman 201518316Swollman 201618316Swollman/* Check the age of an individual route. 201718316Swollman */ 201818316Swollman/* ARGSUSED */ 201918316Swollmanstatic int 202018316Swollmanwalk_age(struct radix_node *rn, 202146303Smarkm struct walkarg *argp UNUSED) 202218316Swollman{ 202318316Swollman#define RT ((struct rt_entry *)rn) 202418316Swollman struct interface *ifp; 202518316Swollman struct rt_spare *rts; 202618316Swollman int i; 202718316Swollman 202818316Swollman 202918316Swollman /* age all of the spare routes, including the primary route 203018316Swollman * currently in use 203118316Swollman */ 203218316Swollman rts = RT->rt_spares; 203318316Swollman for (i = NUM_SPARES; i != 0; i--, rts++) { 203418316Swollman 203518316Swollman ifp = rts->rts_ifp; 203618316Swollman if (i == NUM_SPARES) { 203718316Swollman if (!AGE_RT(RT->rt_state, ifp)) { 203818316Swollman /* Keep various things from deciding ageless 203918316Swollman * routes are stale 204018316Swollman */ 204118316Swollman rts->rts_time = now.tv_sec; 204218316Swollman continue; 204318316Swollman } 204418316Swollman 204518316Swollman /* forget RIP routes after RIP has been turned off. 204618316Swollman */ 204718316Swollman if (rip_sock < 0) { 204818316Swollman rtdelete(RT); 204918316Swollman return 0; 205018316Swollman } 205118316Swollman } 205218316Swollman 205318316Swollman /* age failing routes 205418316Swollman */ 205518316Swollman if (age_bad_gate == rts->rts_gate 205618316Swollman && rts->rts_time >= now_stale) { 205718316Swollman rts->rts_time -= SUPPLY_INTERVAL; 205818316Swollman } 205918316Swollman 206018316Swollman /* trash the spare routes when they go bad */ 206118316Swollman if (rts->rts_metric < HOPCNT_INFINITY 206246303Smarkm && now_garbage > rts->rts_time 206346303Smarkm && i != NUM_SPARES) 206446303Smarkm rts_delete(RT, rts); 206518316Swollman } 206618316Swollman 206718316Swollman 206818316Swollman /* finished if the active route is still fresh */ 206918316Swollman if (now_stale <= RT->rt_time) 207018316Swollman return 0; 207118316Swollman 207218316Swollman /* try to switch to an alternative */ 207318316Swollman rtswitch(RT, 0); 207418316Swollman 207518316Swollman /* Delete a dead route after it has been publically mourned. */ 207618316Swollman if (now_garbage > RT->rt_time) { 207718316Swollman rtdelete(RT); 207818316Swollman return 0; 207918316Swollman } 208018316Swollman 208118316Swollman /* Start poisoning a bad route before deleting it. */ 208246303Smarkm if (now.tv_sec - RT->rt_time > EXPIRE_TIME) { 208346303Smarkm struct rt_spare new = RT->rt_spares[0]; 208446303Smarkm new.rts_metric = HOPCNT_INFINITY; 208546303Smarkm rtchange(RT, RT->rt_state, &new, 0); 208646303Smarkm } 208718316Swollman return 0; 208818316Swollman} 208918316Swollman 209018316Swollman 209118316Swollman/* Watch for dead routes and interfaces. 209218316Swollman */ 209318316Swollmanvoid 209418316Swollmanage(naddr bad_gate) 209518316Swollman{ 209618316Swollman struct interface *ifp; 209719885Swollman int need_query = 0; 209818316Swollman 209919885Swollman /* If not listening to RIP, there is no need to age the routes in 210019885Swollman * the table. 210119885Swollman */ 210219885Swollman age_timer.tv_sec = (now.tv_sec 210319885Swollman + ((rip_sock < 0) ? NEVER : SUPPLY_INTERVAL)); 210418316Swollman 210519885Swollman /* Check for dead IS_REMOTE interfaces by timing their 210619885Swollman * transmissions. 210719885Swollman */ 210819885Swollman for (ifp = ifnet; ifp; ifp = ifp->int_next) { 210919885Swollman if (!(ifp->int_state & IS_REMOTE)) 211019885Swollman continue; 211118316Swollman 211219885Swollman /* ignore unreachable remote interfaces */ 211319885Swollman if (!check_remote(ifp)) 211419885Swollman continue; 211546303Smarkm 211619885Swollman /* Restore remote interface that has become reachable 211718316Swollman */ 211819885Swollman if (ifp->int_state & IS_BROKE) 211919885Swollman if_ok(ifp, "remote "); 212018316Swollman 212119885Swollman if (ifp->int_act_time != NEVER 212219885Swollman && now.tv_sec - ifp->int_act_time > EXPIRE_TIME) { 212319885Swollman msglog("remote interface %s to %s timed out after" 212446303Smarkm " %ld:%ld", 212519885Swollman ifp->int_name, 212619885Swollman naddr_ntoa(ifp->int_dstaddr), 212719885Swollman (now.tv_sec - ifp->int_act_time)/60, 212819885Swollman (now.tv_sec - ifp->int_act_time)%60); 212919885Swollman if_sick(ifp); 213018316Swollman } 213119885Swollman 213219885Swollman /* If we have not heard from the other router 213319885Swollman * recently, ask it. 213419885Swollman */ 213519885Swollman if (now.tv_sec >= ifp->int_query_time) { 213619885Swollman ifp->int_query_time = NEVER; 213719885Swollman need_query = 1; 213819885Swollman } 213918316Swollman } 214018316Swollman 214118316Swollman /* Age routes. */ 214218316Swollman age_bad_gate = bad_gate; 214318316Swollman (void)rn_walktree(rhead, walk_age, 0); 214418316Swollman 214546303Smarkm /* delete old redirected routes to keep the kernel table small 214646303Smarkm * and prevent blackholes 214746303Smarkm */ 214846303Smarkm del_redirects(bad_gate, now.tv_sec-STALE_TIME); 214946303Smarkm 215018316Swollman /* Update the kernel routing table. */ 215118316Swollman fix_kern(); 215219885Swollman 215319885Swollman /* poke reticent remote gateways */ 215419885Swollman if (need_query) 215519885Swollman rip_query(); 215618316Swollman} 2157