table.c revision 64131
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 * 3. All advertising materials mentioning features or use of this software 1446303Smarkm * must display the following acknowledgment: 1518316Swollman * This product includes software developed by the University of 1618316Swollman * California, Berkeley and its contributors. 1718316Swollman * 4. Neither the name of the University nor the names of its contributors 1818316Swollman * may be used to endorse or promote products derived from this software 1918316Swollman * without specific prior written permission. 2018316Swollman * 2118316Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2218316Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2318316Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2418316Swollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2518316Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2618316Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2718316Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2818316Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2918316Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3018316Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3118316Swollman * SUCH DAMAGE. 3246303Smarkm * 3350476Speter * $FreeBSD: head/sbin/routed/table.c 64131 2000-08-02 11:38:20Z sheldonh $ 3418316Swollman */ 3518316Swollman 3646303Smarkm#include "defs.h" 3746303Smarkm 3846303Smarkm#if !defined(sgi) && !defined(__NetBSD__) 3946303Smarkmstatic char sccsid[] __attribute__((unused)) = "@(#)tables.c 8.1 (Berkeley) 6/5/93"; 4046303Smarkm#elif defined(__NetBSD__) 4146303Smarkm__RCSID("$NetBSD$"); 4218316Swollman#endif 4350969Speter#ident "$FreeBSD: head/sbin/routed/table.c 64131 2000-08-02 11:38:20Z sheldonh $" 4418316Swollman 4518316Swollmanstatic struct rt_spare *rts_better(struct rt_entry *); 4646303Smarkmstatic struct rt_spare rts_empty = {0,0,0,HOPCNT_INFINITY,0,0,0}; 4746303Smarkmstatic void set_need_flash(void); 4846303Smarkm#ifdef _HAVE_SIN_LEN 4946303Smarkmstatic void masktrim(struct sockaddr_in *ap); 5046303Smarkm#else 5146303Smarkmstatic void masktrim(struct sockaddr_in_new *ap); 5246303Smarkm#endif 5318316Swollman 5446303Smarkm 5518316Swollmanstruct radix_node_head *rhead; /* root of the radix tree */ 5618316Swollman 5718316Swollmanint need_flash = 1; /* flash update needed 5818316Swollman * start =1 to suppress the 1st 5918316Swollman */ 6018316Swollman 6118316Swollmanstruct timeval age_timer; /* next check of old routes */ 6218316Swollmanstruct timeval need_kern = { /* need to update kernel table */ 6364131Ssheldonh EPOCH+MIN_WAITTIME-1, 0 6418316Swollman}; 6518316Swollman 6618316Swollmanint stopint; 6718316Swollman 6818316Swollmanint total_routes; 6918316Swollman 7019885Swollman/* zap any old routes through this gateway */ 7118316Swollmannaddr age_bad_gate; 7218316Swollman 7318316Swollman 7418316Swollman/* It is desirable to "aggregate" routes, to combine differing routes of 7518316Swollman * the same metric and next hop into a common route with a smaller netmask 7618316Swollman * or to suppress redundant routes, routes that add no information to 7718316Swollman * routes with smaller netmasks. 7818316Swollman * 7918316Swollman * A route is redundant if and only if any and all routes with smaller 8018316Swollman * but matching netmasks and nets are the same. Since routes are 8118316Swollman * kept sorted in the radix tree, redundant routes always come second. 8218316Swollman * 8318316Swollman * There are two kinds of aggregations. First, two routes of the same bit 8418316Swollman * mask and differing only in the least significant bit of the network 8518316Swollman * number can be combined into a single route with a coarser mask. 8618316Swollman * 8718316Swollman * Second, a route can be suppressed in favor of another route with a more 8818316Swollman * coarse mask provided no incompatible routes with intermediate masks 8918316Swollman * are present. The second kind of aggregation involves suppressing routes. 9018316Swollman * A route must not be suppressed if an incompatible route exists with 9118316Swollman * an intermediate mask, since the suppressed route would be covered 9218316Swollman * by the intermediate. 9318316Swollman * 9418316Swollman * This code relies on the radix tree walk encountering routes 9518316Swollman * sorted first by address, with the smallest address first. 9618316Swollman */ 9718316Swollman 9818316Swollmanstruct ag_info ag_slots[NUM_AG_SLOTS], *ag_avail, *ag_corsest, *ag_finest; 9918316Swollman 10018316Swollman/* #define DEBUG_AG */ 10118316Swollman#ifdef DEBUG_AG 10218316Swollman#define CHECK_AG() {int acnt = 0; struct ag_info *cag; \ 10318316Swollman for (cag = ag_avail; cag != 0; cag = cag->ag_fine) \ 10418316Swollman acnt++; \ 10518316Swollman for (cag = ag_corsest; cag != 0; cag = cag->ag_fine) \ 10618316Swollman acnt++; \ 10718316Swollman if (acnt != NUM_AG_SLOTS) { \ 10818316Swollman (void)fflush(stderr); \ 10918316Swollman abort(); \ 11018316Swollman } \ 11118316Swollman} 11218316Swollman#else 11318316Swollman#define CHECK_AG() 11418316Swollman#endif 11518316Swollman 11618316Swollman 11718316Swollman/* Output the contents of an aggregation table slot. 11818316Swollman * This function must always be immediately followed with the deletion 11918316Swollman * of the target slot. 12018316Swollman */ 12118316Swollmanstatic void 12218316Swollmanag_out(struct ag_info *ag, 12318316Swollman void (*out)(struct ag_info *)) 12418316Swollman{ 12518316Swollman struct ag_info *ag_cors; 12618316Swollman naddr bit; 12718316Swollman 12818316Swollman 12946303Smarkm /* Forget it if this route should not be output for split-horizon. */ 13046303Smarkm if (ag->ag_state & AGS_SPLIT_HZ) 13146303Smarkm return; 13246303Smarkm 13318316Swollman /* If we output both the even and odd twins, then the immediate parent, 13418316Swollman * if it is present, is redundant, unless the parent manages to 13518316Swollman * aggregate into something coarser. 13618316Swollman * On successive calls, this code detects the even and odd twins, 13718316Swollman * and marks the parent. 13818316Swollman * 13918316Swollman * Note that the order in which the radix tree code emits routes 14018316Swollman * ensures that the twins are seen before the parent is emitted. 14118316Swollman */ 14218316Swollman ag_cors = ag->ag_cors; 14318316Swollman if (ag_cors != 0 14418316Swollman && ag_cors->ag_mask == ag->ag_mask<<1 14518316Swollman && ag_cors->ag_dst_h == (ag->ag_dst_h & ag_cors->ag_mask)) { 14618316Swollman ag_cors->ag_state |= ((ag_cors->ag_dst_h == ag->ag_dst_h) 14718316Swollman ? AGS_REDUN0 14818316Swollman : AGS_REDUN1); 14918316Swollman } 15018316Swollman 15118316Swollman /* Skip it if this route is itself redundant. 15218316Swollman * 15318316Swollman * It is ok to change the contents of the slot here, since it is 15418316Swollman * always deleted next. 15518316Swollman */ 15618316Swollman if (ag->ag_state & AGS_REDUN0) { 15718316Swollman if (ag->ag_state & AGS_REDUN1) 15846303Smarkm return; /* quit if fully redundant */ 15946303Smarkm /* make it finer if it is half-redundant */ 16018316Swollman bit = (-ag->ag_mask) >> 1; 16118316Swollman ag->ag_dst_h |= bit; 16218316Swollman ag->ag_mask |= bit; 16318316Swollman 16418316Swollman } else if (ag->ag_state & AGS_REDUN1) { 16546303Smarkm /* make it finer if it is half-redundant */ 16618316Swollman bit = (-ag->ag_mask) >> 1; 16718316Swollman ag->ag_mask |= bit; 16818316Swollman } 16918316Swollman out(ag); 17018316Swollman} 17118316Swollman 17218316Swollman 17318316Swollmanstatic void 17418316Swollmanag_del(struct ag_info *ag) 17518316Swollman{ 17618316Swollman CHECK_AG(); 17718316Swollman 17818316Swollman if (ag->ag_cors == 0) 17918316Swollman ag_corsest = ag->ag_fine; 18018316Swollman else 18118316Swollman ag->ag_cors->ag_fine = ag->ag_fine; 18218316Swollman 18318316Swollman if (ag->ag_fine == 0) 18418316Swollman ag_finest = ag->ag_cors; 18518316Swollman else 18618316Swollman ag->ag_fine->ag_cors = ag->ag_cors; 18718316Swollman 18818316Swollman ag->ag_fine = ag_avail; 18918316Swollman ag_avail = ag; 19018316Swollman 19118316Swollman CHECK_AG(); 19218316Swollman} 19318316Swollman 19418316Swollman 19537908Scharnier/* Flush routes waiting for aggregation. 19618316Swollman * This must not suppress a route unless it is known that among all 19718316Swollman * routes with coarser masks that match it, the one with the longest 19818316Swollman * mask is appropriate. This is ensured by scanning the routes 19937908Scharnier * in lexical order, and with the most restrictive mask first 20018316Swollman * among routes to the same destination. 20118316Swollman */ 20218316Swollmanvoid 20318316Swollmanag_flush(naddr lim_dst_h, /* flush routes to here */ 20418316Swollman naddr lim_mask, /* matching this mask */ 20518316Swollman void (*out)(struct ag_info *)) 20618316Swollman{ 20718316Swollman struct ag_info *ag, *ag_cors; 20818316Swollman naddr dst_h; 20918316Swollman 21018316Swollman 21118316Swollman for (ag = ag_finest; 21218316Swollman ag != 0 && ag->ag_mask >= lim_mask; 21318316Swollman ag = ag_cors) { 21418316Swollman ag_cors = ag->ag_cors; 21518316Swollman 21618316Swollman /* work on only the specified routes */ 21718316Swollman dst_h = ag->ag_dst_h; 21818316Swollman if ((dst_h & lim_mask) != lim_dst_h) 21918316Swollman continue; 22018316Swollman 22118316Swollman if (!(ag->ag_state & AGS_SUPPRESS)) 22218316Swollman ag_out(ag, out); 22318316Swollman 22418316Swollman else for ( ; ; ag_cors = ag_cors->ag_cors) { 22518316Swollman /* Look for a route that can suppress the 22618316Swollman * current route */ 22718316Swollman if (ag_cors == 0) { 22818316Swollman /* failed, so output it and look for 22918316Swollman * another route to work on 23018316Swollman */ 23118316Swollman ag_out(ag, out); 23218316Swollman break; 23318316Swollman } 23418316Swollman 23518316Swollman if ((dst_h & ag_cors->ag_mask) == ag_cors->ag_dst_h) { 23618316Swollman /* We found a route with a coarser mask that 23718316Swollman * aggregates the current target. 23818316Swollman * 23918316Swollman * If it has a different next hop, it 24018316Swollman * cannot replace the target, so output 24118316Swollman * the target. 24218316Swollman */ 24318316Swollman if (ag->ag_gate != ag_cors->ag_gate 24418316Swollman && !(ag->ag_state & AGS_FINE_GATE) 24518316Swollman && !(ag_cors->ag_state & AGS_CORS_GATE)) { 24618316Swollman ag_out(ag, out); 24718316Swollman break; 24818316Swollman } 24918316Swollman 25018316Swollman /* If the coarse route has a good enough 25118316Swollman * metric, it suppresses the target. 25246303Smarkm * If the suppressed target was redundant, 25346303Smarkm * then mark the suppressor redundant. 25418316Swollman */ 25518316Swollman if (ag_cors->ag_pref <= ag->ag_pref) { 25618316Swollman if (ag_cors->ag_seqno > ag->ag_seqno) 25718316Swollman ag_cors->ag_seqno = ag->ag_seqno; 25818316Swollman if (AG_IS_REDUN(ag->ag_state) 25918316Swollman && ag_cors->ag_mask==ag->ag_mask<<1) { 26018316Swollman if (ag_cors->ag_dst_h == dst_h) 26118316Swollman ag_cors->ag_state |= AGS_REDUN0; 26218316Swollman else 26318316Swollman ag_cors->ag_state |= AGS_REDUN1; 26418316Swollman } 26518316Swollman if (ag->ag_tag != ag_cors->ag_tag) 26618316Swollman ag_cors->ag_tag = 0; 26718316Swollman if (ag->ag_nhop != ag_cors->ag_nhop) 26818316Swollman ag_cors->ag_nhop = 0; 26918316Swollman break; 27018316Swollman } 27118316Swollman } 27218316Swollman } 27318316Swollman 27418316Swollman /* That route has either been output or suppressed */ 27518316Swollman ag_cors = ag->ag_cors; 27618316Swollman ag_del(ag); 27718316Swollman } 27818316Swollman 27918316Swollman CHECK_AG(); 28018316Swollman} 28118316Swollman 28218316Swollman 28318316Swollman/* Try to aggregate a route with previous routes. 28418316Swollman */ 28518316Swollmanvoid 28618316Swollmanag_check(naddr dst, 28718316Swollman naddr mask, 28818316Swollman naddr gate, 28918316Swollman naddr nhop, 29018316Swollman char metric, 29118316Swollman char pref, 29218316Swollman u_int seqno, 29318316Swollman u_short tag, 29418316Swollman u_short state, 29518316Swollman void (*out)(struct ag_info *)) /* output using this */ 29618316Swollman{ 29718316Swollman struct ag_info *ag, *nag, *ag_cors; 29818316Swollman naddr xaddr; 29918316Swollman int x; 30018316Swollman 30118316Swollman NTOHL(dst); 30218316Swollman 30318316Swollman /* Punt non-contiguous subnet masks. 30418316Swollman * 30518316Swollman * (X & -X) contains a single bit if and only if X is a power of 2. 30618316Swollman * (X + (X & -X)) == 0 if and only if X is a power of 2. 30718316Swollman */ 30818316Swollman if ((mask & -mask) + mask != 0) { 30918316Swollman struct ag_info nc_ag; 31018316Swollman 31118316Swollman nc_ag.ag_dst_h = dst; 31218316Swollman nc_ag.ag_mask = mask; 31318316Swollman nc_ag.ag_gate = gate; 31418316Swollman nc_ag.ag_nhop = nhop; 31518316Swollman nc_ag.ag_metric = metric; 31618316Swollman nc_ag.ag_pref = pref; 31718316Swollman nc_ag.ag_tag = tag; 31818316Swollman nc_ag.ag_state = state; 31918316Swollman nc_ag.ag_seqno = seqno; 32018316Swollman out(&nc_ag); 32118316Swollman return; 32218316Swollman } 32318316Swollman 32418316Swollman /* Search for the right slot in the aggregation table. 32518316Swollman */ 32618316Swollman ag_cors = 0; 32718316Swollman ag = ag_corsest; 32818316Swollman while (ag != 0) { 32918316Swollman if (ag->ag_mask >= mask) 33018316Swollman break; 33118316Swollman 33218316Swollman /* Suppress old routes (i.e. combine with compatible routes 33318316Swollman * with coarser masks) as we look for the right slot in the 33418316Swollman * aggregation table for the new route. 33518316Swollman * A route to an address less than the current destination 33618316Swollman * will not be affected by the current route or any route 33718316Swollman * seen hereafter. That means it is safe to suppress it. 33837908Scharnier * This check keeps poor routes (e.g. with large hop counts) 33937908Scharnier * from preventing suppression of finer routes. 34018316Swollman */ 34118316Swollman if (ag_cors != 0 34218316Swollman && ag->ag_dst_h < dst 34318316Swollman && (ag->ag_state & AGS_SUPPRESS) 34418316Swollman && ag_cors->ag_pref <= ag->ag_pref 34518316Swollman && (ag->ag_dst_h & ag_cors->ag_mask) == ag_cors->ag_dst_h 34618316Swollman && (ag_cors->ag_gate == ag->ag_gate 34718316Swollman || (ag->ag_state & AGS_FINE_GATE) 34818316Swollman || (ag_cors->ag_state & AGS_CORS_GATE))) { 34918316Swollman if (ag_cors->ag_seqno > ag->ag_seqno) 35018316Swollman ag_cors->ag_seqno = ag->ag_seqno; 35146303Smarkm /* If the suppressed target was redundant, 35246303Smarkm * then mark the suppressor redundant. 35346303Smarkm */ 35418316Swollman if (AG_IS_REDUN(ag->ag_state) 35564131Ssheldonh && ag_cors->ag_mask == ag->ag_mask<<1) { 35618316Swollman if (ag_cors->ag_dst_h == dst) 35718316Swollman ag_cors->ag_state |= AGS_REDUN0; 35818316Swollman else 35918316Swollman ag_cors->ag_state |= AGS_REDUN1; 36018316Swollman } 36118316Swollman if (ag->ag_tag != ag_cors->ag_tag) 36218316Swollman ag_cors->ag_tag = 0; 36318316Swollman if (ag->ag_nhop != ag_cors->ag_nhop) 36418316Swollman ag_cors->ag_nhop = 0; 36518316Swollman ag_del(ag); 36618316Swollman CHECK_AG(); 36718316Swollman } else { 36818316Swollman ag_cors = ag; 36918316Swollman } 37018316Swollman ag = ag_cors->ag_fine; 37118316Swollman } 37218316Swollman 37318316Swollman /* If we find the even/odd twin of the new route, and if the 37418316Swollman * masks and so forth are equal, we can aggregate them. 37518316Swollman * We can probably promote one of the pair. 37618316Swollman * 37718316Swollman * Since the routes are encountered in lexical order, 37818316Swollman * the new route must be odd. However, the second or later 37918316Swollman * times around this loop, it could be the even twin promoted 38018316Swollman * from the even/odd pair of twins of the finer route. 38118316Swollman */ 38218316Swollman while (ag != 0 38318316Swollman && ag->ag_mask == mask 38418316Swollman && ((ag->ag_dst_h ^ dst) & (mask<<1)) == 0) { 38518316Swollman 38618316Swollman /* Here we know the target route and the route in the current 38718316Swollman * slot have the same netmasks and differ by at most the 38818316Swollman * last bit. They are either for the same destination, or 38918316Swollman * for an even/odd pair of destinations. 39018316Swollman */ 39118316Swollman if (ag->ag_dst_h == dst) { 39218316Swollman /* We have two routes to the same destination. 39318316Swollman * Routes are encountered in lexical order, so a 39418316Swollman * route is never promoted until the parent route is 39518316Swollman * already present. So we know that the new route is 39646303Smarkm * a promoted (or aggregated) pair and the route 39746303Smarkm * already in the slot is the explicit route. 39818316Swollman * 39918316Swollman * Prefer the best route if their metrics differ, 40046303Smarkm * or the aggregated one if not, following a sort 40118316Swollman * of longest-match rule. 40218316Swollman */ 40318316Swollman if (pref <= ag->ag_pref) { 40418316Swollman ag->ag_gate = gate; 40518316Swollman ag->ag_nhop = nhop; 40618316Swollman ag->ag_tag = tag; 40718316Swollman ag->ag_metric = metric; 40818316Swollman ag->ag_pref = pref; 40918316Swollman x = ag->ag_state; 41018316Swollman ag->ag_state = state; 41118316Swollman state = x; 41218316Swollman } 41318316Swollman 41418316Swollman /* The sequence number controls flash updating, 41518316Swollman * and should be the smaller of the two. 41618316Swollman */ 41718316Swollman if (ag->ag_seqno > seqno) 41818316Swollman ag->ag_seqno = seqno; 41918316Swollman 42046303Smarkm /* Some bits are set if they are set on either route, 42146303Smarkm * except when the route is for an interface. 42246303Smarkm */ 42346303Smarkm if (!(ag->ag_state & AGS_IF)) 42446303Smarkm ag->ag_state |= (state & (AGS_AGGREGATE_EITHER 42546303Smarkm | AGS_REDUN0 42646303Smarkm | AGS_REDUN1)); 42718316Swollman return; 42818316Swollman } 42918316Swollman 43018316Swollman /* If one of the routes can be promoted and the other can 43118316Swollman * be suppressed, it may be possible to combine them or 43218316Swollman * worthwhile to promote one. 43318316Swollman * 43446303Smarkm * Any route that can be promoted is always 43518316Swollman * marked to be eligible to be suppressed. 43618316Swollman */ 43746303Smarkm if (!((state & AGS_AGGREGATE) 43818316Swollman && (ag->ag_state & AGS_SUPPRESS)) 43946303Smarkm && !((ag->ag_state & AGS_AGGREGATE) 44018316Swollman && (state & AGS_SUPPRESS))) 44118316Swollman break; 44218316Swollman 44318316Swollman /* A pair of even/odd twin routes can be combined 44418316Swollman * if either is redundant, or if they are via the 44518316Swollman * same gateway and have the same metric. 44618316Swollman */ 44718316Swollman if (AG_IS_REDUN(ag->ag_state) 44818316Swollman || AG_IS_REDUN(state) 44918316Swollman || (ag->ag_gate == gate 45018316Swollman && ag->ag_pref == pref 45146303Smarkm && (state & ag->ag_state & AGS_AGGREGATE) != 0)) { 45218316Swollman 45318316Swollman /* We have both the even and odd pairs. 45418316Swollman * Since the routes are encountered in order, 45518316Swollman * the route in the slot must be the even twin. 45618316Swollman * 45746303Smarkm * Combine and promote (aggregate) the pair of routes. 45818316Swollman */ 45918316Swollman if (seqno > ag->ag_seqno) 46018316Swollman seqno = ag->ag_seqno; 46118316Swollman if (!AG_IS_REDUN(state)) 46218316Swollman state &= ~AGS_REDUN1; 46318316Swollman if (AG_IS_REDUN(ag->ag_state)) 46418316Swollman state |= AGS_REDUN0; 46518316Swollman else 46618316Swollman state &= ~AGS_REDUN0; 46746303Smarkm state |= (ag->ag_state & AGS_AGGREGATE_EITHER); 46818316Swollman if (ag->ag_tag != tag) 46918316Swollman tag = 0; 47018316Swollman if (ag->ag_nhop != nhop) 47118316Swollman nhop = 0; 47218316Swollman 47318316Swollman /* Get rid of the even twin that was already 47418316Swollman * in the slot. 47518316Swollman */ 47618316Swollman ag_del(ag); 47718316Swollman 47818316Swollman } else if (ag->ag_pref >= pref 47946303Smarkm && (ag->ag_state & AGS_AGGREGATE)) { 48018316Swollman /* If we cannot combine the pair, maybe the route 48118316Swollman * with the worse metric can be promoted. 48218316Swollman * 48318316Swollman * Promote the old, even twin, by giving its slot 48418316Swollman * in the table to the new, odd twin. 48518316Swollman */ 48618316Swollman ag->ag_dst_h = dst; 48718316Swollman 48818316Swollman xaddr = ag->ag_gate; 48918316Swollman ag->ag_gate = gate; 49018316Swollman gate = xaddr; 49118316Swollman 49218316Swollman xaddr = ag->ag_nhop; 49318316Swollman ag->ag_nhop = nhop; 49418316Swollman nhop = xaddr; 49518316Swollman 49618316Swollman x = ag->ag_tag; 49718316Swollman ag->ag_tag = tag; 49818316Swollman tag = x; 49918316Swollman 50046303Smarkm /* The promoted route is even-redundant only if the 50146303Smarkm * even twin was fully redundant. It is not 50246303Smarkm * odd-redundant because the odd-twin will still be 50346303Smarkm * in the table. 50446303Smarkm */ 50518316Swollman x = ag->ag_state; 50646303Smarkm if (!AG_IS_REDUN(x)) 50746303Smarkm x &= ~AGS_REDUN0; 50846303Smarkm x &= ~AGS_REDUN1; 50918316Swollman ag->ag_state = state; 51018316Swollman state = x; 51118316Swollman 51218316Swollman x = ag->ag_metric; 51318316Swollman ag->ag_metric = metric; 51418316Swollman metric = x; 51518316Swollman 51618316Swollman x = ag->ag_pref; 51718316Swollman ag->ag_pref = pref; 51818316Swollman pref = x; 51918316Swollman 52046303Smarkm /* take the newest sequence number */ 52118316Swollman if (seqno >= ag->ag_seqno) 52218316Swollman seqno = ag->ag_seqno; 52318316Swollman else 52418316Swollman ag->ag_seqno = seqno; 52518316Swollman 52618316Swollman } else { 52746303Smarkm if (!(state & AGS_AGGREGATE)) 52818316Swollman break; /* cannot promote either twin */ 52918316Swollman 53046303Smarkm /* Promote the new, odd twin by shaving its 53118316Swollman * mask and address. 53246303Smarkm * The promoted route is odd-redundant only if the 53346303Smarkm * odd twin was fully redundant. It is not 53446303Smarkm * even-redundant because the even twin is still in 53546303Smarkm * the table. 53618316Swollman */ 53746303Smarkm if (!AG_IS_REDUN(state)) 53846303Smarkm state &= ~AGS_REDUN1; 53946303Smarkm state &= ~AGS_REDUN0; 54018316Swollman if (seqno > ag->ag_seqno) 54118316Swollman seqno = ag->ag_seqno; 54218316Swollman else 54318316Swollman ag->ag_seqno = seqno; 54418316Swollman } 54518316Swollman 54618316Swollman mask <<= 1; 54718316Swollman dst &= mask; 54818316Swollman 54918316Swollman if (ag_cors == 0) { 55018316Swollman ag = ag_corsest; 55118316Swollman break; 55218316Swollman } 55318316Swollman ag = ag_cors; 55418316Swollman ag_cors = ag->ag_cors; 55518316Swollman } 55618316Swollman 55718316Swollman /* When we can no longer promote and combine routes, 55818316Swollman * flush the old route in the target slot. Also flush 55918316Swollman * any finer routes that we know will never be aggregated by 56018316Swollman * the new route. 56118316Swollman * 56218316Swollman * In case we moved toward coarser masks, 56318316Swollman * get back where we belong 56418316Swollman */ 56518316Swollman if (ag != 0 56618316Swollman && ag->ag_mask < mask) { 56718316Swollman ag_cors = ag; 56818316Swollman ag = ag->ag_fine; 56918316Swollman } 57018316Swollman 57118316Swollman /* Empty the target slot 57218316Swollman */ 57318316Swollman if (ag != 0 && ag->ag_mask == mask) { 57418316Swollman ag_flush(ag->ag_dst_h, ag->ag_mask, out); 57518316Swollman ag = (ag_cors == 0) ? ag_corsest : ag_cors->ag_fine; 57618316Swollman } 57718316Swollman 57818316Swollman#ifdef DEBUG_AG 57918316Swollman (void)fflush(stderr); 58018316Swollman if (ag == 0 && ag_cors != ag_finest) 58118316Swollman abort(); 58218316Swollman if (ag_cors == 0 && ag != ag_corsest) 58318316Swollman abort(); 58418316Swollman if (ag != 0 && ag->ag_cors != ag_cors) 58518316Swollman abort(); 58618316Swollman if (ag_cors != 0 && ag_cors->ag_fine != ag) 58718316Swollman abort(); 58818316Swollman CHECK_AG(); 58918316Swollman#endif 59018316Swollman 59118316Swollman /* Save the new route on the end of the table. 59218316Swollman */ 59318316Swollman nag = ag_avail; 59418316Swollman ag_avail = nag->ag_fine; 59518316Swollman 59618316Swollman nag->ag_dst_h = dst; 59718316Swollman nag->ag_mask = mask; 59818316Swollman nag->ag_gate = gate; 59918316Swollman nag->ag_nhop = nhop; 60018316Swollman nag->ag_metric = metric; 60118316Swollman nag->ag_pref = pref; 60218316Swollman nag->ag_tag = tag; 60318316Swollman nag->ag_state = state; 60418316Swollman nag->ag_seqno = seqno; 60518316Swollman 60618316Swollman nag->ag_fine = ag; 60718316Swollman if (ag != 0) 60818316Swollman ag->ag_cors = nag; 60918316Swollman else 61018316Swollman ag_finest = nag; 61118316Swollman nag->ag_cors = ag_cors; 61218316Swollman if (ag_cors == 0) 61318316Swollman ag_corsest = nag; 61418316Swollman else 61518316Swollman ag_cors->ag_fine = nag; 61618316Swollman CHECK_AG(); 61718316Swollman} 61818316Swollman 61918316Swollman 62058805Sshin#define NAME0_LEN 14 62146303Smarkmstatic const char * 62218316Swollmanrtm_type_name(u_char type) 62318316Swollman{ 62446303Smarkm static const char *rtm_types[] = { 62518316Swollman "RTM_ADD", 62618316Swollman "RTM_DELETE", 62718316Swollman "RTM_CHANGE", 62818316Swollman "RTM_GET", 62918316Swollman "RTM_LOSING", 63018316Swollman "RTM_REDIRECT", 63118316Swollman "RTM_MISS", 63218316Swollman "RTM_LOCK", 63318316Swollman "RTM_OLDADD", 63418316Swollman "RTM_OLDDEL", 63518316Swollman "RTM_RESOLVE", 63618316Swollman "RTM_NEWADDR", 63718316Swollman "RTM_DELADDR", 63858821Sshin "RTM_IFINFO", 63958821Sshin "RTM_NEWMADDR", 64058821Sshin "RTM_DELMADDR" 64118316Swollman }; 64258805Sshin static char name0[NAME0_LEN]; 64318316Swollman 64418316Swollman 64518316Swollman if (type > sizeof(rtm_types)/sizeof(rtm_types[0]) 64618316Swollman || type == 0) { 64758805Sshin snprintf(name0, NAME0_LEN, "RTM type %#x", type); 64818316Swollman return name0; 64918316Swollman } else { 65018316Swollman return rtm_types[type-1]; 65118316Swollman } 65218316Swollman} 65318316Swollman 65418316Swollman 65518316Swollman/* Trim a mask in a sockaddr 65646303Smarkm * Produce a length of 0 for an address of 0. 65746303Smarkm * Otherwise produce the index of the first zero byte. 65818316Swollman */ 65918316Swollmanvoid 66018316Swollman#ifdef _HAVE_SIN_LEN 66118316Swollmanmasktrim(struct sockaddr_in *ap) 66218316Swollman#else 66318316Swollmanmasktrim(struct sockaddr_in_new *ap) 66418316Swollman#endif 66518316Swollman{ 66646303Smarkm char *cp; 66718316Swollman 66846303Smarkm if (ap->sin_addr.s_addr == 0) { 66946303Smarkm ap->sin_len = 0; 67046303Smarkm return; 67146303Smarkm } 67218316Swollman cp = (char *)(&ap->sin_addr.s_addr+1); 67318316Swollman while (*--cp == 0) 67418316Swollman continue; 67518316Swollman ap->sin_len = cp - (char*)ap + 1; 67618316Swollman} 67718316Swollman 67818316Swollman 67918316Swollman/* Tell the kernel to add, delete or change a route 68018316Swollman */ 68118316Swollmanstatic void 68218316Swollmanrtioctl(int action, /* RTM_DELETE, etc */ 68318316Swollman naddr dst, 68418316Swollman naddr gate, 68518316Swollman naddr mask, 68618316Swollman int metric, 68718316Swollman int flags) 68818316Swollman{ 68918316Swollman struct { 69018316Swollman struct rt_msghdr w_rtm; 69118316Swollman struct sockaddr_in w_dst; 69218316Swollman struct sockaddr_in w_gate; 69318316Swollman#ifdef _HAVE_SA_LEN 69418316Swollman struct sockaddr_in w_mask; 69518316Swollman#else 69618316Swollman struct sockaddr_in_new w_mask; 69718316Swollman#endif 69818316Swollman } w; 69918316Swollman long cc; 70046303Smarkm# define PAT " %-10s %s metric=%d flags=%#x" 70146303Smarkm# define ARGS rtm_type_name(action), rtname(dst,mask,gate), metric, flags 70218316Swollman 70318316Swollmanagain: 70446303Smarkm memset(&w, 0, sizeof(w)); 70518316Swollman w.w_rtm.rtm_msglen = sizeof(w); 70618316Swollman w.w_rtm.rtm_version = RTM_VERSION; 70718316Swollman w.w_rtm.rtm_type = action; 70818316Swollman w.w_rtm.rtm_flags = flags; 70918316Swollman w.w_rtm.rtm_seq = ++rt_sock_seqno; 71018316Swollman w.w_rtm.rtm_addrs = RTA_DST|RTA_GATEWAY; 71146303Smarkm if (metric != 0 || action == RTM_CHANGE) { 71218316Swollman w.w_rtm.rtm_rmx.rmx_hopcount = metric; 71318316Swollman w.w_rtm.rtm_inits |= RTV_HOPCOUNT; 71418316Swollman } 71518316Swollman w.w_dst.sin_family = AF_INET; 71618316Swollman w.w_dst.sin_addr.s_addr = dst; 71718316Swollman w.w_gate.sin_family = AF_INET; 71818316Swollman w.w_gate.sin_addr.s_addr = gate; 71918316Swollman#ifdef _HAVE_SA_LEN 72018316Swollman w.w_dst.sin_len = sizeof(w.w_dst); 72118316Swollman w.w_gate.sin_len = sizeof(w.w_gate); 72218316Swollman#endif 72318316Swollman if (mask == HOST_MASK) { 72418316Swollman w.w_rtm.rtm_flags |= RTF_HOST; 72518316Swollman w.w_rtm.rtm_msglen -= sizeof(w.w_mask); 72618316Swollman } else { 72718316Swollman w.w_rtm.rtm_addrs |= RTA_NETMASK; 72818316Swollman w.w_mask.sin_addr.s_addr = htonl(mask); 72918316Swollman#ifdef _HAVE_SA_LEN 73018316Swollman masktrim(&w.w_mask); 73146303Smarkm if (w.w_mask.sin_len == 0) 73246303Smarkm w.w_mask.sin_len = sizeof(long); 73318316Swollman w.w_rtm.rtm_msglen -= (sizeof(w.w_mask) - w.w_mask.sin_len); 73418316Swollman#endif 73518316Swollman } 73618316Swollman 73718316Swollman#ifndef NO_INSTALL 73818316Swollman cc = write(rt_sock, &w, w.w_rtm.rtm_msglen); 73918316Swollman if (cc < 0) { 74018316Swollman if (errno == ESRCH 74118316Swollman && (action == RTM_CHANGE || action == RTM_DELETE)) { 74246303Smarkm trace_act("route disappeared before" PAT, ARGS); 74318316Swollman if (action == RTM_CHANGE) { 74418316Swollman action = RTM_ADD; 74518316Swollman goto again; 74618316Swollman } 74718316Swollman return; 74818316Swollman } 74946303Smarkm msglog("write(rt_sock)" PAT ": %s", ARGS, strerror(errno)); 75046303Smarkm return; 75146303Smarkm } else if (cc != w.w_rtm.rtm_msglen) { 75246303Smarkm msglog("write(rt_sock) wrote %ld instead of %d for" PAT, 75346303Smarkm cc, w.w_rtm.rtm_msglen, ARGS); 75446303Smarkm return; 75518316Swollman } 75618316Swollman#endif 75746303Smarkm if (TRACEKERNEL) 75846303Smarkm trace_misc("write kernel" PAT, ARGS); 75946303Smarkm#undef PAT 76046303Smarkm#undef ARGS 76118316Swollman} 76218316Swollman 76318316Swollman 76418316Swollman#define KHASH_SIZE 71 /* should be prime */ 76518316Swollman#define KHASH(a,m) khash_bins[((a) ^ (m)) % KHASH_SIZE] 76618316Swollmanstatic struct khash { 76718316Swollman struct khash *k_next; 76818316Swollman naddr k_dst; 76918316Swollman naddr k_mask; 77018316Swollman naddr k_gate; 77118316Swollman short k_metric; 77218316Swollman u_short k_state; 77318316Swollman#define KS_NEW 0x001 77446303Smarkm#define KS_DELETE 0x002 /* need to delete the route */ 77518316Swollman#define KS_ADD 0x004 /* add to the kernel */ 77618316Swollman#define KS_CHANGE 0x008 /* tell kernel to change the route */ 77718316Swollman#define KS_DEL_ADD 0x010 /* delete & add to change the kernel */ 77818316Swollman#define KS_STATIC 0x020 /* Static flag in kernel */ 77918316Swollman#define KS_GATEWAY 0x040 /* G flag in kernel */ 78018316Swollman#define KS_DYNAMIC 0x080 /* result of redirect */ 78146303Smarkm#define KS_DELETED 0x100 /* already deleted from kernel */ 78246303Smarkm#define KS_CHECK 0x200 78318316Swollman time_t k_keep; 78418316Swollman#define K_KEEP_LIM 30 78520342Swollman time_t k_redirect_time; /* when redirected route 1st seen */ 78618316Swollman} *khash_bins[KHASH_SIZE]; 78718316Swollman 78818316Swollman 78918316Swollmanstatic struct khash* 79018316Swollmankern_find(naddr dst, naddr mask, struct khash ***ppk) 79118316Swollman{ 79218316Swollman struct khash *k, **pk; 79318316Swollman 79418316Swollman for (pk = &KHASH(dst,mask); (k = *pk) != 0; pk = &k->k_next) { 79518316Swollman if (k->k_dst == dst && k->k_mask == mask) 79618316Swollman break; 79718316Swollman } 79818316Swollman if (ppk != 0) 79918316Swollman *ppk = pk; 80018316Swollman return k; 80118316Swollman} 80218316Swollman 80318316Swollman 80418316Swollmanstatic struct khash* 80518316Swollmankern_add(naddr dst, naddr mask) 80618316Swollman{ 80718316Swollman struct khash *k, **pk; 80818316Swollman 80918316Swollman k = kern_find(dst, mask, &pk); 81018316Swollman if (k != 0) 81118316Swollman return k; 81218316Swollman 81337908Scharnier k = (struct khash *)rtmalloc(sizeof(*k), "kern_add"); 81418316Swollman 81546303Smarkm memset(k, 0, sizeof(*k)); 81618316Swollman k->k_dst = dst; 81718316Swollman k->k_mask = mask; 81818316Swollman k->k_state = KS_NEW; 81918316Swollman k->k_keep = now.tv_sec; 82018316Swollman *pk = k; 82118316Swollman 82218316Swollman return k; 82318316Swollman} 82418316Swollman 82518316Swollman 82618316Swollman/* If a kernel route has a non-zero metric, check that it is still in the 82718316Swollman * daemon table, and not deleted by interfaces coming and going. 82818316Swollman */ 82918316Swollmanstatic void 83018316Swollmankern_check_static(struct khash *k, 83118316Swollman struct interface *ifp) 83218316Swollman{ 83318316Swollman struct rt_entry *rt; 83446303Smarkm struct rt_spare new; 83518316Swollman 83618316Swollman if (k->k_metric == 0) 83718316Swollman return; 83818316Swollman 83946303Smarkm memset(&new, 0, sizeof(new)); 84046303Smarkm new.rts_ifp = ifp; 84146303Smarkm new.rts_gate = k->k_gate; 84246303Smarkm new.rts_router = (ifp != 0) ? ifp->int_addr : loopaddr; 84346303Smarkm new.rts_metric = k->k_metric; 84446303Smarkm new.rts_time = now.tv_sec; 84518316Swollman 84618316Swollman rt = rtget(k->k_dst, k->k_mask); 84718316Swollman if (rt != 0) { 84818316Swollman if (!(rt->rt_state & RS_STATIC)) 84946303Smarkm rtchange(rt, rt->rt_state | RS_STATIC, &new, 0); 85018316Swollman } else { 85146303Smarkm rtadd(k->k_dst, k->k_mask, RS_STATIC, &new); 85218316Swollman } 85318316Swollman} 85418316Swollman 85518316Swollman 85646303Smarkm/* operate on a kernel entry 85746303Smarkm */ 85846303Smarkmstatic void 85946303Smarkmkern_ioctl(struct khash *k, 86046303Smarkm int action, /* RTM_DELETE, etc */ 86146303Smarkm int flags) 86246303Smarkm 86346303Smarkm{ 86446303Smarkm switch (action) { 86546303Smarkm case RTM_DELETE: 86646303Smarkm k->k_state &= ~KS_DYNAMIC; 86746303Smarkm if (k->k_state & KS_DELETED) 86846303Smarkm return; 86946303Smarkm k->k_state |= KS_DELETED; 87046303Smarkm break; 87146303Smarkm case RTM_ADD: 87246303Smarkm k->k_state &= ~KS_DELETED; 87346303Smarkm break; 87446303Smarkm case RTM_CHANGE: 87546303Smarkm if (k->k_state & KS_DELETED) { 87646303Smarkm action = RTM_ADD; 87746303Smarkm k->k_state &= ~KS_DELETED; 87846303Smarkm } 87946303Smarkm break; 88046303Smarkm } 88146303Smarkm 88246303Smarkm rtioctl(action, k->k_dst, k->k_gate, k->k_mask, k->k_metric, flags); 88346303Smarkm} 88446303Smarkm 88546303Smarkm 88618316Swollman/* add a route the kernel told us 88718316Swollman */ 88818316Swollmanstatic void 88918316Swollmanrtm_add(struct rt_msghdr *rtm, 89018316Swollman struct rt_addrinfo *info, 89118316Swollman time_t keep) 89218316Swollman{ 89318316Swollman struct khash *k; 89418316Swollman struct interface *ifp; 89518316Swollman naddr mask; 89618316Swollman 89718316Swollman 89818316Swollman if (rtm->rtm_flags & RTF_HOST) { 89918316Swollman mask = HOST_MASK; 90018316Swollman } else if (INFO_MASK(info) != 0) { 90118316Swollman mask = ntohl(S_ADDR(INFO_MASK(info))); 90218316Swollman } else { 90320342Swollman msglog("ignore %s without mask", rtm_type_name(rtm->rtm_type)); 90418316Swollman return; 90518316Swollman } 90618316Swollman 90718316Swollman k = kern_add(S_ADDR(INFO_DST(info)), mask); 90818316Swollman if (k->k_state & KS_NEW) 90918316Swollman k->k_keep = now.tv_sec+keep; 91046303Smarkm if (INFO_GATE(info) == 0) { 91146303Smarkm trace_act("note %s without gateway", 91246303Smarkm rtm_type_name(rtm->rtm_type)); 91346303Smarkm k->k_metric = HOPCNT_INFINITY; 91446303Smarkm } else if (INFO_GATE(info)->sa_family != AF_INET) { 91546303Smarkm trace_act("note %s with gateway AF=%d", 91646303Smarkm rtm_type_name(rtm->rtm_type), 91746303Smarkm INFO_GATE(info)->sa_family); 91846303Smarkm k->k_metric = HOPCNT_INFINITY; 91946303Smarkm } else { 92046303Smarkm k->k_gate = S_ADDR(INFO_GATE(info)); 92146303Smarkm k->k_metric = rtm->rtm_rmx.rmx_hopcount; 92246303Smarkm if (k->k_metric < 0) 92346303Smarkm k->k_metric = 0; 92446303Smarkm else if (k->k_metric > HOPCNT_INFINITY-1) 92546303Smarkm k->k_metric = HOPCNT_INFINITY-1; 92646303Smarkm } 92746303Smarkm k->k_state &= ~(KS_DELETE | KS_ADD | KS_CHANGE | KS_DEL_ADD 92846303Smarkm | KS_DELETED | KS_GATEWAY | KS_STATIC 92946303Smarkm | KS_NEW | KS_CHECK); 93018316Swollman if (rtm->rtm_flags & RTF_GATEWAY) 93118316Swollman k->k_state |= KS_GATEWAY; 93218316Swollman if (rtm->rtm_flags & RTF_STATIC) 93318316Swollman k->k_state |= KS_STATIC; 93418316Swollman 93518316Swollman if (0 != (rtm->rtm_flags & (RTF_DYNAMIC | RTF_MODIFIED))) { 93620342Swollman if (INFO_AUTHOR(info) != 0 93720342Swollman && INFO_AUTHOR(info)->sa_family == AF_INET) 93820342Swollman ifp = iflookup(S_ADDR(INFO_AUTHOR(info))); 93920342Swollman else 94020342Swollman ifp = 0; 94120342Swollman if (supplier 94220342Swollman && (ifp == 0 || !(ifp->int_state & IS_REDIRECT_OK))) { 94318316Swollman /* Routers are not supposed to listen to redirects, 94420342Swollman * so delete it if it came via an unknown interface 94520342Swollman * or the interface does not have special permission. 94618316Swollman */ 94718316Swollman k->k_state &= ~KS_DYNAMIC; 94818316Swollman k->k_state |= KS_DELETE; 94918316Swollman LIM_SEC(need_kern, 0); 95020342Swollman trace_act("mark for deletion redirected %s --> %s" 95120342Swollman " via %s", 95218316Swollman addrname(k->k_dst, k->k_mask, 0), 95320342Swollman naddr_ntoa(k->k_gate), 95420342Swollman ifp ? ifp->int_name : "unknown interface"); 95518316Swollman } else { 95618316Swollman k->k_state |= KS_DYNAMIC; 95718316Swollman k->k_redirect_time = now.tv_sec; 95820342Swollman trace_act("accept redirected %s --> %s via %s", 95920342Swollman addrname(k->k_dst, k->k_mask, 0), 96020342Swollman naddr_ntoa(k->k_gate), 96120342Swollman ifp ? ifp->int_name : "unknown interface"); 96218316Swollman } 96318316Swollman return; 96418316Swollman } 96518316Swollman 96618316Swollman /* If it is not a static route, quit until the next comparison 96718316Swollman * between the kernel and daemon tables, when it will be deleted. 96818316Swollman */ 96918316Swollman if (!(k->k_state & KS_STATIC)) { 97018316Swollman k->k_state |= KS_DELETE; 97118316Swollman LIM_SEC(need_kern, k->k_keep); 97218316Swollman return; 97318316Swollman } 97418316Swollman 97518316Swollman /* Put static routes with real metrics into the daemon table so 97618316Swollman * they can be advertised. 97718316Swollman * 97819885Swollman * Find the interface toward the gateway. 97918316Swollman */ 98018316Swollman ifp = iflookup(k->k_gate); 98120342Swollman if (ifp == 0) 98220342Swollman msglog("static route %s --> %s impossibly lacks ifp", 98320342Swollman addrname(S_ADDR(INFO_DST(info)), mask, 0), 98420342Swollman naddr_ntoa(k->k_gate)); 98518316Swollman 98618316Swollman kern_check_static(k, ifp); 98718316Swollman} 98818316Swollman 98918316Swollman 99018316Swollman/* deal with packet loss 99118316Swollman */ 99218316Swollmanstatic void 99318316Swollmanrtm_lose(struct rt_msghdr *rtm, 99418316Swollman struct rt_addrinfo *info) 99518316Swollman{ 99618316Swollman if (INFO_GATE(info) == 0 99718316Swollman || INFO_GATE(info)->sa_family != AF_INET) { 99820342Swollman trace_act("ignore %s without gateway", 99920342Swollman rtm_type_name(rtm->rtm_type)); 100018316Swollman return; 100118316Swollman } 100218316Swollman 100346303Smarkm if (rdisc_ok) 100418316Swollman rdisc_age(S_ADDR(INFO_GATE(info))); 100518316Swollman age(S_ADDR(INFO_GATE(info))); 100618316Swollman} 100718316Swollman 100818316Swollman 100946303Smarkm/* Make the gateway slot of an info structure point to something 101046303Smarkm * useful. If it is not already useful, but it specifies an interface, 101146303Smarkm * then fill in the sockaddr_in provided and point it there. 101246303Smarkm */ 101346303Smarkmstatic int 101446303Smarkmget_info_gate(struct sockaddr **sap, 101546303Smarkm struct sockaddr_in *sin) 101646303Smarkm{ 101746303Smarkm struct sockaddr_dl *sdl = (struct sockaddr_dl *)*sap; 101846303Smarkm struct interface *ifp; 101946303Smarkm 102046303Smarkm if (sdl == 0) 102146303Smarkm return 0; 102246303Smarkm if ((sdl)->sdl_family == AF_INET) 102346303Smarkm return 1; 102446303Smarkm if ((sdl)->sdl_family != AF_LINK) 102546303Smarkm return 0; 102646303Smarkm 102746303Smarkm ifp = ifwithindex(sdl->sdl_index, 1); 102846303Smarkm if (ifp == 0) 102946303Smarkm return 0; 103046303Smarkm 103146303Smarkm sin->sin_addr.s_addr = ifp->int_addr; 103246303Smarkm#ifdef _HAVE_SA_LEN 103346303Smarkm sin->sin_len = sizeof(*sin); 103446303Smarkm#endif 103546303Smarkm sin->sin_family = AF_INET; 103646303Smarkm *sap = (struct sockaddr*)sin; 103746303Smarkm 103846303Smarkm return 1; 103946303Smarkm} 104046303Smarkm 104146303Smarkm 104218316Swollman/* Clean the kernel table by copying it to the daemon image. 104318316Swollman * Eventually the daemon will delete any extra routes. 104418316Swollman */ 104518316Swollmanvoid 104618316Swollmanflush_kern(void) 104718316Swollman{ 104846303Smarkm static char *sysctl_buf; 104946303Smarkm static size_t sysctl_buf_size = 0; 105018316Swollman size_t needed; 105118316Swollman int mib[6]; 105246303Smarkm char *next, *lim; 105318316Swollman struct rt_msghdr *rtm; 105446303Smarkm struct sockaddr_in gate_sin; 105518316Swollman struct rt_addrinfo info; 105646303Smarkm int i; 105746303Smarkm struct khash *k; 105818316Swollman 105918316Swollman 106046303Smarkm for (i = 0; i < KHASH_SIZE; i++) { 106146303Smarkm for (k = khash_bins[i]; k != 0; k = k->k_next) { 106246303Smarkm k->k_state |= KS_CHECK; 106346303Smarkm } 106446303Smarkm } 106546303Smarkm 106618316Swollman mib[0] = CTL_NET; 106718316Swollman mib[1] = PF_ROUTE; 106818316Swollman mib[2] = 0; /* protocol */ 106918316Swollman mib[3] = 0; /* wildcard address family */ 107018316Swollman mib[4] = NET_RT_DUMP; 107118316Swollman mib[5] = 0; /* no flags */ 107246303Smarkm for (;;) { 107346303Smarkm if ((needed = sysctl_buf_size) != 0) { 107446303Smarkm if (sysctl(mib, 6, sysctl_buf,&needed, 0, 0) >= 0) 107546303Smarkm break; 107646303Smarkm if (errno != ENOMEM && errno != EFAULT) 107746303Smarkm BADERR(1,"flush_kern: sysctl(RT_DUMP)"); 107846303Smarkm free(sysctl_buf); 107946303Smarkm needed = 0; 108046303Smarkm } 108146303Smarkm if (sysctl(mib, 6, 0, &needed, 0, 0) < 0) 108246303Smarkm BADERR(1,"flush_kern: sysctl(RT_DUMP) estimate"); 108346303Smarkm /* Kludge around the habit of some systems, such as 108446303Smarkm * BSD/OS 3.1, to not admit how many routes are in the 108546303Smarkm * kernel, or at least to be quite wrong. 108646303Smarkm */ 108746303Smarkm needed += 50*(sizeof(*rtm)+5*sizeof(struct sockaddr)); 108846303Smarkm sysctl_buf = rtmalloc(sysctl_buf_size = needed, 108946303Smarkm "flush_kern sysctl(RT_DUMP)"); 109018316Swollman } 109146303Smarkm 109246303Smarkm lim = sysctl_buf + needed; 109346303Smarkm for (next = sysctl_buf; next < lim; next += rtm->rtm_msglen) { 109418316Swollman rtm = (struct rt_msghdr *)next; 109546303Smarkm if (rtm->rtm_msglen == 0) { 109646303Smarkm msglog("zero length kernel route at " 109746303Smarkm " %#lx in buffer %#lx before %#lx", 109846303Smarkm (u_long)rtm, (u_long)sysctl_buf, (u_long)lim); 109946303Smarkm break; 110046303Smarkm } 110118316Swollman 110218316Swollman rt_xaddrs(&info, 110318316Swollman (struct sockaddr *)(rtm+1), 110418316Swollman (struct sockaddr *)(next + rtm->rtm_msglen), 110518316Swollman rtm->rtm_addrs); 110618316Swollman 110718316Swollman if (INFO_DST(&info) == 0 110818316Swollman || INFO_DST(&info)->sa_family != AF_INET) 110918316Swollman continue; 111018316Swollman 111118316Swollman /* ignore ARP table entries on systems with a merged route 111218316Swollman * and ARP table. 111318316Swollman */ 111418316Swollman if (rtm->rtm_flags & RTF_LLINFO) 111518316Swollman continue; 111618316Swollman 111718316Swollman /* ignore multicast addresses 111818316Swollman */ 111918316Swollman if (IN_MULTICAST(ntohl(S_ADDR(INFO_DST(&info))))) 112018316Swollman continue; 112118316Swollman 112246303Smarkm if (!get_info_gate(&INFO_GATE(&info), &gate_sin)) 112346303Smarkm continue; 112446303Smarkm 112518316Swollman /* Note static routes and interface routes, and also 112618316Swollman * preload the image of the kernel table so that 112718316Swollman * we can later clean it, as well as avoid making 112818316Swollman * unneeded changes. Keep the old kernel routes for a 112918316Swollman * few seconds to allow a RIP or router-discovery 113018316Swollman * response to be heard. 113118316Swollman */ 113218316Swollman rtm_add(rtm,&info,MIN_WAITTIME); 113318316Swollman } 113446303Smarkm 113546303Smarkm for (i = 0; i < KHASH_SIZE; i++) { 113646303Smarkm for (k = khash_bins[i]; k != 0; k = k->k_next) { 113746303Smarkm if (k->k_state & KS_CHECK) { 113846303Smarkm msglog("%s --> %s disappeared from kernel", 113946303Smarkm addrname(k->k_dst, k->k_mask, 0), 114046303Smarkm naddr_ntoa(k->k_gate)); 114146303Smarkm del_static(k->k_dst, k->k_mask, k->k_gate, 1); 114246303Smarkm } 114346303Smarkm } 114446303Smarkm } 114518316Swollman} 114618316Swollman 114718316Swollman 114818316Swollman/* Listen to announcements from the kernel 114918316Swollman */ 115018316Swollmanvoid 115118316Swollmanread_rt(void) 115218316Swollman{ 115318316Swollman long cc; 115418316Swollman struct interface *ifp; 115546303Smarkm struct sockaddr_in gate_sin; 115646303Smarkm naddr mask, gate; 115718316Swollman union { 115818316Swollman struct { 115918316Swollman struct rt_msghdr rtm; 116018316Swollman struct sockaddr addrs[RTAX_MAX]; 116118316Swollman } r; 116218316Swollman struct if_msghdr ifm; 116318316Swollman } m; 116418316Swollman char str[100], *strp; 116518316Swollman struct rt_addrinfo info; 116618316Swollman 116718316Swollman 116818316Swollman for (;;) { 116918316Swollman cc = read(rt_sock, &m, sizeof(m)); 117018316Swollman if (cc <= 0) { 117118316Swollman if (cc < 0 && errno != EWOULDBLOCK) 117218316Swollman LOGERR("read(rt_sock)"); 117318316Swollman return; 117418316Swollman } 117518316Swollman 117618316Swollman if (m.r.rtm.rtm_version != RTM_VERSION) { 117718316Swollman msglog("bogus routing message version %d", 117818316Swollman m.r.rtm.rtm_version); 117918316Swollman continue; 118018316Swollman } 118118316Swollman 118218316Swollman /* Ignore our own results. 118318316Swollman */ 118418316Swollman if (m.r.rtm.rtm_type <= RTM_CHANGE 118518316Swollman && m.r.rtm.rtm_pid == mypid) { 118618316Swollman static int complained = 0; 118718316Swollman if (!complained) { 118818316Swollman msglog("receiving our own change messages"); 118918316Swollman complained = 1; 119018316Swollman } 119118316Swollman continue; 119218316Swollman } 119318316Swollman 119418316Swollman if (m.r.rtm.rtm_type == RTM_IFINFO 119518316Swollman || m.r.rtm.rtm_type == RTM_NEWADDR 119618316Swollman || m.r.rtm.rtm_type == RTM_DELADDR) { 119746303Smarkm ifp = ifwithindex(m.ifm.ifm_index, 119846303Smarkm m.r.rtm.rtm_type != RTM_DELADDR); 119918316Swollman if (ifp == 0) 120018316Swollman trace_act("note %s with flags %#x" 120146303Smarkm " for unknown interface index #%d", 120218316Swollman rtm_type_name(m.r.rtm.rtm_type), 120318316Swollman m.ifm.ifm_flags, 120418316Swollman m.ifm.ifm_index); 120518316Swollman else 120619885Swollman trace_act("note %s with flags %#x for %s", 120718316Swollman rtm_type_name(m.r.rtm.rtm_type), 120818316Swollman m.ifm.ifm_flags, 120918316Swollman ifp->int_name); 121018316Swollman 121118316Swollman /* After being informed of a change to an interface, 121218316Swollman * check them all now if the check would otherwise 121318316Swollman * be a long time from now, if the interface is 121418316Swollman * not known, or if the interface has been turned 121518316Swollman * off or on. 121618316Swollman */ 121718316Swollman if (ifinit_timer.tv_sec-now.tv_sec>=CHECK_BAD_INTERVAL 121818316Swollman || ifp == 0 121918316Swollman || ((ifp->int_if_flags ^ m.ifm.ifm_flags) 122046303Smarkm & IFF_UP) != 0) 122118316Swollman ifinit_timer.tv_sec = now.tv_sec; 122218316Swollman continue; 122318316Swollman } 122418316Swollman 122518316Swollman strcpy(str, rtm_type_name(m.r.rtm.rtm_type)); 122618316Swollman strp = &str[strlen(str)]; 122718316Swollman if (m.r.rtm.rtm_type <= RTM_CHANGE) 122818316Swollman strp += sprintf(strp," from pid %d",m.r.rtm.rtm_pid); 122918316Swollman 123018316Swollman rt_xaddrs(&info, m.r.addrs, &m.r.addrs[RTAX_MAX], 123118316Swollman m.r.rtm.rtm_addrs); 123218316Swollman 123318316Swollman if (INFO_DST(&info) == 0) { 123419885Swollman trace_act("ignore %s without dst", str); 123518316Swollman continue; 123618316Swollman } 123718316Swollman 123818316Swollman if (INFO_DST(&info)->sa_family != AF_INET) { 123919885Swollman trace_act("ignore %s for AF %d", str, 124018316Swollman INFO_DST(&info)->sa_family); 124118316Swollman continue; 124218316Swollman } 124318316Swollman 124418316Swollman mask = ((INFO_MASK(&info) != 0) 124518316Swollman ? ntohl(S_ADDR(INFO_MASK(&info))) 124618316Swollman : (m.r.rtm.rtm_flags & RTF_HOST) 124718316Swollman ? HOST_MASK 124818316Swollman : std_mask(S_ADDR(INFO_DST(&info)))); 124918316Swollman 125018316Swollman strp += sprintf(strp, ": %s", 125118316Swollman addrname(S_ADDR(INFO_DST(&info)), mask, 0)); 125218316Swollman 125318316Swollman if (IN_MULTICAST(ntohl(S_ADDR(INFO_DST(&info))))) { 125419885Swollman trace_act("ignore multicast %s", str); 125518316Swollman continue; 125618316Swollman } 125718316Swollman 125846303Smarkm if (m.r.rtm.rtm_flags & RTF_LLINFO) { 125946303Smarkm trace_act("ignore ARP %s", str); 126046303Smarkm continue; 126146303Smarkm } 126218316Swollman 126346303Smarkm if (get_info_gate(&INFO_GATE(&info), &gate_sin)) { 126446303Smarkm gate = S_ADDR(INFO_GATE(&info)); 126546303Smarkm strp += sprintf(strp, " --> %s", naddr_ntoa(gate)); 126646303Smarkm } else { 126746303Smarkm gate = 0; 126846303Smarkm } 126946303Smarkm 127018316Swollman if (INFO_AUTHOR(&info) != 0) 127118316Swollman strp += sprintf(strp, " by authority of %s", 127218316Swollman saddr_ntoa(INFO_AUTHOR(&info))); 127318316Swollman 127418316Swollman switch (m.r.rtm.rtm_type) { 127518316Swollman case RTM_ADD: 127618316Swollman case RTM_CHANGE: 127718316Swollman case RTM_REDIRECT: 127818316Swollman if (m.r.rtm.rtm_errno != 0) { 127919885Swollman trace_act("ignore %s with \"%s\" error", 128018316Swollman str, strerror(m.r.rtm.rtm_errno)); 128118316Swollman } else { 128219885Swollman trace_act("%s", str); 128318316Swollman rtm_add(&m.r.rtm,&info,0); 128418316Swollman } 128518316Swollman break; 128618316Swollman 128718316Swollman case RTM_DELETE: 128846303Smarkm if (m.r.rtm.rtm_errno != 0 128946303Smarkm && m.r.rtm.rtm_errno != ESRCH) { 129019885Swollman trace_act("ignore %s with \"%s\" error", 129118316Swollman str, strerror(m.r.rtm.rtm_errno)); 129218316Swollman } else { 129319885Swollman trace_act("%s", str); 129446303Smarkm del_static(S_ADDR(INFO_DST(&info)), mask, 129546303Smarkm gate, 1); 129618316Swollman } 129718316Swollman break; 129818316Swollman 129918316Swollman case RTM_LOSING: 130019885Swollman trace_act("%s", str); 130118316Swollman rtm_lose(&m.r.rtm,&info); 130218316Swollman break; 130318316Swollman 130418316Swollman default: 130519885Swollman trace_act("ignore %s", str); 130618316Swollman break; 130718316Swollman } 130818316Swollman } 130918316Swollman} 131018316Swollman 131118316Swollman 131218316Swollman/* after aggregating, note routes that belong in the kernel 131318316Swollman */ 131418316Swollmanstatic void 131518316Swollmankern_out(struct ag_info *ag) 131618316Swollman{ 131718316Swollman struct khash *k; 131818316Swollman 131918316Swollman 132018316Swollman /* Do not install bad routes if they are not already present. 132118316Swollman * This includes routes that had RS_NET_SYN for interfaces that 132218316Swollman * recently died. 132318316Swollman */ 132418316Swollman if (ag->ag_metric == HOPCNT_INFINITY) { 132518316Swollman k = kern_find(htonl(ag->ag_dst_h), ag->ag_mask, 0); 132618316Swollman if (k == 0) 132718316Swollman return; 132818316Swollman } else { 132918316Swollman k = kern_add(htonl(ag->ag_dst_h), ag->ag_mask); 133018316Swollman } 133118316Swollman 133218316Swollman if (k->k_state & KS_NEW) { 133318316Swollman /* will need to add new entry to the kernel table */ 133418316Swollman k->k_state = KS_ADD; 133518316Swollman if (ag->ag_state & AGS_GATEWAY) 133618316Swollman k->k_state |= KS_GATEWAY; 133718316Swollman k->k_gate = ag->ag_gate; 133818316Swollman k->k_metric = ag->ag_metric; 133918316Swollman return; 134018316Swollman } 134118316Swollman 134218316Swollman if (k->k_state & KS_STATIC) 134318316Swollman return; 134418316Swollman 134518316Swollman /* modify existing kernel entry if necessary */ 134618316Swollman if (k->k_gate != ag->ag_gate 134718316Swollman || k->k_metric != ag->ag_metric) { 134846303Smarkm /* Must delete bad interface routes etc. to change them. */ 134946303Smarkm if (k->k_metric == HOPCNT_INFINITY) 135046303Smarkm k->k_state |= KS_DEL_ADD; 135118316Swollman k->k_gate = ag->ag_gate; 135218316Swollman k->k_metric = ag->ag_metric; 135318316Swollman k->k_state |= KS_CHANGE; 135418316Swollman } 135518316Swollman 135646303Smarkm /* If the daemon thinks the route should exist, forget 135746303Smarkm * about any redirections. 135846303Smarkm * If the daemon thinks the route should exist, eventually 135946303Smarkm * override manual intervention by the operator. 136046303Smarkm */ 136146303Smarkm if ((k->k_state & (KS_DYNAMIC | KS_DELETED)) != 0) { 136218316Swollman k->k_state &= ~KS_DYNAMIC; 136318316Swollman k->k_state |= (KS_ADD | KS_DEL_ADD); 136418316Swollman } 136518316Swollman 136618316Swollman if ((k->k_state & KS_GATEWAY) 136718316Swollman && !(ag->ag_state & AGS_GATEWAY)) { 136818316Swollman k->k_state &= ~KS_GATEWAY; 136918316Swollman k->k_state |= (KS_ADD | KS_DEL_ADD); 137018316Swollman } else if (!(k->k_state & KS_GATEWAY) 137118316Swollman && (ag->ag_state & AGS_GATEWAY)) { 137218316Swollman k->k_state |= KS_GATEWAY; 137318316Swollman k->k_state |= (KS_ADD | KS_DEL_ADD); 137418316Swollman } 137518316Swollman 137618316Swollman /* Deleting-and-adding is necessary to change aspects of a route. 137718316Swollman * Just delete instead of deleting and then adding a bad route. 137818316Swollman * Otherwise, we want to keep the route in the kernel. 137918316Swollman */ 138018316Swollman if (k->k_metric == HOPCNT_INFINITY 138118316Swollman && (k->k_state & KS_DEL_ADD)) 138218316Swollman k->k_state |= KS_DELETE; 138318316Swollman else 138418316Swollman k->k_state &= ~KS_DELETE; 138518316Swollman#undef RT 138618316Swollman} 138718316Swollman 138818316Swollman 138918316Swollman/* ARGSUSED */ 139018316Swollmanstatic int 139118316Swollmanwalk_kern(struct radix_node *rn, 139246303Smarkm struct walkarg *argp UNUSED) 139318316Swollman{ 139418316Swollman#define RT ((struct rt_entry *)rn) 139518316Swollman char metric, pref; 139618316Swollman u_int ags = 0; 139718316Swollman 139818316Swollman 139918316Swollman /* Do not install synthetic routes */ 140018316Swollman if (RT->rt_state & RS_NET_SYN) 140118316Swollman return 0; 140218316Swollman 140318316Swollman if (!(RT->rt_state & RS_IF)) { 140446303Smarkm /* This is an ordinary route, not for an interface. 140546303Smarkm */ 140618316Swollman 140746303Smarkm /* aggregate, ordinary good routes without regard to 140846303Smarkm * their metric 140946303Smarkm */ 141046303Smarkm pref = 1; 141146303Smarkm ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_AGGREGATE); 141246303Smarkm 141346303Smarkm /* Do not install host routes directly to hosts, to avoid 141446303Smarkm * interfering with ARP entries in the kernel table. 141546303Smarkm */ 141646303Smarkm if (RT_ISHOST(RT) 141746303Smarkm && ntohl(RT->rt_dst) == RT->rt_gate) 141846303Smarkm return 0; 141946303Smarkm 142018316Swollman } else { 142146303Smarkm /* This is an interface route. 142246303Smarkm * Do not install routes for "external" remote interfaces. 142318316Swollman */ 142418316Swollman if (RT->rt_ifp != 0 && (RT->rt_ifp->int_state & IS_EXTERNAL)) 142518316Swollman return 0; 142618316Swollman 142746303Smarkm /* Interfaces should override received routes. 142846303Smarkm */ 142946303Smarkm pref = 0; 143046303Smarkm ags |= (AGS_IF | AGS_CORS_GATE); 143118316Swollman 143218316Swollman /* If it is not an interface, or an alias for an interface, 143318316Swollman * it must be a "gateway." 143418316Swollman * 143518316Swollman * If it is a "remote" interface, it is also a "gateway" to 143618316Swollman * the kernel if is not a alias. 143718316Swollman */ 143818316Swollman if (RT->rt_ifp == 0 143919885Swollman || (RT->rt_ifp->int_state & IS_REMOTE)) 144046303Smarkm ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_AGGREGATE); 144118316Swollman } 144218316Swollman 144346303Smarkm /* If RIP is off and IRDP is on, let the route to the discovered 144446303Smarkm * route suppress any RIP routes. Eventually the RIP routes 144546303Smarkm * will time-out and be deleted. This reaches the steady-state 144646303Smarkm * quicker. 144746303Smarkm */ 144846303Smarkm if ((RT->rt_state & RS_RDISC) && rip_sock < 0) 144918316Swollman ags |= AGS_CORS_GATE; 145018316Swollman 145118316Swollman metric = RT->rt_metric; 145218316Swollman if (metric == HOPCNT_INFINITY) { 145318316Swollman /* if the route is dead, so try hard to aggregate. */ 145418316Swollman pref = HOPCNT_INFINITY; 145518316Swollman ags |= (AGS_FINE_GATE | AGS_SUPPRESS); 145646303Smarkm ags &= ~(AGS_IF | AGS_CORS_GATE); 145718316Swollman } 145818316Swollman 145918316Swollman ag_check(RT->rt_dst, RT->rt_mask, RT->rt_gate, 0, 146018316Swollman metric,pref, 0, 0, ags, kern_out); 146118316Swollman return 0; 146218316Swollman#undef RT 146318316Swollman} 146418316Swollman 146518316Swollman 146618316Swollman/* Update the kernel table to match the daemon table. 146718316Swollman */ 146818316Swollmanstatic void 146918316Swollmanfix_kern(void) 147018316Swollman{ 147146303Smarkm int i; 147218316Swollman struct khash *k, **pk; 147318316Swollman 147418316Swollman 147518316Swollman need_kern = age_timer; 147618316Swollman 147718316Swollman /* Walk daemon table, updating the copy of the kernel table. 147818316Swollman */ 147918316Swollman (void)rn_walktree(rhead, walk_kern, 0); 148018316Swollman ag_flush(0,0,kern_out); 148118316Swollman 148218316Swollman for (i = 0; i < KHASH_SIZE; i++) { 148318316Swollman for (pk = &khash_bins[i]; (k = *pk) != 0; ) { 148418316Swollman /* Do not touch static routes */ 148518316Swollman if (k->k_state & KS_STATIC) { 148618316Swollman kern_check_static(k,0); 148718316Swollman pk = &k->k_next; 148818316Swollman continue; 148918316Swollman } 149018316Swollman 149118316Swollman /* check hold on routes deleted by the operator */ 149218316Swollman if (k->k_keep > now.tv_sec) { 149346303Smarkm /* ensure we check when the hold is over */ 149418316Swollman LIM_SEC(need_kern, k->k_keep); 149546303Smarkm /* mark for the next cycle */ 149618316Swollman k->k_state |= KS_DELETE; 149718316Swollman pk = &k->k_next; 149818316Swollman continue; 149918316Swollman } 150018316Swollman 150146303Smarkm if ((k->k_state & KS_DELETE) 150246303Smarkm && !(k->k_state & KS_DYNAMIC)) { 150346303Smarkm kern_ioctl(k, RTM_DELETE, 0); 150418316Swollman *pk = k->k_next; 150518316Swollman free(k); 150618316Swollman continue; 150718316Swollman } 150818316Swollman 150946303Smarkm if (k->k_state & KS_DEL_ADD) 151046303Smarkm kern_ioctl(k, RTM_DELETE, 0); 151118316Swollman 151246303Smarkm if (k->k_state & KS_ADD) { 151346303Smarkm kern_ioctl(k, RTM_ADD, 151446303Smarkm ((0 != (k->k_state & (KS_GATEWAY 151546303Smarkm | KS_DYNAMIC))) 151646303Smarkm ? RTF_GATEWAY : 0)); 151746303Smarkm } else if (k->k_state & KS_CHANGE) { 151846303Smarkm kern_ioctl(k, RTM_CHANGE, 151946303Smarkm ((0 != (k->k_state & (KS_GATEWAY 152046303Smarkm | KS_DYNAMIC))) 152146303Smarkm ? RTF_GATEWAY : 0)); 152218316Swollman } 152346303Smarkm k->k_state &= ~(KS_ADD|KS_CHANGE|KS_DEL_ADD); 152418316Swollman 152518316Swollman /* Mark this route to be deleted in the next cycle. 152618316Swollman * This deletes routes that disappear from the 152718316Swollman * daemon table, since the normal aging code 152818316Swollman * will clear the bit for routes that have not 152918316Swollman * disappeared from the daemon table. 153018316Swollman */ 153118316Swollman k->k_state |= KS_DELETE; 153218316Swollman pk = &k->k_next; 153318316Swollman } 153418316Swollman } 153518316Swollman} 153618316Swollman 153718316Swollman 153818316Swollman/* Delete a static route in the image of the kernel table. 153918316Swollman */ 154018316Swollmanvoid 154118316Swollmandel_static(naddr dst, 154218316Swollman naddr mask, 154346303Smarkm naddr gate, 154418316Swollman int gone) 154518316Swollman{ 154618316Swollman struct khash *k; 154718316Swollman struct rt_entry *rt; 154818316Swollman 154918316Swollman /* Just mark it in the table to be deleted next time the kernel 155018316Swollman * table is updated. 155118316Swollman * If it has already been deleted, mark it as such, and set its 155218316Swollman * keep-timer so that it will not be deleted again for a while. 155318316Swollman * This lets the operator delete a route added by the daemon 155418316Swollman * and add a replacement. 155518316Swollman */ 155618316Swollman k = kern_find(dst, mask, 0); 155746303Smarkm if (k != 0 && (gate == 0 || k->k_gate == gate)) { 155846303Smarkm k->k_state &= ~(KS_STATIC | KS_DYNAMIC | KS_CHECK); 155918316Swollman k->k_state |= KS_DELETE; 156018316Swollman if (gone) { 156118316Swollman k->k_state |= KS_DELETED; 156218316Swollman k->k_keep = now.tv_sec + K_KEEP_LIM; 156318316Swollman } 156418316Swollman } 156518316Swollman 156618316Swollman rt = rtget(dst, mask); 156718316Swollman if (rt != 0 && (rt->rt_state & RS_STATIC)) 156818316Swollman rtbad(rt); 156918316Swollman} 157018316Swollman 157118316Swollman 157218316Swollman/* Delete all routes generated from ICMP Redirects that use a given gateway, 157318316Swollman * as well as old redirected routes. 157418316Swollman */ 157518316Swollmanvoid 157618316Swollmandel_redirects(naddr bad_gate, 157718316Swollman time_t old) 157818316Swollman{ 157918316Swollman int i; 158018316Swollman struct khash *k; 158118316Swollman 158218316Swollman 158318316Swollman for (i = 0; i < KHASH_SIZE; i++) { 158418316Swollman for (k = khash_bins[i]; k != 0; k = k->k_next) { 158518316Swollman if (!(k->k_state & KS_DYNAMIC) 158618316Swollman || (k->k_state & KS_STATIC)) 158718316Swollman continue; 158818316Swollman 158918316Swollman if (k->k_gate != bad_gate 159018316Swollman && k->k_redirect_time > old 159118316Swollman && !supplier) 159218316Swollman continue; 159318316Swollman 159418316Swollman k->k_state |= KS_DELETE; 159518316Swollman k->k_state &= ~KS_DYNAMIC; 159618316Swollman need_kern.tv_sec = now.tv_sec; 159719885Swollman trace_act("mark redirected %s --> %s for deletion", 159818316Swollman addrname(k->k_dst, k->k_mask, 0), 159918316Swollman naddr_ntoa(k->k_gate)); 160018316Swollman } 160118316Swollman } 160218316Swollman} 160318316Swollman 160418316Swollman 160518316Swollman/* Start the daemon tables. 160618316Swollman */ 160746303Smarkmextern int max_keylen; 160846303Smarkm 160918316Swollmanvoid 161018316Swollmanrtinit(void) 161118316Swollman{ 161218316Swollman int i; 161318316Swollman struct ag_info *ag; 161418316Swollman 161518316Swollman /* Initialize the radix trees */ 161618316Swollman max_keylen = sizeof(struct sockaddr_in); 161718316Swollman rn_init(); 161818316Swollman rn_inithead((void**)&rhead, 32); 161918316Swollman 162018316Swollman /* mark all of the slots in the table free */ 162118316Swollman ag_avail = ag_slots; 162218316Swollman for (ag = ag_slots, i = 1; i < NUM_AG_SLOTS; i++) { 162318316Swollman ag->ag_fine = ag+1; 162418316Swollman ag++; 162518316Swollman } 162618316Swollman} 162718316Swollman 162818316Swollman 162918316Swollman#ifdef _HAVE_SIN_LEN 163064131Ssheldonhstatic struct sockaddr_in dst_sock = {sizeof(dst_sock), AF_INET, 0, {0}, {0}}; 163164131Ssheldonhstatic struct sockaddr_in mask_sock = {sizeof(mask_sock), AF_INET, 0, {0}, {0}}; 163218316Swollman#else 163318316Swollmanstatic struct sockaddr_in_new dst_sock = {_SIN_ADDR_SIZE, AF_INET}; 163418316Swollmanstatic struct sockaddr_in_new mask_sock = {_SIN_ADDR_SIZE, AF_INET}; 163518316Swollman#endif 163618316Swollman 163718316Swollman 163846303Smarkmstatic void 163918316Swollmanset_need_flash(void) 164018316Swollman{ 164118316Swollman if (!need_flash) { 164218316Swollman need_flash = 1; 164318316Swollman /* Do not send the flash update immediately. Wait a little 164418316Swollman * while to hear from other routers. 164518316Swollman */ 164618316Swollman no_flash.tv_sec = now.tv_sec + MIN_WAITTIME; 164718316Swollman } 164818316Swollman} 164918316Swollman 165018316Swollman 165118316Swollman/* Get a particular routing table entry 165218316Swollman */ 165318316Swollmanstruct rt_entry * 165418316Swollmanrtget(naddr dst, naddr mask) 165518316Swollman{ 165618316Swollman struct rt_entry *rt; 165718316Swollman 165818316Swollman dst_sock.sin_addr.s_addr = dst; 165964131Ssheldonh mask_sock.sin_addr.s_addr = htonl(mask); 166018316Swollman masktrim(&mask_sock); 166118316Swollman rt = (struct rt_entry *)rhead->rnh_lookup(&dst_sock,&mask_sock,rhead); 166218316Swollman if (!rt 166318316Swollman || rt->rt_dst != dst 166418316Swollman || rt->rt_mask != mask) 166518316Swollman return 0; 166618316Swollman 166718316Swollman return rt; 166818316Swollman} 166918316Swollman 167018316Swollman 167118316Swollman/* Find a route to dst as the kernel would. 167218316Swollman */ 167318316Swollmanstruct rt_entry * 167418316Swollmanrtfind(naddr dst) 167518316Swollman{ 167618316Swollman dst_sock.sin_addr.s_addr = dst; 167718316Swollman return (struct rt_entry *)rhead->rnh_matchaddr(&dst_sock, rhead); 167818316Swollman} 167918316Swollman 168018316Swollman 168118316Swollman/* add a route to the table 168218316Swollman */ 168318316Swollmanvoid 168418316Swollmanrtadd(naddr dst, 168518316Swollman naddr mask, 168646303Smarkm u_int state, /* rt_state for the entry */ 168746303Smarkm struct rt_spare *new) 168818316Swollman{ 168918316Swollman struct rt_entry *rt; 169018316Swollman naddr smask; 169118316Swollman int i; 169218316Swollman struct rt_spare *rts; 169318316Swollman 169418316Swollman rt = (struct rt_entry *)rtmalloc(sizeof (*rt), "rtadd"); 169546303Smarkm memset(rt, 0, sizeof(*rt)); 169618316Swollman for (rts = rt->rt_spares, i = NUM_SPARES; i != 0; i--, rts++) 169718316Swollman rts->rts_metric = HOPCNT_INFINITY; 169818316Swollman 169918316Swollman rt->rt_nodes->rn_key = (caddr_t)&rt->rt_dst_sock; 170018316Swollman rt->rt_dst = dst; 170118316Swollman rt->rt_dst_sock.sin_family = AF_INET; 170218316Swollman#ifdef _HAVE_SIN_LEN 170318316Swollman rt->rt_dst_sock.sin_len = dst_sock.sin_len; 170418316Swollman#endif 170518316Swollman if (mask != HOST_MASK) { 170618316Swollman smask = std_mask(dst); 170718316Swollman if ((smask & ~mask) == 0 && mask > smask) 170818316Swollman state |= RS_SUBNET; 170918316Swollman } 171064131Ssheldonh mask_sock.sin_addr.s_addr = htonl(mask); 171118316Swollman masktrim(&mask_sock); 171218316Swollman rt->rt_mask = mask; 171318316Swollman rt->rt_state = state; 171446303Smarkm rt->rt_spares[0] = *new; 171518316Swollman rt->rt_time = now.tv_sec; 171618316Swollman rt->rt_poison_metric = HOPCNT_INFINITY; 171718316Swollman rt->rt_seqno = update_seqno; 171818316Swollman 171918316Swollman if (++total_routes == MAX_ROUTES) 172018316Swollman msglog("have maximum (%d) routes", total_routes); 172118316Swollman if (TRACEACTIONS) 172218316Swollman trace_add_del("Add", rt); 172318316Swollman 172418316Swollman need_kern.tv_sec = now.tv_sec; 172518316Swollman set_need_flash(); 172618316Swollman 172718316Swollman if (0 == rhead->rnh_addaddr(&rt->rt_dst_sock, &mask_sock, 172818316Swollman rhead, rt->rt_nodes)) { 172946303Smarkm msglog("rnh_addaddr() failed for %s mask=%#lx", 173046303Smarkm naddr_ntoa(dst), (u_long)mask); 173161186Sjlemon free(rt); 173218316Swollman } 173318316Swollman} 173418316Swollman 173518316Swollman 173618316Swollman/* notice a changed route 173718316Swollman */ 173818316Swollmanvoid 173918316Swollmanrtchange(struct rt_entry *rt, 174018316Swollman u_int state, /* new state bits */ 174146303Smarkm struct rt_spare *new, 174218316Swollman char *label) 174318316Swollman{ 174446303Smarkm if (rt->rt_metric != new->rts_metric) { 174518316Swollman /* Fix the kernel immediately if it seems the route 174618316Swollman * has gone bad, since there may be a working route that 174718316Swollman * aggregates this route. 174818316Swollman */ 174946303Smarkm if (new->rts_metric == HOPCNT_INFINITY) { 175018316Swollman need_kern.tv_sec = now.tv_sec; 175146303Smarkm if (new->rts_time >= now.tv_sec - EXPIRE_TIME) 175246303Smarkm new->rts_time = now.tv_sec - EXPIRE_TIME; 175318316Swollman } 175418316Swollman rt->rt_seqno = update_seqno; 175518316Swollman set_need_flash(); 175618316Swollman } 175718316Swollman 175846303Smarkm if (rt->rt_gate != new->rts_gate) { 175918316Swollman need_kern.tv_sec = now.tv_sec; 176018316Swollman rt->rt_seqno = update_seqno; 176118316Swollman set_need_flash(); 176218316Swollman } 176318316Swollman 176418316Swollman state |= (rt->rt_state & RS_SUBNET); 176518316Swollman 176618316Swollman /* Keep various things from deciding ageless routes are stale. 176718316Swollman */ 176846303Smarkm if (!AGE_RT(state, new->rts_ifp)) 176946303Smarkm new->rts_time = now.tv_sec; 177018316Swollman 177118316Swollman if (TRACEACTIONS) 177246303Smarkm trace_change(rt, state, new, 177318316Swollman label ? label : "Chg "); 177418316Swollman 177518316Swollman rt->rt_state = state; 177646303Smarkm rt->rt_spares[0] = *new; 177718316Swollman} 177818316Swollman 177918316Swollman 178018316Swollman/* check for a better route among the spares 178118316Swollman */ 178218316Swollmanstatic struct rt_spare * 178318316Swollmanrts_better(struct rt_entry *rt) 178418316Swollman{ 178518316Swollman struct rt_spare *rts, *rts1; 178618316Swollman int i; 178718316Swollman 178818316Swollman /* find the best alternative among the spares */ 178918316Swollman rts = rt->rt_spares+1; 179018316Swollman for (i = NUM_SPARES, rts1 = rts+1; i > 2; i--, rts1++) { 179118316Swollman if (BETTER_LINK(rt,rts1,rts)) 179218316Swollman rts = rts1; 179318316Swollman } 179418316Swollman 179518316Swollman return rts; 179618316Swollman} 179718316Swollman 179818316Swollman 179918316Swollman/* switch to a backup route 180018316Swollman */ 180118316Swollmanvoid 180218316Swollmanrtswitch(struct rt_entry *rt, 180318316Swollman struct rt_spare *rts) 180418316Swollman{ 180518316Swollman struct rt_spare swap; 180618316Swollman char label[10]; 180718316Swollman 180818316Swollman 180918316Swollman /* Do not change permanent routes */ 181018316Swollman if (0 != (rt->rt_state & (RS_MHOME | RS_STATIC | RS_RDISC 181118316Swollman | RS_NET_SYN | RS_IF))) 181218316Swollman return; 181318316Swollman 181418316Swollman /* find the best alternative among the spares */ 181518316Swollman if (rts == 0) 181618316Swollman rts = rts_better(rt); 181718316Swollman 181818316Swollman /* Do not bother if it is not worthwhile. 181918316Swollman */ 182018316Swollman if (!BETTER_LINK(rt, rts, rt->rt_spares)) 182118316Swollman return; 182218316Swollman 182318316Swollman swap = rt->rt_spares[0]; 182446303Smarkm (void)sprintf(label, "Use #%d", (int)(rts - rt->rt_spares)); 182546303Smarkm rtchange(rt, rt->rt_state & ~(RS_NET_SYN | RS_RDISC), rts, label); 182646303Smarkm if (swap.rts_metric == HOPCNT_INFINITY) { 182746303Smarkm *rts = rts_empty; 182846303Smarkm } else { 182946303Smarkm *rts = swap; 183046303Smarkm } 183118316Swollman} 183218316Swollman 183318316Swollman 183418316Swollmanvoid 183518316Swollmanrtdelete(struct rt_entry *rt) 183618316Swollman{ 183718316Swollman struct khash *k; 183818316Swollman 183918316Swollman 184018316Swollman if (TRACEACTIONS) 184118316Swollman trace_add_del("Del", rt); 184218316Swollman 184318316Swollman k = kern_find(rt->rt_dst, rt->rt_mask, 0); 184418316Swollman if (k != 0) { 184518316Swollman k->k_state |= KS_DELETE; 184618316Swollman need_kern.tv_sec = now.tv_sec; 184718316Swollman } 184818316Swollman 184918316Swollman dst_sock.sin_addr.s_addr = rt->rt_dst; 185064131Ssheldonh mask_sock.sin_addr.s_addr = htonl(rt->rt_mask); 185118316Swollman masktrim(&mask_sock); 185218316Swollman if (rt != (struct rt_entry *)rhead->rnh_deladdr(&dst_sock, &mask_sock, 185318316Swollman rhead)) { 185418316Swollman msglog("rnh_deladdr() failed"); 185518316Swollman } else { 185618316Swollman free(rt); 185718316Swollman total_routes--; 185818316Swollman } 185918316Swollman} 186018316Swollman 186118316Swollman 186246303Smarkmvoid 186346303Smarkmrts_delete(struct rt_entry *rt, 186446303Smarkm struct rt_spare *rts) 186546303Smarkm{ 186646303Smarkm trace_upslot(rt, rts, &rts_empty); 186746303Smarkm *rts = rts_empty; 186846303Smarkm} 186946303Smarkm 187046303Smarkm 187118316Swollman/* Get rid of a bad route, and try to switch to a replacement. 187218316Swollman */ 187318316Swollmanvoid 187418316Swollmanrtbad(struct rt_entry *rt) 187518316Swollman{ 187646303Smarkm struct rt_spare new; 187746303Smarkm 187818316Swollman /* Poison the route */ 187946303Smarkm new = rt->rt_spares[0]; 188046303Smarkm new.rts_metric = HOPCNT_INFINITY; 188146303Smarkm rtchange(rt, rt->rt_state & ~(RS_IF | RS_LOCAL | RS_STATIC), &new, 0); 188218316Swollman rtswitch(rt, 0); 188318316Swollman} 188418316Swollman 188518316Swollman 188618316Swollman/* Junk a RS_NET_SYN or RS_LOCAL route, 188718316Swollman * unless it is needed by another interface. 188818316Swollman */ 188918316Swollmanvoid 189018316Swollmanrtbad_sub(struct rt_entry *rt) 189118316Swollman{ 189218316Swollman struct interface *ifp, *ifp1; 189318316Swollman struct intnet *intnetp; 189418316Swollman u_int state; 189518316Swollman 189618316Swollman 189718316Swollman ifp1 = 0; 189818316Swollman state = 0; 189918316Swollman 190018316Swollman if (rt->rt_state & RS_LOCAL) { 190118316Swollman /* Is this the route through loopback for the interface? 190218316Swollman * If so, see if it is used by any other interfaces, such 190318316Swollman * as a point-to-point interface with the same local address. 190418316Swollman */ 190518316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 190618316Swollman /* Retain it if another interface needs it. 190718316Swollman */ 190818316Swollman if (ifp->int_addr == rt->rt_ifp->int_addr) { 190918316Swollman state |= RS_LOCAL; 191018316Swollman ifp1 = ifp; 191118316Swollman break; 191218316Swollman } 191318316Swollman } 191418316Swollman 191518316Swollman } 191618316Swollman 191718316Swollman if (!(state & RS_LOCAL)) { 191818316Swollman /* Retain RIPv1 logical network route if there is another 191918316Swollman * interface that justifies it. 192018316Swollman */ 192118316Swollman if (rt->rt_state & RS_NET_SYN) { 192218316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 192318316Swollman if ((ifp->int_state & IS_NEED_NET_SYN) 192418316Swollman && rt->rt_mask == ifp->int_std_mask 192518316Swollman && rt->rt_dst == ifp->int_std_addr) { 192618316Swollman state |= RS_NET_SYN; 192718316Swollman ifp1 = ifp; 192818316Swollman break; 192918316Swollman } 193018316Swollman } 193118316Swollman } 193218316Swollman 193318316Swollman /* or if there is an authority route that needs it. */ 193418316Swollman for (intnetp = intnets; 193518316Swollman intnetp != 0; 193618316Swollman intnetp = intnetp->intnet_next) { 193718316Swollman if (intnetp->intnet_addr == rt->rt_dst 193818316Swollman && intnetp->intnet_mask == rt->rt_mask) { 193918316Swollman state |= (RS_NET_SYN | RS_NET_INT); 194018316Swollman break; 194118316Swollman } 194218316Swollman } 194318316Swollman } 194418316Swollman 194518316Swollman if (ifp1 != 0 || (state & RS_NET_SYN)) { 194646303Smarkm struct rt_spare new = rt->rt_spares[0]; 194746303Smarkm new.rts_ifp = ifp1; 194846303Smarkm rtchange(rt, ((rt->rt_state & ~(RS_NET_SYN|RS_LOCAL)) | state), 194946303Smarkm &new, 0); 195018316Swollman } else { 195118316Swollman rtbad(rt); 195218316Swollman } 195318316Swollman} 195418316Swollman 195518316Swollman 195618316Swollman/* Called while walking the table looking for sick interfaces 195718316Swollman * or after a time change. 195818316Swollman */ 195918316Swollman/* ARGSUSED */ 196018316Swollmanint 196118316Swollmanwalk_bad(struct radix_node *rn, 196246303Smarkm struct walkarg *argp UNUSED) 196318316Swollman{ 196418316Swollman#define RT ((struct rt_entry *)rn) 196518316Swollman struct rt_spare *rts; 196618316Swollman int i; 196718316Swollman 196818316Swollman 196918316Swollman /* fix any spare routes through the interface 197018316Swollman */ 197118316Swollman rts = RT->rt_spares; 197218316Swollman for (i = NUM_SPARES; i != 1; i--) { 197318316Swollman rts++; 197446303Smarkm if (rts->rts_metric < HOPCNT_INFINITY 197546303Smarkm && (rts->rts_ifp == 0 197646303Smarkm || (rts->rts_ifp->int_state & IS_BROKE))) 197746303Smarkm rts_delete(RT, rts); 197818316Swollman } 197918316Swollman 198018316Swollman /* Deal with the main route 198118316Swollman */ 198218316Swollman /* finished if it has been handled before or if its interface is ok 198318316Swollman */ 198418316Swollman if (RT->rt_ifp == 0 || !(RT->rt_ifp->int_state & IS_BROKE)) 198518316Swollman return 0; 198618316Swollman 198718316Swollman /* Bad routes for other than interfaces are easy. 198818316Swollman */ 198918316Swollman if (0 == (RT->rt_state & (RS_IF | RS_NET_SYN | RS_LOCAL))) { 199018316Swollman rtbad(RT); 199118316Swollman return 0; 199218316Swollman } 199318316Swollman 199418316Swollman rtbad_sub(RT); 199518316Swollman return 0; 199618316Swollman#undef RT 199718316Swollman} 199818316Swollman 199918316Swollman 200018316Swollman/* Check the age of an individual route. 200118316Swollman */ 200218316Swollman/* ARGSUSED */ 200318316Swollmanstatic int 200418316Swollmanwalk_age(struct radix_node *rn, 200546303Smarkm struct walkarg *argp UNUSED) 200618316Swollman{ 200718316Swollman#define RT ((struct rt_entry *)rn) 200818316Swollman struct interface *ifp; 200918316Swollman struct rt_spare *rts; 201018316Swollman int i; 201118316Swollman 201218316Swollman 201318316Swollman /* age all of the spare routes, including the primary route 201418316Swollman * currently in use 201518316Swollman */ 201618316Swollman rts = RT->rt_spares; 201718316Swollman for (i = NUM_SPARES; i != 0; i--, rts++) { 201818316Swollman 201918316Swollman ifp = rts->rts_ifp; 202018316Swollman if (i == NUM_SPARES) { 202118316Swollman if (!AGE_RT(RT->rt_state, ifp)) { 202218316Swollman /* Keep various things from deciding ageless 202318316Swollman * routes are stale 202418316Swollman */ 202518316Swollman rts->rts_time = now.tv_sec; 202618316Swollman continue; 202718316Swollman } 202818316Swollman 202918316Swollman /* forget RIP routes after RIP has been turned off. 203018316Swollman */ 203118316Swollman if (rip_sock < 0) { 203218316Swollman rtdelete(RT); 203318316Swollman return 0; 203418316Swollman } 203518316Swollman } 203618316Swollman 203718316Swollman /* age failing routes 203818316Swollman */ 203918316Swollman if (age_bad_gate == rts->rts_gate 204018316Swollman && rts->rts_time >= now_stale) { 204118316Swollman rts->rts_time -= SUPPLY_INTERVAL; 204218316Swollman } 204318316Swollman 204418316Swollman /* trash the spare routes when they go bad */ 204518316Swollman if (rts->rts_metric < HOPCNT_INFINITY 204646303Smarkm && now_garbage > rts->rts_time 204746303Smarkm && i != NUM_SPARES) 204846303Smarkm rts_delete(RT, rts); 204918316Swollman } 205018316Swollman 205118316Swollman 205218316Swollman /* finished if the active route is still fresh */ 205318316Swollman if (now_stale <= RT->rt_time) 205418316Swollman return 0; 205518316Swollman 205618316Swollman /* try to switch to an alternative */ 205718316Swollman rtswitch(RT, 0); 205818316Swollman 205918316Swollman /* Delete a dead route after it has been publically mourned. */ 206018316Swollman if (now_garbage > RT->rt_time) { 206118316Swollman rtdelete(RT); 206218316Swollman return 0; 206318316Swollman } 206418316Swollman 206518316Swollman /* Start poisoning a bad route before deleting it. */ 206646303Smarkm if (now.tv_sec - RT->rt_time > EXPIRE_TIME) { 206746303Smarkm struct rt_spare new = RT->rt_spares[0]; 206846303Smarkm new.rts_metric = HOPCNT_INFINITY; 206946303Smarkm rtchange(RT, RT->rt_state, &new, 0); 207046303Smarkm } 207118316Swollman return 0; 207218316Swollman} 207318316Swollman 207418316Swollman 207518316Swollman/* Watch for dead routes and interfaces. 207618316Swollman */ 207718316Swollmanvoid 207818316Swollmanage(naddr bad_gate) 207918316Swollman{ 208018316Swollman struct interface *ifp; 208119885Swollman int need_query = 0; 208218316Swollman 208319885Swollman /* If not listening to RIP, there is no need to age the routes in 208419885Swollman * the table. 208519885Swollman */ 208619885Swollman age_timer.tv_sec = (now.tv_sec 208719885Swollman + ((rip_sock < 0) ? NEVER : SUPPLY_INTERVAL)); 208818316Swollman 208919885Swollman /* Check for dead IS_REMOTE interfaces by timing their 209019885Swollman * transmissions. 209119885Swollman */ 209219885Swollman for (ifp = ifnet; ifp; ifp = ifp->int_next) { 209319885Swollman if (!(ifp->int_state & IS_REMOTE)) 209419885Swollman continue; 209518316Swollman 209619885Swollman /* ignore unreachable remote interfaces */ 209719885Swollman if (!check_remote(ifp)) 209819885Swollman continue; 209946303Smarkm 210019885Swollman /* Restore remote interface that has become reachable 210118316Swollman */ 210219885Swollman if (ifp->int_state & IS_BROKE) 210319885Swollman if_ok(ifp, "remote "); 210418316Swollman 210519885Swollman if (ifp->int_act_time != NEVER 210619885Swollman && now.tv_sec - ifp->int_act_time > EXPIRE_TIME) { 210719885Swollman msglog("remote interface %s to %s timed out after" 210846303Smarkm " %ld:%ld", 210919885Swollman ifp->int_name, 211019885Swollman naddr_ntoa(ifp->int_dstaddr), 211119885Swollman (now.tv_sec - ifp->int_act_time)/60, 211219885Swollman (now.tv_sec - ifp->int_act_time)%60); 211319885Swollman if_sick(ifp); 211418316Swollman } 211519885Swollman 211619885Swollman /* If we have not heard from the other router 211719885Swollman * recently, ask it. 211819885Swollman */ 211919885Swollman if (now.tv_sec >= ifp->int_query_time) { 212019885Swollman ifp->int_query_time = NEVER; 212119885Swollman need_query = 1; 212219885Swollman } 212318316Swollman } 212418316Swollman 212518316Swollman /* Age routes. */ 212618316Swollman age_bad_gate = bad_gate; 212718316Swollman (void)rn_walktree(rhead, walk_age, 0); 212818316Swollman 212946303Smarkm /* delete old redirected routes to keep the kernel table small 213046303Smarkm * and prevent blackholes 213146303Smarkm */ 213246303Smarkm del_redirects(bad_gate, now.tv_sec-STALE_TIME); 213346303Smarkm 213418316Swollman /* Update the kernel routing table. */ 213518316Swollman fix_kern(); 213619885Swollman 213719885Swollman /* poke reticent remote gateways */ 213819885Swollman if (need_query) 213919885Swollman rip_query(); 214018316Swollman} 2141