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: releng/10.3/sbin/routed/table.c 229778 2012-01-07 16:09:33Z uqs $ 3018316Swollman */ 3118316Swollman 3246303Smarkm#include "defs.h" 3346303Smarkm 34126250Sbms#ifdef __NetBSD__ 3546303Smarkm__RCSID("$NetBSD$"); 36126250Sbms#elif defined(__FreeBSD__) 37126250Sbms__RCSID("$FreeBSD: releng/10.3/sbin/routed/table.c 229778 2012-01-07 16:09:33Z uqs $"); 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 51190715Sphkstatic void rtbad(struct rt_entry *); 5218316Swollman 5346303Smarkm 5418316Swollmanstruct radix_node_head *rhead; /* root of the radix tree */ 5518316Swollman 5618316Swollmanint need_flash = 1; /* flash update needed 5718316Swollman * start =1 to suppress the 1st 5818316Swollman */ 5918316Swollman 6018316Swollmanstruct timeval age_timer; /* next check of old routes */ 6118316Swollmanstruct timeval need_kern = { /* need to update kernel table */ 6264131Ssheldonh EPOCH+MIN_WAITTIME-1, 0 6318316Swollman}; 6418316Swollman 6518316Swollmanint stopint; 6618316Swollman 6718316Swollmanint total_routes; 6818316Swollman 6919885Swollman/* zap any old routes through this gateway */ 70190715Sphkstatic naddr age_bad_gate; 7118316Swollman 7218316Swollman 7318316Swollman/* It is desirable to "aggregate" routes, to combine differing routes of 7418316Swollman * the same metric and next hop into a common route with a smaller netmask 7518316Swollman * or to suppress redundant routes, routes that add no information to 7618316Swollman * routes with smaller netmasks. 7718316Swollman * 7818316Swollman * A route is redundant if and only if any and all routes with smaller 7918316Swollman * but matching netmasks and nets are the same. Since routes are 8018316Swollman * kept sorted in the radix tree, redundant routes always come second. 8118316Swollman * 8218316Swollman * There are two kinds of aggregations. First, two routes of the same bit 8318316Swollman * mask and differing only in the least significant bit of the network 8418316Swollman * number can be combined into a single route with a coarser mask. 8518316Swollman * 8618316Swollman * Second, a route can be suppressed in favor of another route with a more 8718316Swollman * coarse mask provided no incompatible routes with intermediate masks 8818316Swollman * are present. The second kind of aggregation involves suppressing routes. 8918316Swollman * A route must not be suppressed if an incompatible route exists with 9018316Swollman * an intermediate mask, since the suppressed route would be covered 9118316Swollman * by the intermediate. 9218316Swollman * 9318316Swollman * This code relies on the radix tree walk encountering routes 9418316Swollman * sorted first by address, with the smallest address first. 9518316Swollman */ 9618316Swollman 97190715Sphkstatic struct ag_info ag_slots[NUM_AG_SLOTS], *ag_avail, *ag_corsest, *ag_finest; 9818316Swollman 9918316Swollman/* #define DEBUG_AG */ 10018316Swollman#ifdef DEBUG_AG 10118316Swollman#define CHECK_AG() {int acnt = 0; struct ag_info *cag; \ 10218316Swollman for (cag = ag_avail; cag != 0; cag = cag->ag_fine) \ 10318316Swollman acnt++; \ 10418316Swollman for (cag = ag_corsest; cag != 0; cag = cag->ag_fine) \ 10518316Swollman acnt++; \ 10618316Swollman if (acnt != NUM_AG_SLOTS) { \ 10718316Swollman (void)fflush(stderr); \ 10818316Swollman abort(); \ 10918316Swollman } \ 11018316Swollman} 11118316Swollman#else 11218316Swollman#define CHECK_AG() 11318316Swollman#endif 11418316Swollman 11518316Swollman 11618316Swollman/* Output the contents of an aggregation table slot. 11718316Swollman * This function must always be immediately followed with the deletion 11818316Swollman * of the target slot. 11918316Swollman */ 12018316Swollmanstatic void 12118316Swollmanag_out(struct ag_info *ag, 12218316Swollman void (*out)(struct ag_info *)) 12318316Swollman{ 12418316Swollman struct ag_info *ag_cors; 12518316Swollman naddr bit; 12618316Swollman 12718316Swollman 12846303Smarkm /* Forget it if this route should not be output for split-horizon. */ 12946303Smarkm if (ag->ag_state & AGS_SPLIT_HZ) 13046303Smarkm return; 13146303Smarkm 13218316Swollman /* If we output both the even and odd twins, then the immediate parent, 13318316Swollman * if it is present, is redundant, unless the parent manages to 13418316Swollman * aggregate into something coarser. 13518316Swollman * On successive calls, this code detects the even and odd twins, 13618316Swollman * and marks the parent. 13718316Swollman * 13818316Swollman * Note that the order in which the radix tree code emits routes 13918316Swollman * ensures that the twins are seen before the parent is emitted. 14018316Swollman */ 14118316Swollman ag_cors = ag->ag_cors; 14218316Swollman if (ag_cors != 0 14318316Swollman && ag_cors->ag_mask == ag->ag_mask<<1 14418316Swollman && ag_cors->ag_dst_h == (ag->ag_dst_h & ag_cors->ag_mask)) { 14518316Swollman ag_cors->ag_state |= ((ag_cors->ag_dst_h == ag->ag_dst_h) 14618316Swollman ? AGS_REDUN0 14718316Swollman : AGS_REDUN1); 14818316Swollman } 14918316Swollman 15018316Swollman /* Skip it if this route is itself redundant. 15118316Swollman * 15218316Swollman * It is ok to change the contents of the slot here, since it is 15318316Swollman * always deleted next. 15418316Swollman */ 15518316Swollman if (ag->ag_state & AGS_REDUN0) { 15618316Swollman if (ag->ag_state & AGS_REDUN1) 15746303Smarkm return; /* quit if fully redundant */ 15846303Smarkm /* make it finer if it is half-redundant */ 15918316Swollman bit = (-ag->ag_mask) >> 1; 16018316Swollman ag->ag_dst_h |= bit; 16118316Swollman ag->ag_mask |= bit; 16218316Swollman 16318316Swollman } else if (ag->ag_state & AGS_REDUN1) { 16446303Smarkm /* make it finer if it is half-redundant */ 16518316Swollman bit = (-ag->ag_mask) >> 1; 16618316Swollman ag->ag_mask |= bit; 16718316Swollman } 16818316Swollman out(ag); 16918316Swollman} 17018316Swollman 17118316Swollman 17218316Swollmanstatic void 17318316Swollmanag_del(struct ag_info *ag) 17418316Swollman{ 17518316Swollman CHECK_AG(); 17618316Swollman 17718316Swollman if (ag->ag_cors == 0) 17818316Swollman ag_corsest = ag->ag_fine; 17918316Swollman else 18018316Swollman ag->ag_cors->ag_fine = ag->ag_fine; 18118316Swollman 18218316Swollman if (ag->ag_fine == 0) 18318316Swollman ag_finest = ag->ag_cors; 18418316Swollman else 18518316Swollman ag->ag_fine->ag_cors = ag->ag_cors; 18618316Swollman 18718316Swollman ag->ag_fine = ag_avail; 18818316Swollman ag_avail = ag; 18918316Swollman 19018316Swollman CHECK_AG(); 19118316Swollman} 19218316Swollman 19318316Swollman 19437908Scharnier/* Flush routes waiting for aggregation. 19518316Swollman * This must not suppress a route unless it is known that among all 19618316Swollman * routes with coarser masks that match it, the one with the longest 19718316Swollman * mask is appropriate. This is ensured by scanning the routes 19837908Scharnier * in lexical order, and with the most restrictive mask first 19918316Swollman * among routes to the same destination. 20018316Swollman */ 20118316Swollmanvoid 20218316Swollmanag_flush(naddr lim_dst_h, /* flush routes to here */ 20318316Swollman naddr lim_mask, /* matching this mask */ 20418316Swollman void (*out)(struct ag_info *)) 20518316Swollman{ 20618316Swollman struct ag_info *ag, *ag_cors; 20718316Swollman naddr dst_h; 20818316Swollman 20918316Swollman 21018316Swollman for (ag = ag_finest; 21118316Swollman ag != 0 && ag->ag_mask >= lim_mask; 21218316Swollman ag = ag_cors) { 21318316Swollman ag_cors = ag->ag_cors; 21418316Swollman 21518316Swollman /* work on only the specified routes */ 21618316Swollman dst_h = ag->ag_dst_h; 21718316Swollman if ((dst_h & lim_mask) != lim_dst_h) 21818316Swollman continue; 21918316Swollman 22018316Swollman if (!(ag->ag_state & AGS_SUPPRESS)) 22118316Swollman ag_out(ag, out); 22218316Swollman 22318316Swollman else for ( ; ; ag_cors = ag_cors->ag_cors) { 22418316Swollman /* Look for a route that can suppress the 22518316Swollman * current route */ 22618316Swollman if (ag_cors == 0) { 22718316Swollman /* failed, so output it and look for 22818316Swollman * another route to work on 22918316Swollman */ 23018316Swollman ag_out(ag, out); 23118316Swollman break; 23218316Swollman } 23318316Swollman 23418316Swollman if ((dst_h & ag_cors->ag_mask) == ag_cors->ag_dst_h) { 23518316Swollman /* We found a route with a coarser mask that 23618316Swollman * aggregates the current target. 23718316Swollman * 23818316Swollman * If it has a different next hop, it 23918316Swollman * cannot replace the target, so output 24018316Swollman * the target. 24118316Swollman */ 24218316Swollman if (ag->ag_gate != ag_cors->ag_gate 24318316Swollman && !(ag->ag_state & AGS_FINE_GATE) 24418316Swollman && !(ag_cors->ag_state & AGS_CORS_GATE)) { 24518316Swollman ag_out(ag, out); 24618316Swollman break; 24718316Swollman } 24818316Swollman 24918316Swollman /* If the coarse route has a good enough 25018316Swollman * metric, it suppresses the target. 25146303Smarkm * If the suppressed target was redundant, 25246303Smarkm * then mark the suppressor redundant. 25318316Swollman */ 25418316Swollman if (ag_cors->ag_pref <= ag->ag_pref) { 25518316Swollman if (AG_IS_REDUN(ag->ag_state) 25618316Swollman && ag_cors->ag_mask==ag->ag_mask<<1) { 25718316Swollman if (ag_cors->ag_dst_h == dst_h) 25818316Swollman ag_cors->ag_state |= AGS_REDUN0; 25918316Swollman else 26018316Swollman ag_cors->ag_state |= AGS_REDUN1; 26118316Swollman } 26218316Swollman if (ag->ag_tag != ag_cors->ag_tag) 26318316Swollman ag_cors->ag_tag = 0; 26418316Swollman if (ag->ag_nhop != ag_cors->ag_nhop) 26518316Swollman ag_cors->ag_nhop = 0; 26618316Swollman break; 26718316Swollman } 26818316Swollman } 26918316Swollman } 27018316Swollman 27118316Swollman /* That route has either been output or suppressed */ 27218316Swollman ag_cors = ag->ag_cors; 27318316Swollman ag_del(ag); 27418316Swollman } 27518316Swollman 27618316Swollman CHECK_AG(); 27718316Swollman} 27818316Swollman 27918316Swollman 28018316Swollman/* Try to aggregate a route with previous routes. 28118316Swollman */ 28218316Swollmanvoid 28318316Swollmanag_check(naddr dst, 28418316Swollman naddr mask, 28518316Swollman naddr gate, 28618316Swollman naddr nhop, 28718316Swollman char metric, 28818316Swollman char pref, 289126250Sbms u_int new_seqno, 29018316Swollman u_short tag, 29118316Swollman u_short state, 29218316Swollman void (*out)(struct ag_info *)) /* output using this */ 29318316Swollman{ 29418316Swollman struct ag_info *ag, *nag, *ag_cors; 29518316Swollman naddr xaddr; 29618316Swollman int x; 29718316Swollman 29890868Smike dst = ntohl(dst); 29918316Swollman 30018316Swollman /* Punt non-contiguous subnet masks. 30118316Swollman * 30218316Swollman * (X & -X) contains a single bit if and only if X is a power of 2. 30318316Swollman * (X + (X & -X)) == 0 if and only if X is a power of 2. 30418316Swollman */ 30518316Swollman if ((mask & -mask) + mask != 0) { 30618316Swollman struct ag_info nc_ag; 30718316Swollman 30818316Swollman nc_ag.ag_dst_h = dst; 30918316Swollman nc_ag.ag_mask = mask; 31018316Swollman nc_ag.ag_gate = gate; 31118316Swollman nc_ag.ag_nhop = nhop; 31218316Swollman nc_ag.ag_metric = metric; 31318316Swollman nc_ag.ag_pref = pref; 31418316Swollman nc_ag.ag_tag = tag; 31518316Swollman nc_ag.ag_state = state; 316126250Sbms nc_ag.ag_seqno = new_seqno; 31718316Swollman out(&nc_ag); 31818316Swollman return; 31918316Swollman } 32018316Swollman 32118316Swollman /* Search for the right slot in the aggregation table. 32218316Swollman */ 32318316Swollman ag_cors = 0; 32418316Swollman ag = ag_corsest; 32518316Swollman while (ag != 0) { 32618316Swollman if (ag->ag_mask >= mask) 32718316Swollman break; 32818316Swollman 32918316Swollman /* Suppress old routes (i.e. combine with compatible routes 33018316Swollman * with coarser masks) as we look for the right slot in the 33118316Swollman * aggregation table for the new route. 33218316Swollman * A route to an address less than the current destination 33318316Swollman * will not be affected by the current route or any route 33418316Swollman * seen hereafter. That means it is safe to suppress it. 33537908Scharnier * This check keeps poor routes (e.g. with large hop counts) 33637908Scharnier * from preventing suppression of finer routes. 33718316Swollman */ 33818316Swollman if (ag_cors != 0 33918316Swollman && ag->ag_dst_h < dst 34018316Swollman && (ag->ag_state & AGS_SUPPRESS) 34118316Swollman && ag_cors->ag_pref <= ag->ag_pref 34218316Swollman && (ag->ag_dst_h & ag_cors->ag_mask) == ag_cors->ag_dst_h 34318316Swollman && (ag_cors->ag_gate == ag->ag_gate 34418316Swollman || (ag->ag_state & AGS_FINE_GATE) 34518316Swollman || (ag_cors->ag_state & AGS_CORS_GATE))) { 34646303Smarkm /* If the suppressed target was redundant, 34746303Smarkm * then mark the suppressor redundant. 34846303Smarkm */ 34918316Swollman if (AG_IS_REDUN(ag->ag_state) 35064131Ssheldonh && ag_cors->ag_mask == ag->ag_mask<<1) { 35118316Swollman if (ag_cors->ag_dst_h == dst) 35218316Swollman ag_cors->ag_state |= AGS_REDUN0; 35318316Swollman else 35418316Swollman ag_cors->ag_state |= AGS_REDUN1; 35518316Swollman } 35618316Swollman if (ag->ag_tag != ag_cors->ag_tag) 35718316Swollman ag_cors->ag_tag = 0; 35818316Swollman if (ag->ag_nhop != ag_cors->ag_nhop) 35918316Swollman ag_cors->ag_nhop = 0; 36018316Swollman ag_del(ag); 36118316Swollman CHECK_AG(); 36218316Swollman } else { 36318316Swollman ag_cors = ag; 36418316Swollman } 36518316Swollman ag = ag_cors->ag_fine; 36618316Swollman } 36718316Swollman 36818316Swollman /* If we find the even/odd twin of the new route, and if the 36918316Swollman * masks and so forth are equal, we can aggregate them. 37018316Swollman * We can probably promote one of the pair. 37118316Swollman * 37218316Swollman * Since the routes are encountered in lexical order, 37318316Swollman * the new route must be odd. However, the second or later 37418316Swollman * times around this loop, it could be the even twin promoted 37518316Swollman * from the even/odd pair of twins of the finer route. 37618316Swollman */ 37718316Swollman while (ag != 0 37818316Swollman && ag->ag_mask == mask 37918316Swollman && ((ag->ag_dst_h ^ dst) & (mask<<1)) == 0) { 38018316Swollman 38118316Swollman /* Here we know the target route and the route in the current 38218316Swollman * slot have the same netmasks and differ by at most the 38318316Swollman * last bit. They are either for the same destination, or 38418316Swollman * for an even/odd pair of destinations. 38518316Swollman */ 38618316Swollman if (ag->ag_dst_h == dst) { 38718316Swollman /* We have two routes to the same destination. 38818316Swollman * Routes are encountered in lexical order, so a 38918316Swollman * route is never promoted until the parent route is 39018316Swollman * already present. So we know that the new route is 39146303Smarkm * a promoted (or aggregated) pair and the route 39246303Smarkm * already in the slot is the explicit route. 39318316Swollman * 39418316Swollman * Prefer the best route if their metrics differ, 39546303Smarkm * or the aggregated one if not, following a sort 39618316Swollman * of longest-match rule. 39718316Swollman */ 39818316Swollman if (pref <= ag->ag_pref) { 39918316Swollman ag->ag_gate = gate; 40018316Swollman ag->ag_nhop = nhop; 40118316Swollman ag->ag_tag = tag; 40218316Swollman ag->ag_metric = metric; 40318316Swollman ag->ag_pref = pref; 404126250Sbms if (ag->ag_seqno < new_seqno) 405126250Sbms ag->ag_seqno = new_seqno; 40618316Swollman x = ag->ag_state; 40718316Swollman ag->ag_state = state; 40818316Swollman state = x; 40918316Swollman } 41018316Swollman 41146303Smarkm /* Some bits are set if they are set on either route, 41246303Smarkm * except when the route is for an interface. 41346303Smarkm */ 41446303Smarkm if (!(ag->ag_state & AGS_IF)) 41546303Smarkm ag->ag_state |= (state & (AGS_AGGREGATE_EITHER 41646303Smarkm | AGS_REDUN0 41746303Smarkm | AGS_REDUN1)); 41818316Swollman return; 41918316Swollman } 42018316Swollman 42118316Swollman /* If one of the routes can be promoted and the other can 42218316Swollman * be suppressed, it may be possible to combine them or 42318316Swollman * worthwhile to promote one. 42418316Swollman * 42546303Smarkm * Any route that can be promoted is always 42618316Swollman * marked to be eligible to be suppressed. 42718316Swollman */ 42846303Smarkm if (!((state & AGS_AGGREGATE) 42918316Swollman && (ag->ag_state & AGS_SUPPRESS)) 43046303Smarkm && !((ag->ag_state & AGS_AGGREGATE) 43118316Swollman && (state & AGS_SUPPRESS))) 43218316Swollman break; 43318316Swollman 43418316Swollman /* A pair of even/odd twin routes can be combined 43518316Swollman * if either is redundant, or if they are via the 43618316Swollman * same gateway and have the same metric. 43718316Swollman */ 43818316Swollman if (AG_IS_REDUN(ag->ag_state) 43918316Swollman || AG_IS_REDUN(state) 44018316Swollman || (ag->ag_gate == gate 44118316Swollman && ag->ag_pref == pref 44246303Smarkm && (state & ag->ag_state & AGS_AGGREGATE) != 0)) { 44318316Swollman 44418316Swollman /* We have both the even and odd pairs. 44518316Swollman * Since the routes are encountered in order, 44618316Swollman * the route in the slot must be the even twin. 44718316Swollman * 44846303Smarkm * Combine and promote (aggregate) the pair of routes. 44918316Swollman */ 450126250Sbms if (new_seqno < ag->ag_seqno) 451126250Sbms new_seqno = ag->ag_seqno; 45218316Swollman if (!AG_IS_REDUN(state)) 45318316Swollman state &= ~AGS_REDUN1; 45418316Swollman if (AG_IS_REDUN(ag->ag_state)) 45518316Swollman state |= AGS_REDUN0; 45618316Swollman else 45718316Swollman state &= ~AGS_REDUN0; 45846303Smarkm state |= (ag->ag_state & AGS_AGGREGATE_EITHER); 45918316Swollman if (ag->ag_tag != tag) 46018316Swollman tag = 0; 46118316Swollman if (ag->ag_nhop != nhop) 46218316Swollman nhop = 0; 46318316Swollman 46418316Swollman /* Get rid of the even twin that was already 46518316Swollman * in the slot. 46618316Swollman */ 46718316Swollman ag_del(ag); 46818316Swollman 46918316Swollman } else if (ag->ag_pref >= pref 47046303Smarkm && (ag->ag_state & AGS_AGGREGATE)) { 47118316Swollman /* If we cannot combine the pair, maybe the route 47218316Swollman * with the worse metric can be promoted. 47318316Swollman * 47418316Swollman * Promote the old, even twin, by giving its slot 47518316Swollman * in the table to the new, odd twin. 47618316Swollman */ 47718316Swollman ag->ag_dst_h = dst; 47818316Swollman 47918316Swollman xaddr = ag->ag_gate; 48018316Swollman ag->ag_gate = gate; 48118316Swollman gate = xaddr; 48218316Swollman 48318316Swollman xaddr = ag->ag_nhop; 48418316Swollman ag->ag_nhop = nhop; 48518316Swollman nhop = xaddr; 48618316Swollman 48718316Swollman x = ag->ag_tag; 48818316Swollman ag->ag_tag = tag; 48918316Swollman tag = x; 49018316Swollman 49146303Smarkm /* The promoted route is even-redundant only if the 49246303Smarkm * even twin was fully redundant. It is not 49346303Smarkm * odd-redundant because the odd-twin will still be 49446303Smarkm * in the table. 49546303Smarkm */ 49618316Swollman x = ag->ag_state; 49746303Smarkm if (!AG_IS_REDUN(x)) 49846303Smarkm x &= ~AGS_REDUN0; 49946303Smarkm x &= ~AGS_REDUN1; 50018316Swollman ag->ag_state = state; 50118316Swollman state = x; 50218316Swollman 50318316Swollman x = ag->ag_metric; 50418316Swollman ag->ag_metric = metric; 50518316Swollman metric = x; 50618316Swollman 50718316Swollman x = ag->ag_pref; 50818316Swollman ag->ag_pref = pref; 50918316Swollman pref = x; 51018316Swollman 51146303Smarkm /* take the newest sequence number */ 512126250Sbms if (new_seqno <= ag->ag_seqno) 513126250Sbms new_seqno = ag->ag_seqno; 51418316Swollman else 515126250Sbms ag->ag_seqno = new_seqno; 51618316Swollman 51718316Swollman } else { 51846303Smarkm if (!(state & AGS_AGGREGATE)) 51918316Swollman break; /* cannot promote either twin */ 52018316Swollman 52146303Smarkm /* Promote the new, odd twin by shaving its 52218316Swollman * mask and address. 52346303Smarkm * The promoted route is odd-redundant only if the 52446303Smarkm * odd twin was fully redundant. It is not 52546303Smarkm * even-redundant because the even twin is still in 52646303Smarkm * the table. 52718316Swollman */ 52846303Smarkm if (!AG_IS_REDUN(state)) 52946303Smarkm state &= ~AGS_REDUN1; 53046303Smarkm state &= ~AGS_REDUN0; 531126250Sbms if (new_seqno < ag->ag_seqno) 532126250Sbms new_seqno = ag->ag_seqno; 53318316Swollman else 534126250Sbms ag->ag_seqno = new_seqno; 53518316Swollman } 53618316Swollman 53718316Swollman mask <<= 1; 53818316Swollman dst &= mask; 53918316Swollman 54018316Swollman if (ag_cors == 0) { 54118316Swollman ag = ag_corsest; 54218316Swollman break; 54318316Swollman } 54418316Swollman ag = ag_cors; 54518316Swollman ag_cors = ag->ag_cors; 54618316Swollman } 54718316Swollman 54818316Swollman /* When we can no longer promote and combine routes, 54918316Swollman * flush the old route in the target slot. Also flush 55018316Swollman * any finer routes that we know will never be aggregated by 55118316Swollman * the new route. 55218316Swollman * 55318316Swollman * In case we moved toward coarser masks, 55418316Swollman * get back where we belong 55518316Swollman */ 55618316Swollman if (ag != 0 55718316Swollman && ag->ag_mask < mask) { 55818316Swollman ag_cors = ag; 55918316Swollman ag = ag->ag_fine; 56018316Swollman } 56118316Swollman 56218316Swollman /* Empty the target slot 56318316Swollman */ 56418316Swollman if (ag != 0 && ag->ag_mask == mask) { 56518316Swollman ag_flush(ag->ag_dst_h, ag->ag_mask, out); 56618316Swollman ag = (ag_cors == 0) ? ag_corsest : ag_cors->ag_fine; 56718316Swollman } 56818316Swollman 56918316Swollman#ifdef DEBUG_AG 57018316Swollman (void)fflush(stderr); 57118316Swollman if (ag == 0 && ag_cors != ag_finest) 57218316Swollman abort(); 57318316Swollman if (ag_cors == 0 && ag != ag_corsest) 57418316Swollman abort(); 57518316Swollman if (ag != 0 && ag->ag_cors != ag_cors) 57618316Swollman abort(); 57718316Swollman if (ag_cors != 0 && ag_cors->ag_fine != ag) 57818316Swollman abort(); 57918316Swollman CHECK_AG(); 58018316Swollman#endif 58118316Swollman 58218316Swollman /* Save the new route on the end of the table. 58318316Swollman */ 58418316Swollman nag = ag_avail; 58518316Swollman ag_avail = nag->ag_fine; 58618316Swollman 58718316Swollman nag->ag_dst_h = dst; 58818316Swollman nag->ag_mask = mask; 58918316Swollman nag->ag_gate = gate; 59018316Swollman nag->ag_nhop = nhop; 59118316Swollman nag->ag_metric = metric; 59218316Swollman nag->ag_pref = pref; 59318316Swollman nag->ag_tag = tag; 59418316Swollman nag->ag_state = state; 595126250Sbms nag->ag_seqno = new_seqno; 59618316Swollman 59718316Swollman nag->ag_fine = ag; 59818316Swollman if (ag != 0) 59918316Swollman ag->ag_cors = nag; 60018316Swollman else 60118316Swollman ag_finest = nag; 60218316Swollman nag->ag_cors = ag_cors; 60318316Swollman if (ag_cors == 0) 60418316Swollman ag_corsest = nag; 60518316Swollman else 60618316Swollman ag_cors->ag_fine = nag; 60718316Swollman CHECK_AG(); 60818316Swollman} 60918316Swollman 61046303Smarkmstatic const char * 61118316Swollmanrtm_type_name(u_char type) 61218316Swollman{ 613190715Sphk static const char * const rtm_types[] = { 61418316Swollman "RTM_ADD", 61518316Swollman "RTM_DELETE", 61618316Swollman "RTM_CHANGE", 61718316Swollman "RTM_GET", 61818316Swollman "RTM_LOSING", 61918316Swollman "RTM_REDIRECT", 62018316Swollman "RTM_MISS", 62118316Swollman "RTM_LOCK", 62218316Swollman "RTM_OLDADD", 62318316Swollman "RTM_OLDDEL", 62418316Swollman "RTM_RESOLVE", 62518316Swollman "RTM_NEWADDR", 62618316Swollman "RTM_DELADDR", 627126250Sbms#ifdef RTM_OIFINFO 628126250Sbms "RTM_OIFINFO", 629126250Sbms#endif 63058821Sshin "RTM_IFINFO", 63158821Sshin "RTM_NEWMADDR", 63258821Sshin "RTM_DELMADDR" 63318316Swollman }; 63464483Ssheldonh#define NEW_RTM_PAT "RTM type %#x" 63564483Ssheldonh static char name0[sizeof(NEW_RTM_PAT)+2]; 63618316Swollman 63718316Swollman 63818316Swollman if (type > sizeof(rtm_types)/sizeof(rtm_types[0]) 63918316Swollman || type == 0) { 64064483Ssheldonh snprintf(name0, sizeof(name0), NEW_RTM_PAT, type); 64118316Swollman return name0; 64218316Swollman } else { 64318316Swollman return rtm_types[type-1]; 64418316Swollman } 64564483Ssheldonh#undef NEW_RTM_PAT 64618316Swollman} 64718316Swollman 64818316Swollman 64918316Swollman/* Trim a mask in a sockaddr 65046303Smarkm * Produce a length of 0 for an address of 0. 65146303Smarkm * Otherwise produce the index of the first zero byte. 65218316Swollman */ 65318316Swollmanvoid 65418316Swollman#ifdef _HAVE_SIN_LEN 65518316Swollmanmasktrim(struct sockaddr_in *ap) 65618316Swollman#else 65718316Swollmanmasktrim(struct sockaddr_in_new *ap) 65818316Swollman#endif 65918316Swollman{ 66046303Smarkm char *cp; 66118316Swollman 66246303Smarkm if (ap->sin_addr.s_addr == 0) { 66346303Smarkm ap->sin_len = 0; 66446303Smarkm return; 66546303Smarkm } 66618316Swollman cp = (char *)(&ap->sin_addr.s_addr+1); 66718316Swollman while (*--cp == 0) 66818316Swollman continue; 66918316Swollman ap->sin_len = cp - (char*)ap + 1; 67018316Swollman} 67118316Swollman 67218316Swollman 67318316Swollman/* Tell the kernel to add, delete or change a route 67418316Swollman */ 67518316Swollmanstatic void 67618316Swollmanrtioctl(int action, /* RTM_DELETE, etc */ 67718316Swollman naddr dst, 67818316Swollman naddr gate, 67918316Swollman naddr mask, 68018316Swollman int metric, 68118316Swollman int flags) 68218316Swollman{ 68318316Swollman struct { 68418316Swollman struct rt_msghdr w_rtm; 68518316Swollman struct sockaddr_in w_dst; 68618316Swollman struct sockaddr_in w_gate; 68718316Swollman#ifdef _HAVE_SA_LEN 68818316Swollman struct sockaddr_in w_mask; 68918316Swollman#else 69018316Swollman struct sockaddr_in_new w_mask; 69118316Swollman#endif 69218316Swollman } w; 69318316Swollman long cc; 69446303Smarkm# define PAT " %-10s %s metric=%d flags=%#x" 69546303Smarkm# define ARGS rtm_type_name(action), rtname(dst,mask,gate), metric, flags 69618316Swollman 69718316Swollmanagain: 69846303Smarkm memset(&w, 0, sizeof(w)); 69918316Swollman w.w_rtm.rtm_msglen = sizeof(w); 70018316Swollman w.w_rtm.rtm_version = RTM_VERSION; 70118316Swollman w.w_rtm.rtm_type = action; 70218316Swollman w.w_rtm.rtm_flags = flags; 70318316Swollman w.w_rtm.rtm_seq = ++rt_sock_seqno; 70418316Swollman w.w_rtm.rtm_addrs = RTA_DST|RTA_GATEWAY; 70546303Smarkm if (metric != 0 || action == RTM_CHANGE) { 70618316Swollman w.w_rtm.rtm_rmx.rmx_hopcount = metric; 70718316Swollman w.w_rtm.rtm_inits |= RTV_HOPCOUNT; 70818316Swollman } 70918316Swollman w.w_dst.sin_family = AF_INET; 71018316Swollman w.w_dst.sin_addr.s_addr = dst; 71118316Swollman w.w_gate.sin_family = AF_INET; 71218316Swollman w.w_gate.sin_addr.s_addr = gate; 71318316Swollman#ifdef _HAVE_SA_LEN 71418316Swollman w.w_dst.sin_len = sizeof(w.w_dst); 71518316Swollman w.w_gate.sin_len = sizeof(w.w_gate); 71618316Swollman#endif 71718316Swollman if (mask == HOST_MASK) { 71818316Swollman w.w_rtm.rtm_flags |= RTF_HOST; 71918316Swollman w.w_rtm.rtm_msglen -= sizeof(w.w_mask); 72018316Swollman } else { 72118316Swollman w.w_rtm.rtm_addrs |= RTA_NETMASK; 72218316Swollman w.w_mask.sin_addr.s_addr = htonl(mask); 72318316Swollman#ifdef _HAVE_SA_LEN 72418316Swollman masktrim(&w.w_mask); 72546303Smarkm if (w.w_mask.sin_len == 0) 72646303Smarkm w.w_mask.sin_len = sizeof(long); 72718316Swollman w.w_rtm.rtm_msglen -= (sizeof(w.w_mask) - w.w_mask.sin_len); 72818316Swollman#endif 72918316Swollman } 73018316Swollman 73118316Swollman#ifndef NO_INSTALL 73218316Swollman cc = write(rt_sock, &w, w.w_rtm.rtm_msglen); 73318316Swollman if (cc < 0) { 73418316Swollman if (errno == ESRCH 73518316Swollman && (action == RTM_CHANGE || action == RTM_DELETE)) { 73646303Smarkm trace_act("route disappeared before" PAT, ARGS); 73718316Swollman if (action == RTM_CHANGE) { 73818316Swollman action = RTM_ADD; 73918316Swollman goto again; 74018316Swollman } 74118316Swollman return; 74218316Swollman } 74346303Smarkm msglog("write(rt_sock)" PAT ": %s", ARGS, strerror(errno)); 74446303Smarkm return; 74546303Smarkm } else if (cc != w.w_rtm.rtm_msglen) { 74646303Smarkm msglog("write(rt_sock) wrote %ld instead of %d for" PAT, 74746303Smarkm cc, w.w_rtm.rtm_msglen, ARGS); 74846303Smarkm return; 74918316Swollman } 75018316Swollman#endif 75146303Smarkm if (TRACEKERNEL) 75246303Smarkm trace_misc("write kernel" PAT, ARGS); 75346303Smarkm#undef PAT 75446303Smarkm#undef ARGS 75518316Swollman} 75618316Swollman 75718316Swollman 75818316Swollman#define KHASH_SIZE 71 /* should be prime */ 75918316Swollman#define KHASH(a,m) khash_bins[((a) ^ (m)) % KHASH_SIZE] 76018316Swollmanstatic struct khash { 76118316Swollman struct khash *k_next; 76218316Swollman naddr k_dst; 76318316Swollman naddr k_mask; 76418316Swollman naddr k_gate; 76518316Swollman short k_metric; 76618316Swollman u_short k_state; 76718316Swollman#define KS_NEW 0x001 76846303Smarkm#define KS_DELETE 0x002 /* need to delete the route */ 76918316Swollman#define KS_ADD 0x004 /* add to the kernel */ 77018316Swollman#define KS_CHANGE 0x008 /* tell kernel to change the route */ 77118316Swollman#define KS_DEL_ADD 0x010 /* delete & add to change the kernel */ 77218316Swollman#define KS_STATIC 0x020 /* Static flag in kernel */ 77318316Swollman#define KS_GATEWAY 0x040 /* G flag in kernel */ 77418316Swollman#define KS_DYNAMIC 0x080 /* result of redirect */ 77546303Smarkm#define KS_DELETED 0x100 /* already deleted from kernel */ 77646303Smarkm#define KS_CHECK 0x200 77718316Swollman time_t k_keep; 77818316Swollman#define K_KEEP_LIM 30 77920342Swollman time_t k_redirect_time; /* when redirected route 1st seen */ 78018316Swollman} *khash_bins[KHASH_SIZE]; 78118316Swollman 78218316Swollman 78318316Swollmanstatic struct khash* 78418316Swollmankern_find(naddr dst, naddr mask, struct khash ***ppk) 78518316Swollman{ 78618316Swollman struct khash *k, **pk; 78718316Swollman 78818316Swollman for (pk = &KHASH(dst,mask); (k = *pk) != 0; pk = &k->k_next) { 78918316Swollman if (k->k_dst == dst && k->k_mask == mask) 79018316Swollman break; 79118316Swollman } 79218316Swollman if (ppk != 0) 79318316Swollman *ppk = pk; 79418316Swollman return k; 79518316Swollman} 79618316Swollman 79718316Swollman 79818316Swollmanstatic struct khash* 79918316Swollmankern_add(naddr dst, naddr mask) 80018316Swollman{ 80118316Swollman struct khash *k, **pk; 80218316Swollman 80318316Swollman k = kern_find(dst, mask, &pk); 80418316Swollman if (k != 0) 80518316Swollman return k; 80618316Swollman 80737908Scharnier k = (struct khash *)rtmalloc(sizeof(*k), "kern_add"); 80818316Swollman 80946303Smarkm memset(k, 0, sizeof(*k)); 81018316Swollman k->k_dst = dst; 81118316Swollman k->k_mask = mask; 81218316Swollman k->k_state = KS_NEW; 81318316Swollman k->k_keep = now.tv_sec; 81418316Swollman *pk = k; 81518316Swollman 81618316Swollman return k; 81718316Swollman} 81818316Swollman 81918316Swollman 82018316Swollman/* If a kernel route has a non-zero metric, check that it is still in the 82118316Swollman * daemon table, and not deleted by interfaces coming and going. 82218316Swollman */ 82318316Swollmanstatic void 82418316Swollmankern_check_static(struct khash *k, 82518316Swollman struct interface *ifp) 82618316Swollman{ 82718316Swollman struct rt_entry *rt; 82846303Smarkm struct rt_spare new; 82918316Swollman 83018316Swollman if (k->k_metric == 0) 83118316Swollman return; 83218316Swollman 83346303Smarkm memset(&new, 0, sizeof(new)); 83446303Smarkm new.rts_ifp = ifp; 83546303Smarkm new.rts_gate = k->k_gate; 83646303Smarkm new.rts_router = (ifp != 0) ? ifp->int_addr : loopaddr; 83746303Smarkm new.rts_metric = k->k_metric; 83846303Smarkm new.rts_time = now.tv_sec; 83918316Swollman 84018316Swollman rt = rtget(k->k_dst, k->k_mask); 84118316Swollman if (rt != 0) { 84218316Swollman if (!(rt->rt_state & RS_STATIC)) 84346303Smarkm rtchange(rt, rt->rt_state | RS_STATIC, &new, 0); 84418316Swollman } else { 84546303Smarkm rtadd(k->k_dst, k->k_mask, RS_STATIC, &new); 84618316Swollman } 84718316Swollman} 84818316Swollman 84918316Swollman 85046303Smarkm/* operate on a kernel entry 85146303Smarkm */ 85246303Smarkmstatic void 85346303Smarkmkern_ioctl(struct khash *k, 85446303Smarkm int action, /* RTM_DELETE, etc */ 85546303Smarkm int flags) 85646303Smarkm 85746303Smarkm{ 85846303Smarkm switch (action) { 85946303Smarkm case RTM_DELETE: 86046303Smarkm k->k_state &= ~KS_DYNAMIC; 86146303Smarkm if (k->k_state & KS_DELETED) 86246303Smarkm return; 86346303Smarkm k->k_state |= KS_DELETED; 86446303Smarkm break; 86546303Smarkm case RTM_ADD: 86646303Smarkm k->k_state &= ~KS_DELETED; 86746303Smarkm break; 86846303Smarkm case RTM_CHANGE: 86946303Smarkm if (k->k_state & KS_DELETED) { 87046303Smarkm action = RTM_ADD; 87146303Smarkm k->k_state &= ~KS_DELETED; 87246303Smarkm } 87346303Smarkm break; 87446303Smarkm } 87546303Smarkm 87646303Smarkm rtioctl(action, k->k_dst, k->k_gate, k->k_mask, k->k_metric, flags); 87746303Smarkm} 87846303Smarkm 87946303Smarkm 88018316Swollman/* add a route the kernel told us 88118316Swollman */ 88218316Swollmanstatic void 88318316Swollmanrtm_add(struct rt_msghdr *rtm, 88418316Swollman struct rt_addrinfo *info, 88518316Swollman time_t keep) 88618316Swollman{ 88718316Swollman struct khash *k; 88818316Swollman struct interface *ifp; 88918316Swollman naddr mask; 89018316Swollman 89118316Swollman 89218316Swollman if (rtm->rtm_flags & RTF_HOST) { 89318316Swollman mask = HOST_MASK; 89418316Swollman } else if (INFO_MASK(info) != 0) { 89518316Swollman mask = ntohl(S_ADDR(INFO_MASK(info))); 89618316Swollman } else { 89720342Swollman msglog("ignore %s without mask", rtm_type_name(rtm->rtm_type)); 89818316Swollman return; 89918316Swollman } 90018316Swollman 90118316Swollman k = kern_add(S_ADDR(INFO_DST(info)), mask); 90218316Swollman if (k->k_state & KS_NEW) 90318316Swollman k->k_keep = now.tv_sec+keep; 90446303Smarkm if (INFO_GATE(info) == 0) { 90546303Smarkm trace_act("note %s without gateway", 90646303Smarkm rtm_type_name(rtm->rtm_type)); 90746303Smarkm k->k_metric = HOPCNT_INFINITY; 90846303Smarkm } else if (INFO_GATE(info)->sa_family != AF_INET) { 90946303Smarkm trace_act("note %s with gateway AF=%d", 91046303Smarkm rtm_type_name(rtm->rtm_type), 91146303Smarkm INFO_GATE(info)->sa_family); 91246303Smarkm k->k_metric = HOPCNT_INFINITY; 91346303Smarkm } else { 91446303Smarkm k->k_gate = S_ADDR(INFO_GATE(info)); 91546303Smarkm k->k_metric = rtm->rtm_rmx.rmx_hopcount; 91646303Smarkm if (k->k_metric < 0) 91746303Smarkm k->k_metric = 0; 91846303Smarkm else if (k->k_metric > HOPCNT_INFINITY-1) 91946303Smarkm k->k_metric = HOPCNT_INFINITY-1; 92046303Smarkm } 92146303Smarkm k->k_state &= ~(KS_DELETE | KS_ADD | KS_CHANGE | KS_DEL_ADD 92246303Smarkm | KS_DELETED | KS_GATEWAY | KS_STATIC 92346303Smarkm | KS_NEW | KS_CHECK); 92418316Swollman if (rtm->rtm_flags & RTF_GATEWAY) 92518316Swollman k->k_state |= KS_GATEWAY; 92618316Swollman if (rtm->rtm_flags & RTF_STATIC) 92718316Swollman k->k_state |= KS_STATIC; 92818316Swollman 92918316Swollman if (0 != (rtm->rtm_flags & (RTF_DYNAMIC | RTF_MODIFIED))) { 93020342Swollman if (INFO_AUTHOR(info) != 0 93120342Swollman && INFO_AUTHOR(info)->sa_family == AF_INET) 93220342Swollman ifp = iflookup(S_ADDR(INFO_AUTHOR(info))); 93320342Swollman else 93420342Swollman ifp = 0; 93520342Swollman if (supplier 93620342Swollman && (ifp == 0 || !(ifp->int_state & IS_REDIRECT_OK))) { 93718316Swollman /* Routers are not supposed to listen to redirects, 93820342Swollman * so delete it if it came via an unknown interface 93920342Swollman * or the interface does not have special permission. 94018316Swollman */ 94118316Swollman k->k_state &= ~KS_DYNAMIC; 94218316Swollman k->k_state |= KS_DELETE; 94318316Swollman LIM_SEC(need_kern, 0); 94420342Swollman trace_act("mark for deletion redirected %s --> %s" 94520342Swollman " via %s", 94618316Swollman addrname(k->k_dst, k->k_mask, 0), 94720342Swollman naddr_ntoa(k->k_gate), 94820342Swollman ifp ? ifp->int_name : "unknown interface"); 94918316Swollman } else { 95018316Swollman k->k_state |= KS_DYNAMIC; 95118316Swollman k->k_redirect_time = now.tv_sec; 95220342Swollman trace_act("accept redirected %s --> %s via %s", 95320342Swollman addrname(k->k_dst, k->k_mask, 0), 95420342Swollman naddr_ntoa(k->k_gate), 95520342Swollman ifp ? ifp->int_name : "unknown interface"); 95618316Swollman } 95718316Swollman return; 95818316Swollman } 95918316Swollman 96018316Swollman /* If it is not a static route, quit until the next comparison 96118316Swollman * between the kernel and daemon tables, when it will be deleted. 96218316Swollman */ 96318316Swollman if (!(k->k_state & KS_STATIC)) { 96418316Swollman k->k_state |= KS_DELETE; 96518316Swollman LIM_SEC(need_kern, k->k_keep); 96618316Swollman return; 96718316Swollman } 96818316Swollman 96918316Swollman /* Put static routes with real metrics into the daemon table so 97018316Swollman * they can be advertised. 97118316Swollman * 97219885Swollman * Find the interface toward the gateway. 97318316Swollman */ 97418316Swollman ifp = iflookup(k->k_gate); 97520342Swollman if (ifp == 0) 97620342Swollman msglog("static route %s --> %s impossibly lacks ifp", 97720342Swollman addrname(S_ADDR(INFO_DST(info)), mask, 0), 97820342Swollman naddr_ntoa(k->k_gate)); 97918316Swollman 98018316Swollman kern_check_static(k, ifp); 98118316Swollman} 98218316Swollman 98318316Swollman 98418316Swollman/* deal with packet loss 98518316Swollman */ 98618316Swollmanstatic void 98718316Swollmanrtm_lose(struct rt_msghdr *rtm, 98818316Swollman struct rt_addrinfo *info) 98918316Swollman{ 99018316Swollman if (INFO_GATE(info) == 0 99118316Swollman || INFO_GATE(info)->sa_family != AF_INET) { 99220342Swollman trace_act("ignore %s without gateway", 99320342Swollman rtm_type_name(rtm->rtm_type)); 99418316Swollman return; 99518316Swollman } 99618316Swollman 99746303Smarkm if (rdisc_ok) 99818316Swollman rdisc_age(S_ADDR(INFO_GATE(info))); 99918316Swollman age(S_ADDR(INFO_GATE(info))); 100018316Swollman} 100118316Swollman 100218316Swollman 100346303Smarkm/* Make the gateway slot of an info structure point to something 100446303Smarkm * useful. If it is not already useful, but it specifies an interface, 100546303Smarkm * then fill in the sockaddr_in provided and point it there. 100646303Smarkm */ 100746303Smarkmstatic int 100846303Smarkmget_info_gate(struct sockaddr **sap, 1009126250Sbms struct sockaddr_in *rsin) 101046303Smarkm{ 101146303Smarkm struct sockaddr_dl *sdl = (struct sockaddr_dl *)*sap; 101246303Smarkm struct interface *ifp; 101346303Smarkm 101446303Smarkm if (sdl == 0) 101546303Smarkm return 0; 101646303Smarkm if ((sdl)->sdl_family == AF_INET) 101746303Smarkm return 1; 101846303Smarkm if ((sdl)->sdl_family != AF_LINK) 101946303Smarkm return 0; 102046303Smarkm 102146303Smarkm ifp = ifwithindex(sdl->sdl_index, 1); 102246303Smarkm if (ifp == 0) 102346303Smarkm return 0; 102446303Smarkm 1025126250Sbms rsin->sin_addr.s_addr = ifp->int_addr; 102646303Smarkm#ifdef _HAVE_SA_LEN 1027126250Sbms rsin->sin_len = sizeof(*rsin); 102846303Smarkm#endif 1029126250Sbms rsin->sin_family = AF_INET; 1030126250Sbms *sap = (struct sockaddr*)rsin; 103146303Smarkm 103246303Smarkm return 1; 103346303Smarkm} 103446303Smarkm 103546303Smarkm 103618316Swollman/* Clean the kernel table by copying it to the daemon image. 103718316Swollman * Eventually the daemon will delete any extra routes. 103818316Swollman */ 103918316Swollmanvoid 104018316Swollmanflush_kern(void) 104118316Swollman{ 104246303Smarkm static char *sysctl_buf; 104346303Smarkm static size_t sysctl_buf_size = 0; 104418316Swollman size_t needed; 104518316Swollman int mib[6]; 104646303Smarkm char *next, *lim; 104718316Swollman struct rt_msghdr *rtm; 104846303Smarkm struct sockaddr_in gate_sin; 104918316Swollman struct rt_addrinfo info; 105046303Smarkm int i; 105146303Smarkm struct khash *k; 105218316Swollman 105318316Swollman 105446303Smarkm for (i = 0; i < KHASH_SIZE; i++) { 105546303Smarkm for (k = khash_bins[i]; k != 0; k = k->k_next) { 105646303Smarkm k->k_state |= KS_CHECK; 105746303Smarkm } 105846303Smarkm } 105946303Smarkm 106018316Swollman mib[0] = CTL_NET; 106118316Swollman mib[1] = PF_ROUTE; 106218316Swollman mib[2] = 0; /* protocol */ 106318316Swollman mib[3] = 0; /* wildcard address family */ 106418316Swollman mib[4] = NET_RT_DUMP; 106518316Swollman mib[5] = 0; /* no flags */ 106646303Smarkm for (;;) { 106746303Smarkm if ((needed = sysctl_buf_size) != 0) { 106846303Smarkm if (sysctl(mib, 6, sysctl_buf,&needed, 0, 0) >= 0) 106946303Smarkm break; 107046303Smarkm if (errno != ENOMEM && errno != EFAULT) 107146303Smarkm BADERR(1,"flush_kern: sysctl(RT_DUMP)"); 107246303Smarkm free(sysctl_buf); 107346303Smarkm needed = 0; 107446303Smarkm } 107546303Smarkm if (sysctl(mib, 6, 0, &needed, 0, 0) < 0) 107646303Smarkm BADERR(1,"flush_kern: sysctl(RT_DUMP) estimate"); 107746303Smarkm /* Kludge around the habit of some systems, such as 107846303Smarkm * BSD/OS 3.1, to not admit how many routes are in the 107946303Smarkm * kernel, or at least to be quite wrong. 108046303Smarkm */ 108146303Smarkm needed += 50*(sizeof(*rtm)+5*sizeof(struct sockaddr)); 108246303Smarkm sysctl_buf = rtmalloc(sysctl_buf_size = needed, 108346303Smarkm "flush_kern sysctl(RT_DUMP)"); 108418316Swollman } 108546303Smarkm 108646303Smarkm lim = sysctl_buf + needed; 108746303Smarkm for (next = sysctl_buf; next < lim; next += rtm->rtm_msglen) { 108818316Swollman rtm = (struct rt_msghdr *)next; 108946303Smarkm if (rtm->rtm_msglen == 0) { 109046303Smarkm msglog("zero length kernel route at " 109146303Smarkm " %#lx in buffer %#lx before %#lx", 109246303Smarkm (u_long)rtm, (u_long)sysctl_buf, (u_long)lim); 109346303Smarkm break; 109446303Smarkm } 109518316Swollman 109618316Swollman rt_xaddrs(&info, 109718316Swollman (struct sockaddr *)(rtm+1), 109818316Swollman (struct sockaddr *)(next + rtm->rtm_msglen), 109918316Swollman rtm->rtm_addrs); 110018316Swollman 110118316Swollman if (INFO_DST(&info) == 0 110218316Swollman || INFO_DST(&info)->sa_family != AF_INET) 110318316Swollman continue; 110418316Swollman 1105186119Sqingli#if defined (RTF_LLINFO) 110618316Swollman /* ignore ARP table entries on systems with a merged route 110718316Swollman * and ARP table. 110818316Swollman */ 110918316Swollman if (rtm->rtm_flags & RTF_LLINFO) 111018316Swollman continue; 1111186119Sqingli#endif 1112130498Sbms#if defined(RTF_WASCLONED) && defined(__FreeBSD__) 1113126250Sbms /* ignore cloned routes 1114126250Sbms */ 1115130498Sbms if (rtm->rtm_flags & RTF_WASCLONED) 1116126250Sbms continue; 1117126250Sbms#endif 1118126250Sbms 111918316Swollman /* ignore multicast addresses 112018316Swollman */ 112118316Swollman if (IN_MULTICAST(ntohl(S_ADDR(INFO_DST(&info))))) 112218316Swollman continue; 112318316Swollman 112446303Smarkm if (!get_info_gate(&INFO_GATE(&info), &gate_sin)) 112546303Smarkm continue; 112646303Smarkm 112718316Swollman /* Note static routes and interface routes, and also 112818316Swollman * preload the image of the kernel table so that 112918316Swollman * we can later clean it, as well as avoid making 113018316Swollman * unneeded changes. Keep the old kernel routes for a 113118316Swollman * few seconds to allow a RIP or router-discovery 113218316Swollman * response to be heard. 113318316Swollman */ 113418316Swollman rtm_add(rtm,&info,MIN_WAITTIME); 113518316Swollman } 113646303Smarkm 113746303Smarkm for (i = 0; i < KHASH_SIZE; i++) { 113846303Smarkm for (k = khash_bins[i]; k != 0; k = k->k_next) { 113946303Smarkm if (k->k_state & KS_CHECK) { 114046303Smarkm msglog("%s --> %s disappeared from kernel", 114146303Smarkm addrname(k->k_dst, k->k_mask, 0), 114246303Smarkm naddr_ntoa(k->k_gate)); 114346303Smarkm del_static(k->k_dst, k->k_mask, k->k_gate, 1); 114446303Smarkm } 114546303Smarkm } 114646303Smarkm } 114718316Swollman} 114818316Swollman 114918316Swollman 115018316Swollman/* Listen to announcements from the kernel 115118316Swollman */ 115218316Swollmanvoid 115318316Swollmanread_rt(void) 115418316Swollman{ 115518316Swollman long cc; 115618316Swollman struct interface *ifp; 115746303Smarkm struct sockaddr_in gate_sin; 115846303Smarkm naddr mask, gate; 115918316Swollman union { 116018316Swollman struct { 116118316Swollman struct rt_msghdr rtm; 116218316Swollman struct sockaddr addrs[RTAX_MAX]; 116318316Swollman } r; 116418316Swollman struct if_msghdr ifm; 116518316Swollman } m; 116618316Swollman char str[100], *strp; 116718316Swollman struct rt_addrinfo info; 116818316Swollman 116918316Swollman 117018316Swollman for (;;) { 117118316Swollman cc = read(rt_sock, &m, sizeof(m)); 117218316Swollman if (cc <= 0) { 117318316Swollman if (cc < 0 && errno != EWOULDBLOCK) 117418316Swollman LOGERR("read(rt_sock)"); 117518316Swollman return; 117618316Swollman } 117718316Swollman 117818316Swollman if (m.r.rtm.rtm_version != RTM_VERSION) { 117918316Swollman msglog("bogus routing message version %d", 118018316Swollman m.r.rtm.rtm_version); 118118316Swollman continue; 118218316Swollman } 118318316Swollman 118418316Swollman /* Ignore our own results. 118518316Swollman */ 118618316Swollman if (m.r.rtm.rtm_type <= RTM_CHANGE 118718316Swollman && m.r.rtm.rtm_pid == mypid) { 118818316Swollman static int complained = 0; 118918316Swollman if (!complained) { 119018316Swollman msglog("receiving our own change messages"); 119118316Swollman complained = 1; 119218316Swollman } 119318316Swollman continue; 119418316Swollman } 119518316Swollman 119618316Swollman if (m.r.rtm.rtm_type == RTM_IFINFO 119718316Swollman || m.r.rtm.rtm_type == RTM_NEWADDR 119818316Swollman || m.r.rtm.rtm_type == RTM_DELADDR) { 119946303Smarkm ifp = ifwithindex(m.ifm.ifm_index, 120046303Smarkm m.r.rtm.rtm_type != RTM_DELADDR); 120118316Swollman if (ifp == 0) 120218316Swollman trace_act("note %s with flags %#x" 120346303Smarkm " for unknown interface index #%d", 120418316Swollman rtm_type_name(m.r.rtm.rtm_type), 120518316Swollman m.ifm.ifm_flags, 120618316Swollman m.ifm.ifm_index); 120718316Swollman else 120819885Swollman trace_act("note %s with flags %#x for %s", 120918316Swollman rtm_type_name(m.r.rtm.rtm_type), 121018316Swollman m.ifm.ifm_flags, 121118316Swollman ifp->int_name); 121218316Swollman 121318316Swollman /* After being informed of a change to an interface, 121418316Swollman * check them all now if the check would otherwise 121518316Swollman * be a long time from now, if the interface is 121618316Swollman * not known, or if the interface has been turned 121718316Swollman * off or on. 121818316Swollman */ 121918316Swollman if (ifinit_timer.tv_sec-now.tv_sec>=CHECK_BAD_INTERVAL 122018316Swollman || ifp == 0 122118316Swollman || ((ifp->int_if_flags ^ m.ifm.ifm_flags) 122246303Smarkm & IFF_UP) != 0) 122318316Swollman ifinit_timer.tv_sec = now.tv_sec; 122418316Swollman continue; 122518316Swollman } 1226126250Sbms#ifdef RTM_OIFINFO 1227126250Sbms if (m.r.rtm.rtm_type == RTM_OIFINFO) 1228126250Sbms continue; /* ignore compat message */ 1229126250Sbms#endif 123018316Swollman 123118316Swollman strcpy(str, rtm_type_name(m.r.rtm.rtm_type)); 123218316Swollman strp = &str[strlen(str)]; 123318316Swollman if (m.r.rtm.rtm_type <= RTM_CHANGE) 123418316Swollman strp += sprintf(strp," from pid %d",m.r.rtm.rtm_pid); 123518316Swollman 123618316Swollman rt_xaddrs(&info, m.r.addrs, &m.r.addrs[RTAX_MAX], 123718316Swollman m.r.rtm.rtm_addrs); 123818316Swollman 123918316Swollman if (INFO_DST(&info) == 0) { 124019885Swollman trace_act("ignore %s without dst", str); 124118316Swollman continue; 124218316Swollman } 124318316Swollman 124418316Swollman if (INFO_DST(&info)->sa_family != AF_INET) { 124519885Swollman trace_act("ignore %s for AF %d", str, 124618316Swollman INFO_DST(&info)->sa_family); 124718316Swollman continue; 124818316Swollman } 124918316Swollman 125018316Swollman mask = ((INFO_MASK(&info) != 0) 125118316Swollman ? ntohl(S_ADDR(INFO_MASK(&info))) 125218316Swollman : (m.r.rtm.rtm_flags & RTF_HOST) 125318316Swollman ? HOST_MASK 125418316Swollman : std_mask(S_ADDR(INFO_DST(&info)))); 125518316Swollman 125618316Swollman strp += sprintf(strp, ": %s", 125718316Swollman addrname(S_ADDR(INFO_DST(&info)), mask, 0)); 125818316Swollman 125918316Swollman if (IN_MULTICAST(ntohl(S_ADDR(INFO_DST(&info))))) { 126019885Swollman trace_act("ignore multicast %s", str); 126118316Swollman continue; 126218316Swollman } 126318316Swollman 1264186119Sqingli#if defined(RTF_LLINFO) 126546303Smarkm if (m.r.rtm.rtm_flags & RTF_LLINFO) { 126646303Smarkm trace_act("ignore ARP %s", str); 126746303Smarkm continue; 126846303Smarkm } 1269186119Sqingli#endif 1270186119Sqingli 1271130498Sbms#if defined(RTF_WASCLONED) && defined(__FreeBSD__) 1272130498Sbms if (m.r.rtm.rtm_flags & RTF_WASCLONED) { 1273126250Sbms trace_act("ignore cloned %s", str); 1274126250Sbms continue; 1275126250Sbms } 1276126250Sbms#endif 1277126250Sbms 127846303Smarkm if (get_info_gate(&INFO_GATE(&info), &gate_sin)) { 127946303Smarkm gate = S_ADDR(INFO_GATE(&info)); 128046303Smarkm strp += sprintf(strp, " --> %s", naddr_ntoa(gate)); 128146303Smarkm } else { 128246303Smarkm gate = 0; 128346303Smarkm } 128446303Smarkm 128518316Swollman if (INFO_AUTHOR(&info) != 0) 128618316Swollman strp += sprintf(strp, " by authority of %s", 128718316Swollman saddr_ntoa(INFO_AUTHOR(&info))); 128818316Swollman 128918316Swollman switch (m.r.rtm.rtm_type) { 129018316Swollman case RTM_ADD: 129118316Swollman case RTM_CHANGE: 129218316Swollman case RTM_REDIRECT: 129318316Swollman if (m.r.rtm.rtm_errno != 0) { 129419885Swollman trace_act("ignore %s with \"%s\" error", 129518316Swollman str, strerror(m.r.rtm.rtm_errno)); 129618316Swollman } else { 129719885Swollman trace_act("%s", str); 129818316Swollman rtm_add(&m.r.rtm,&info,0); 129918316Swollman } 130018316Swollman break; 130118316Swollman 130218316Swollman case RTM_DELETE: 130346303Smarkm if (m.r.rtm.rtm_errno != 0 130446303Smarkm && m.r.rtm.rtm_errno != ESRCH) { 130519885Swollman trace_act("ignore %s with \"%s\" error", 130618316Swollman str, strerror(m.r.rtm.rtm_errno)); 130718316Swollman } else { 130819885Swollman trace_act("%s", str); 130946303Smarkm del_static(S_ADDR(INFO_DST(&info)), mask, 131046303Smarkm gate, 1); 131118316Swollman } 131218316Swollman break; 131318316Swollman 131418316Swollman case RTM_LOSING: 131519885Swollman trace_act("%s", str); 131618316Swollman rtm_lose(&m.r.rtm,&info); 131718316Swollman break; 131818316Swollman 131918316Swollman default: 132019885Swollman trace_act("ignore %s", str); 132118316Swollman break; 132218316Swollman } 132318316Swollman } 132418316Swollman} 132518316Swollman 132618316Swollman 132718316Swollman/* after aggregating, note routes that belong in the kernel 132818316Swollman */ 132918316Swollmanstatic void 133018316Swollmankern_out(struct ag_info *ag) 133118316Swollman{ 133218316Swollman struct khash *k; 133318316Swollman 133418316Swollman 133518316Swollman /* Do not install bad routes if they are not already present. 133618316Swollman * This includes routes that had RS_NET_SYN for interfaces that 133718316Swollman * recently died. 133818316Swollman */ 133918316Swollman if (ag->ag_metric == HOPCNT_INFINITY) { 134018316Swollman k = kern_find(htonl(ag->ag_dst_h), ag->ag_mask, 0); 134118316Swollman if (k == 0) 134218316Swollman return; 134318316Swollman } else { 134418316Swollman k = kern_add(htonl(ag->ag_dst_h), ag->ag_mask); 134518316Swollman } 134618316Swollman 134718316Swollman if (k->k_state & KS_NEW) { 134818316Swollman /* will need to add new entry to the kernel table */ 134918316Swollman k->k_state = KS_ADD; 135018316Swollman if (ag->ag_state & AGS_GATEWAY) 135118316Swollman k->k_state |= KS_GATEWAY; 135218316Swollman k->k_gate = ag->ag_gate; 135318316Swollman k->k_metric = ag->ag_metric; 135418316Swollman return; 135518316Swollman } 135618316Swollman 135718316Swollman if (k->k_state & KS_STATIC) 135818316Swollman return; 135918316Swollman 136018316Swollman /* modify existing kernel entry if necessary */ 136118316Swollman if (k->k_gate != ag->ag_gate 136218316Swollman || k->k_metric != ag->ag_metric) { 136346303Smarkm /* Must delete bad interface routes etc. to change them. */ 136446303Smarkm if (k->k_metric == HOPCNT_INFINITY) 136546303Smarkm k->k_state |= KS_DEL_ADD; 136618316Swollman k->k_gate = ag->ag_gate; 136718316Swollman k->k_metric = ag->ag_metric; 136818316Swollman k->k_state |= KS_CHANGE; 136918316Swollman } 137018316Swollman 137146303Smarkm /* If the daemon thinks the route should exist, forget 137246303Smarkm * about any redirections. 137346303Smarkm * If the daemon thinks the route should exist, eventually 137446303Smarkm * override manual intervention by the operator. 137546303Smarkm */ 137646303Smarkm if ((k->k_state & (KS_DYNAMIC | KS_DELETED)) != 0) { 137718316Swollman k->k_state &= ~KS_DYNAMIC; 137818316Swollman k->k_state |= (KS_ADD | KS_DEL_ADD); 137918316Swollman } 138018316Swollman 138118316Swollman if ((k->k_state & KS_GATEWAY) 138218316Swollman && !(ag->ag_state & AGS_GATEWAY)) { 138318316Swollman k->k_state &= ~KS_GATEWAY; 138418316Swollman k->k_state |= (KS_ADD | KS_DEL_ADD); 138518316Swollman } else if (!(k->k_state & KS_GATEWAY) 138618316Swollman && (ag->ag_state & AGS_GATEWAY)) { 138718316Swollman k->k_state |= KS_GATEWAY; 138818316Swollman k->k_state |= (KS_ADD | KS_DEL_ADD); 138918316Swollman } 139018316Swollman 139118316Swollman /* Deleting-and-adding is necessary to change aspects of a route. 139218316Swollman * Just delete instead of deleting and then adding a bad route. 139318316Swollman * Otherwise, we want to keep the route in the kernel. 139418316Swollman */ 139518316Swollman if (k->k_metric == HOPCNT_INFINITY 139618316Swollman && (k->k_state & KS_DEL_ADD)) 139718316Swollman k->k_state |= KS_DELETE; 139818316Swollman else 139918316Swollman k->k_state &= ~KS_DELETE; 140018316Swollman#undef RT 140118316Swollman} 140218316Swollman 140318316Swollman 140418316Swollman/* ARGSUSED */ 140518316Swollmanstatic int 140618316Swollmanwalk_kern(struct radix_node *rn, 140746303Smarkm struct walkarg *argp UNUSED) 140818316Swollman{ 140918316Swollman#define RT ((struct rt_entry *)rn) 141018316Swollman char metric, pref; 141118316Swollman u_int ags = 0; 141218316Swollman 141318316Swollman 141418316Swollman /* Do not install synthetic routes */ 141518316Swollman if (RT->rt_state & RS_NET_SYN) 141618316Swollman return 0; 141718316Swollman 141818316Swollman if (!(RT->rt_state & RS_IF)) { 141946303Smarkm /* This is an ordinary route, not for an interface. 142046303Smarkm */ 142118316Swollman 142246303Smarkm /* aggregate, ordinary good routes without regard to 142346303Smarkm * their metric 142446303Smarkm */ 142546303Smarkm pref = 1; 142646303Smarkm ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_AGGREGATE); 142746303Smarkm 142846303Smarkm /* Do not install host routes directly to hosts, to avoid 142946303Smarkm * interfering with ARP entries in the kernel table. 143046303Smarkm */ 143146303Smarkm if (RT_ISHOST(RT) 143246303Smarkm && ntohl(RT->rt_dst) == RT->rt_gate) 143346303Smarkm return 0; 143446303Smarkm 143518316Swollman } else { 143646303Smarkm /* This is an interface route. 143746303Smarkm * Do not install routes for "external" remote interfaces. 143818316Swollman */ 143918316Swollman if (RT->rt_ifp != 0 && (RT->rt_ifp->int_state & IS_EXTERNAL)) 144018316Swollman return 0; 144118316Swollman 144246303Smarkm /* Interfaces should override received routes. 144346303Smarkm */ 144446303Smarkm pref = 0; 144546303Smarkm ags |= (AGS_IF | AGS_CORS_GATE); 144618316Swollman 144718316Swollman /* If it is not an interface, or an alias for an interface, 144818316Swollman * it must be a "gateway." 144918316Swollman * 145018316Swollman * If it is a "remote" interface, it is also a "gateway" to 1451108533Sschweikh * the kernel if is not an alias. 145218316Swollman */ 145318316Swollman if (RT->rt_ifp == 0 145419885Swollman || (RT->rt_ifp->int_state & IS_REMOTE)) 145546303Smarkm ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_AGGREGATE); 145618316Swollman } 145718316Swollman 145846303Smarkm /* If RIP is off and IRDP is on, let the route to the discovered 145946303Smarkm * route suppress any RIP routes. Eventually the RIP routes 146046303Smarkm * will time-out and be deleted. This reaches the steady-state 146146303Smarkm * quicker. 146246303Smarkm */ 146346303Smarkm if ((RT->rt_state & RS_RDISC) && rip_sock < 0) 146418316Swollman ags |= AGS_CORS_GATE; 146518316Swollman 146618316Swollman metric = RT->rt_metric; 146718316Swollman if (metric == HOPCNT_INFINITY) { 146818316Swollman /* if the route is dead, so try hard to aggregate. */ 146918316Swollman pref = HOPCNT_INFINITY; 147018316Swollman ags |= (AGS_FINE_GATE | AGS_SUPPRESS); 147146303Smarkm ags &= ~(AGS_IF | AGS_CORS_GATE); 147218316Swollman } 147318316Swollman 147418316Swollman ag_check(RT->rt_dst, RT->rt_mask, RT->rt_gate, 0, 147518316Swollman metric,pref, 0, 0, ags, kern_out); 147618316Swollman return 0; 147718316Swollman#undef RT 147818316Swollman} 147918316Swollman 148018316Swollman 148118316Swollman/* Update the kernel table to match the daemon table. 148218316Swollman */ 148318316Swollmanstatic void 148418316Swollmanfix_kern(void) 148518316Swollman{ 148646303Smarkm int i; 148718316Swollman struct khash *k, **pk; 148818316Swollman 148918316Swollman 149018316Swollman need_kern = age_timer; 149118316Swollman 149218316Swollman /* Walk daemon table, updating the copy of the kernel table. 149318316Swollman */ 149418316Swollman (void)rn_walktree(rhead, walk_kern, 0); 149518316Swollman ag_flush(0,0,kern_out); 149618316Swollman 149718316Swollman for (i = 0; i < KHASH_SIZE; i++) { 149818316Swollman for (pk = &khash_bins[i]; (k = *pk) != 0; ) { 149918316Swollman /* Do not touch static routes */ 150018316Swollman if (k->k_state & KS_STATIC) { 150118316Swollman kern_check_static(k,0); 150218316Swollman pk = &k->k_next; 150318316Swollman continue; 150418316Swollman } 150518316Swollman 150618316Swollman /* check hold on routes deleted by the operator */ 150718316Swollman if (k->k_keep > now.tv_sec) { 150846303Smarkm /* ensure we check when the hold is over */ 150918316Swollman LIM_SEC(need_kern, k->k_keep); 151046303Smarkm /* mark for the next cycle */ 151118316Swollman k->k_state |= KS_DELETE; 151218316Swollman pk = &k->k_next; 151318316Swollman continue; 151418316Swollman } 151518316Swollman 151646303Smarkm if ((k->k_state & KS_DELETE) 151746303Smarkm && !(k->k_state & KS_DYNAMIC)) { 151846303Smarkm kern_ioctl(k, RTM_DELETE, 0); 151918316Swollman *pk = k->k_next; 152018316Swollman free(k); 152118316Swollman continue; 152218316Swollman } 152318316Swollman 152446303Smarkm if (k->k_state & KS_DEL_ADD) 152546303Smarkm kern_ioctl(k, RTM_DELETE, 0); 152618316Swollman 152746303Smarkm if (k->k_state & KS_ADD) { 152846303Smarkm kern_ioctl(k, RTM_ADD, 152946303Smarkm ((0 != (k->k_state & (KS_GATEWAY 153046303Smarkm | KS_DYNAMIC))) 153146303Smarkm ? RTF_GATEWAY : 0)); 153246303Smarkm } else if (k->k_state & KS_CHANGE) { 153346303Smarkm kern_ioctl(k, RTM_CHANGE, 153446303Smarkm ((0 != (k->k_state & (KS_GATEWAY 153546303Smarkm | KS_DYNAMIC))) 153646303Smarkm ? RTF_GATEWAY : 0)); 153718316Swollman } 153846303Smarkm k->k_state &= ~(KS_ADD|KS_CHANGE|KS_DEL_ADD); 153918316Swollman 154018316Swollman /* Mark this route to be deleted in the next cycle. 154118316Swollman * This deletes routes that disappear from the 154218316Swollman * daemon table, since the normal aging code 154318316Swollman * will clear the bit for routes that have not 154418316Swollman * disappeared from the daemon table. 154518316Swollman */ 154618316Swollman k->k_state |= KS_DELETE; 154718316Swollman pk = &k->k_next; 154818316Swollman } 154918316Swollman } 155018316Swollman} 155118316Swollman 155218316Swollman 155318316Swollman/* Delete a static route in the image of the kernel table. 155418316Swollman */ 155518316Swollmanvoid 155618316Swollmandel_static(naddr dst, 155718316Swollman naddr mask, 155846303Smarkm naddr gate, 155918316Swollman int gone) 156018316Swollman{ 156118316Swollman struct khash *k; 156218316Swollman struct rt_entry *rt; 156318316Swollman 156418316Swollman /* Just mark it in the table to be deleted next time the kernel 156518316Swollman * table is updated. 156618316Swollman * If it has already been deleted, mark it as such, and set its 156718316Swollman * keep-timer so that it will not be deleted again for a while. 156818316Swollman * This lets the operator delete a route added by the daemon 156918316Swollman * and add a replacement. 157018316Swollman */ 157118316Swollman k = kern_find(dst, mask, 0); 157246303Smarkm if (k != 0 && (gate == 0 || k->k_gate == gate)) { 157346303Smarkm k->k_state &= ~(KS_STATIC | KS_DYNAMIC | KS_CHECK); 157418316Swollman k->k_state |= KS_DELETE; 157518316Swollman if (gone) { 157618316Swollman k->k_state |= KS_DELETED; 157718316Swollman k->k_keep = now.tv_sec + K_KEEP_LIM; 157818316Swollman } 157918316Swollman } 158018316Swollman 158118316Swollman rt = rtget(dst, mask); 158218316Swollman if (rt != 0 && (rt->rt_state & RS_STATIC)) 158318316Swollman rtbad(rt); 158418316Swollman} 158518316Swollman 158618316Swollman 158718316Swollman/* Delete all routes generated from ICMP Redirects that use a given gateway, 158818316Swollman * as well as old redirected routes. 158918316Swollman */ 159018316Swollmanvoid 159118316Swollmandel_redirects(naddr bad_gate, 159218316Swollman time_t old) 159318316Swollman{ 159418316Swollman int i; 159518316Swollman struct khash *k; 159618316Swollman 159718316Swollman 159818316Swollman for (i = 0; i < KHASH_SIZE; i++) { 159918316Swollman for (k = khash_bins[i]; k != 0; k = k->k_next) { 160018316Swollman if (!(k->k_state & KS_DYNAMIC) 160118316Swollman || (k->k_state & KS_STATIC)) 160218316Swollman continue; 160318316Swollman 160418316Swollman if (k->k_gate != bad_gate 160518316Swollman && k->k_redirect_time > old 160618316Swollman && !supplier) 160718316Swollman continue; 160818316Swollman 160918316Swollman k->k_state |= KS_DELETE; 161018316Swollman k->k_state &= ~KS_DYNAMIC; 161118316Swollman need_kern.tv_sec = now.tv_sec; 161219885Swollman trace_act("mark redirected %s --> %s for deletion", 161318316Swollman addrname(k->k_dst, k->k_mask, 0), 161418316Swollman naddr_ntoa(k->k_gate)); 161518316Swollman } 161618316Swollman } 161718316Swollman} 161818316Swollman 161918316Swollman 162018316Swollman/* Start the daemon tables. 162118316Swollman */ 162246303Smarkmextern int max_keylen; 162346303Smarkm 162418316Swollmanvoid 162518316Swollmanrtinit(void) 162618316Swollman{ 162718316Swollman int i; 162818316Swollman struct ag_info *ag; 162918316Swollman 163018316Swollman /* Initialize the radix trees */ 163118316Swollman max_keylen = sizeof(struct sockaddr_in); 163218316Swollman rn_init(); 1633190712Sphk rn_inithead(&rhead, 32); 163418316Swollman 163518316Swollman /* mark all of the slots in the table free */ 163618316Swollman ag_avail = ag_slots; 163718316Swollman for (ag = ag_slots, i = 1; i < NUM_AG_SLOTS; i++) { 163818316Swollman ag->ag_fine = ag+1; 163918316Swollman ag++; 164018316Swollman } 164118316Swollman} 164218316Swollman 164318316Swollman 164418316Swollman#ifdef _HAVE_SIN_LEN 164564131Ssheldonhstatic struct sockaddr_in dst_sock = {sizeof(dst_sock), AF_INET, 0, {0}, {0}}; 164664131Ssheldonhstatic struct sockaddr_in mask_sock = {sizeof(mask_sock), AF_INET, 0, {0}, {0}}; 164718316Swollman#else 164818316Swollmanstatic struct sockaddr_in_new dst_sock = {_SIN_ADDR_SIZE, AF_INET}; 164918316Swollmanstatic struct sockaddr_in_new mask_sock = {_SIN_ADDR_SIZE, AF_INET}; 165018316Swollman#endif 165118316Swollman 165218316Swollman 165346303Smarkmstatic void 165418316Swollmanset_need_flash(void) 165518316Swollman{ 165618316Swollman if (!need_flash) { 165718316Swollman need_flash = 1; 165818316Swollman /* Do not send the flash update immediately. Wait a little 165918316Swollman * while to hear from other routers. 166018316Swollman */ 166118316Swollman no_flash.tv_sec = now.tv_sec + MIN_WAITTIME; 166218316Swollman } 166318316Swollman} 166418316Swollman 166518316Swollman 166618316Swollman/* Get a particular routing table entry 166718316Swollman */ 166818316Swollmanstruct rt_entry * 166918316Swollmanrtget(naddr dst, naddr mask) 167018316Swollman{ 167118316Swollman struct rt_entry *rt; 167218316Swollman 167318316Swollman dst_sock.sin_addr.s_addr = dst; 167464131Ssheldonh mask_sock.sin_addr.s_addr = htonl(mask); 167518316Swollman masktrim(&mask_sock); 167618316Swollman rt = (struct rt_entry *)rhead->rnh_lookup(&dst_sock,&mask_sock,rhead); 167718316Swollman if (!rt 167818316Swollman || rt->rt_dst != dst 167918316Swollman || rt->rt_mask != mask) 168018316Swollman return 0; 168118316Swollman 168218316Swollman return rt; 168318316Swollman} 168418316Swollman 168518316Swollman 168618316Swollman/* Find a route to dst as the kernel would. 168718316Swollman */ 168818316Swollmanstruct rt_entry * 168918316Swollmanrtfind(naddr dst) 169018316Swollman{ 169118316Swollman dst_sock.sin_addr.s_addr = dst; 169218316Swollman return (struct rt_entry *)rhead->rnh_matchaddr(&dst_sock, rhead); 169318316Swollman} 169418316Swollman 169518316Swollman 169618316Swollman/* add a route to the table 169718316Swollman */ 169818316Swollmanvoid 169918316Swollmanrtadd(naddr dst, 170018316Swollman naddr mask, 170146303Smarkm u_int state, /* rt_state for the entry */ 170246303Smarkm struct rt_spare *new) 170318316Swollman{ 170418316Swollman struct rt_entry *rt; 170518316Swollman naddr smask; 170618316Swollman int i; 170718316Swollman struct rt_spare *rts; 170818316Swollman 170918316Swollman rt = (struct rt_entry *)rtmalloc(sizeof (*rt), "rtadd"); 171046303Smarkm memset(rt, 0, sizeof(*rt)); 171118316Swollman for (rts = rt->rt_spares, i = NUM_SPARES; i != 0; i--, rts++) 171218316Swollman rts->rts_metric = HOPCNT_INFINITY; 171318316Swollman 171418316Swollman rt->rt_nodes->rn_key = (caddr_t)&rt->rt_dst_sock; 171518316Swollman rt->rt_dst = dst; 171618316Swollman rt->rt_dst_sock.sin_family = AF_INET; 171718316Swollman#ifdef _HAVE_SIN_LEN 171818316Swollman rt->rt_dst_sock.sin_len = dst_sock.sin_len; 171918316Swollman#endif 172018316Swollman if (mask != HOST_MASK) { 172118316Swollman smask = std_mask(dst); 172218316Swollman if ((smask & ~mask) == 0 && mask > smask) 172318316Swollman state |= RS_SUBNET; 172418316Swollman } 172564131Ssheldonh mask_sock.sin_addr.s_addr = htonl(mask); 172618316Swollman masktrim(&mask_sock); 172718316Swollman rt->rt_mask = mask; 172818316Swollman rt->rt_state = state; 172946303Smarkm rt->rt_spares[0] = *new; 173018316Swollman rt->rt_time = now.tv_sec; 173118316Swollman rt->rt_poison_metric = HOPCNT_INFINITY; 173218316Swollman rt->rt_seqno = update_seqno; 173318316Swollman 173418316Swollman if (++total_routes == MAX_ROUTES) 173518316Swollman msglog("have maximum (%d) routes", total_routes); 173618316Swollman if (TRACEACTIONS) 173718316Swollman trace_add_del("Add", rt); 173818316Swollman 173918316Swollman need_kern.tv_sec = now.tv_sec; 174018316Swollman set_need_flash(); 174118316Swollman 174218316Swollman if (0 == rhead->rnh_addaddr(&rt->rt_dst_sock, &mask_sock, 174318316Swollman rhead, rt->rt_nodes)) { 174446303Smarkm msglog("rnh_addaddr() failed for %s mask=%#lx", 174546303Smarkm naddr_ntoa(dst), (u_long)mask); 174661186Sjlemon free(rt); 174718316Swollman } 174818316Swollman} 174918316Swollman 175018316Swollman 175118316Swollman/* notice a changed route 175218316Swollman */ 175318316Swollmanvoid 175418316Swollmanrtchange(struct rt_entry *rt, 175518316Swollman u_int state, /* new state bits */ 175646303Smarkm struct rt_spare *new, 175718316Swollman char *label) 175818316Swollman{ 175946303Smarkm if (rt->rt_metric != new->rts_metric) { 176018316Swollman /* Fix the kernel immediately if it seems the route 176118316Swollman * has gone bad, since there may be a working route that 176218316Swollman * aggregates this route. 176318316Swollman */ 176446303Smarkm if (new->rts_metric == HOPCNT_INFINITY) { 176518316Swollman need_kern.tv_sec = now.tv_sec; 176646303Smarkm if (new->rts_time >= now.tv_sec - EXPIRE_TIME) 176746303Smarkm new->rts_time = now.tv_sec - EXPIRE_TIME; 176818316Swollman } 176918316Swollman rt->rt_seqno = update_seqno; 177018316Swollman set_need_flash(); 177118316Swollman } 177218316Swollman 177346303Smarkm if (rt->rt_gate != new->rts_gate) { 177418316Swollman need_kern.tv_sec = now.tv_sec; 177518316Swollman rt->rt_seqno = update_seqno; 177618316Swollman set_need_flash(); 177718316Swollman } 177818316Swollman 177918316Swollman state |= (rt->rt_state & RS_SUBNET); 178018316Swollman 178118316Swollman /* Keep various things from deciding ageless routes are stale. 178218316Swollman */ 178346303Smarkm if (!AGE_RT(state, new->rts_ifp)) 178446303Smarkm new->rts_time = now.tv_sec; 178518316Swollman 178618316Swollman if (TRACEACTIONS) 178746303Smarkm trace_change(rt, state, new, 178818316Swollman label ? label : "Chg "); 178918316Swollman 179018316Swollman rt->rt_state = state; 179146303Smarkm rt->rt_spares[0] = *new; 179218316Swollman} 179318316Swollman 179418316Swollman 179518316Swollman/* check for a better route among the spares 179618316Swollman */ 179718316Swollmanstatic struct rt_spare * 179818316Swollmanrts_better(struct rt_entry *rt) 179918316Swollman{ 180018316Swollman struct rt_spare *rts, *rts1; 180118316Swollman int i; 180218316Swollman 180318316Swollman /* find the best alternative among the spares */ 180418316Swollman rts = rt->rt_spares+1; 180518316Swollman for (i = NUM_SPARES, rts1 = rts+1; i > 2; i--, rts1++) { 180618316Swollman if (BETTER_LINK(rt,rts1,rts)) 180718316Swollman rts = rts1; 180818316Swollman } 180918316Swollman 181018316Swollman return rts; 181118316Swollman} 181218316Swollman 181318316Swollman 181418316Swollman/* switch to a backup route 181518316Swollman */ 181618316Swollmanvoid 181718316Swollmanrtswitch(struct rt_entry *rt, 181818316Swollman struct rt_spare *rts) 181918316Swollman{ 182018316Swollman struct rt_spare swap; 182118316Swollman char label[10]; 182218316Swollman 182318316Swollman 182418316Swollman /* Do not change permanent routes */ 182518316Swollman if (0 != (rt->rt_state & (RS_MHOME | RS_STATIC | RS_RDISC 182618316Swollman | RS_NET_SYN | RS_IF))) 182718316Swollman return; 182818316Swollman 182918316Swollman /* find the best alternative among the spares */ 183018316Swollman if (rts == 0) 183118316Swollman rts = rts_better(rt); 183218316Swollman 183318316Swollman /* Do not bother if it is not worthwhile. 183418316Swollman */ 183518316Swollman if (!BETTER_LINK(rt, rts, rt->rt_spares)) 183618316Swollman return; 183718316Swollman 183818316Swollman swap = rt->rt_spares[0]; 183946303Smarkm (void)sprintf(label, "Use #%d", (int)(rts - rt->rt_spares)); 184046303Smarkm rtchange(rt, rt->rt_state & ~(RS_NET_SYN | RS_RDISC), rts, label); 184146303Smarkm if (swap.rts_metric == HOPCNT_INFINITY) { 184246303Smarkm *rts = rts_empty; 184346303Smarkm } else { 184446303Smarkm *rts = swap; 184546303Smarkm } 184618316Swollman} 184718316Swollman 184818316Swollman 184918316Swollmanvoid 185018316Swollmanrtdelete(struct rt_entry *rt) 185118316Swollman{ 185218316Swollman struct khash *k; 185318316Swollman 185418316Swollman 185518316Swollman if (TRACEACTIONS) 185618316Swollman trace_add_del("Del", rt); 185718316Swollman 185818316Swollman k = kern_find(rt->rt_dst, rt->rt_mask, 0); 185918316Swollman if (k != 0) { 186018316Swollman k->k_state |= KS_DELETE; 186118316Swollman need_kern.tv_sec = now.tv_sec; 186218316Swollman } 186318316Swollman 186418316Swollman dst_sock.sin_addr.s_addr = rt->rt_dst; 186564131Ssheldonh mask_sock.sin_addr.s_addr = htonl(rt->rt_mask); 186618316Swollman masktrim(&mask_sock); 186718316Swollman if (rt != (struct rt_entry *)rhead->rnh_deladdr(&dst_sock, &mask_sock, 186818316Swollman rhead)) { 186918316Swollman msglog("rnh_deladdr() failed"); 187018316Swollman } else { 187118316Swollman free(rt); 187218316Swollman total_routes--; 187318316Swollman } 187418316Swollman} 187518316Swollman 187618316Swollman 187746303Smarkmvoid 187846303Smarkmrts_delete(struct rt_entry *rt, 187946303Smarkm struct rt_spare *rts) 188046303Smarkm{ 188146303Smarkm trace_upslot(rt, rts, &rts_empty); 188246303Smarkm *rts = rts_empty; 188346303Smarkm} 188446303Smarkm 188546303Smarkm 188618316Swollman/* Get rid of a bad route, and try to switch to a replacement. 188718316Swollman */ 1888190715Sphkstatic void 188918316Swollmanrtbad(struct rt_entry *rt) 189018316Swollman{ 189146303Smarkm struct rt_spare new; 189246303Smarkm 189318316Swollman /* Poison the route */ 189446303Smarkm new = rt->rt_spares[0]; 189546303Smarkm new.rts_metric = HOPCNT_INFINITY; 189646303Smarkm rtchange(rt, rt->rt_state & ~(RS_IF | RS_LOCAL | RS_STATIC), &new, 0); 189718316Swollman rtswitch(rt, 0); 189818316Swollman} 189918316Swollman 190018316Swollman 190118316Swollman/* Junk a RS_NET_SYN or RS_LOCAL route, 190218316Swollman * unless it is needed by another interface. 190318316Swollman */ 190418316Swollmanvoid 190518316Swollmanrtbad_sub(struct rt_entry *rt) 190618316Swollman{ 190718316Swollman struct interface *ifp, *ifp1; 190818316Swollman struct intnet *intnetp; 190918316Swollman u_int state; 191018316Swollman 191118316Swollman 191218316Swollman ifp1 = 0; 191318316Swollman state = 0; 191418316Swollman 191518316Swollman if (rt->rt_state & RS_LOCAL) { 191618316Swollman /* Is this the route through loopback for the interface? 191718316Swollman * If so, see if it is used by any other interfaces, such 191818316Swollman * as a point-to-point interface with the same local address. 191918316Swollman */ 1920190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 192118316Swollman /* Retain it if another interface needs it. 192218316Swollman */ 192318316Swollman if (ifp->int_addr == rt->rt_ifp->int_addr) { 192418316Swollman state |= RS_LOCAL; 192518316Swollman ifp1 = ifp; 192618316Swollman break; 192718316Swollman } 192818316Swollman } 192918316Swollman 193018316Swollman } 193118316Swollman 193218316Swollman if (!(state & RS_LOCAL)) { 193318316Swollman /* Retain RIPv1 logical network route if there is another 193418316Swollman * interface that justifies it. 193518316Swollman */ 193618316Swollman if (rt->rt_state & RS_NET_SYN) { 1937190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 193818316Swollman if ((ifp->int_state & IS_NEED_NET_SYN) 193918316Swollman && rt->rt_mask == ifp->int_std_mask 194018316Swollman && rt->rt_dst == ifp->int_std_addr) { 194118316Swollman state |= RS_NET_SYN; 194218316Swollman ifp1 = ifp; 194318316Swollman break; 194418316Swollman } 194518316Swollman } 194618316Swollman } 194718316Swollman 194818316Swollman /* or if there is an authority route that needs it. */ 194918316Swollman for (intnetp = intnets; 195018316Swollman intnetp != 0; 195118316Swollman intnetp = intnetp->intnet_next) { 195218316Swollman if (intnetp->intnet_addr == rt->rt_dst 195318316Swollman && intnetp->intnet_mask == rt->rt_mask) { 195418316Swollman state |= (RS_NET_SYN | RS_NET_INT); 195518316Swollman break; 195618316Swollman } 195718316Swollman } 195818316Swollman } 195918316Swollman 196018316Swollman if (ifp1 != 0 || (state & RS_NET_SYN)) { 196146303Smarkm struct rt_spare new = rt->rt_spares[0]; 196246303Smarkm new.rts_ifp = ifp1; 196346303Smarkm rtchange(rt, ((rt->rt_state & ~(RS_NET_SYN|RS_LOCAL)) | state), 196446303Smarkm &new, 0); 196518316Swollman } else { 196618316Swollman rtbad(rt); 196718316Swollman } 196818316Swollman} 196918316Swollman 197018316Swollman 197118316Swollman/* Called while walking the table looking for sick interfaces 197218316Swollman * or after a time change. 197318316Swollman */ 197418316Swollman/* ARGSUSED */ 197518316Swollmanint 197618316Swollmanwalk_bad(struct radix_node *rn, 197746303Smarkm struct walkarg *argp UNUSED) 197818316Swollman{ 197918316Swollman#define RT ((struct rt_entry *)rn) 198018316Swollman struct rt_spare *rts; 198118316Swollman int i; 198218316Swollman 198318316Swollman 198418316Swollman /* fix any spare routes through the interface 198518316Swollman */ 198618316Swollman rts = RT->rt_spares; 198718316Swollman for (i = NUM_SPARES; i != 1; i--) { 198818316Swollman rts++; 198946303Smarkm if (rts->rts_metric < HOPCNT_INFINITY 199046303Smarkm && (rts->rts_ifp == 0 199146303Smarkm || (rts->rts_ifp->int_state & IS_BROKE))) 199246303Smarkm rts_delete(RT, rts); 199318316Swollman } 199418316Swollman 199518316Swollman /* Deal with the main route 199618316Swollman */ 199718316Swollman /* finished if it has been handled before or if its interface is ok 199818316Swollman */ 199918316Swollman if (RT->rt_ifp == 0 || !(RT->rt_ifp->int_state & IS_BROKE)) 200018316Swollman return 0; 200118316Swollman 200218316Swollman /* Bad routes for other than interfaces are easy. 200318316Swollman */ 200418316Swollman if (0 == (RT->rt_state & (RS_IF | RS_NET_SYN | RS_LOCAL))) { 200518316Swollman rtbad(RT); 200618316Swollman return 0; 200718316Swollman } 200818316Swollman 200918316Swollman rtbad_sub(RT); 201018316Swollman return 0; 201118316Swollman#undef RT 201218316Swollman} 201318316Swollman 201418316Swollman 201518316Swollman/* Check the age of an individual route. 201618316Swollman */ 201718316Swollman/* ARGSUSED */ 201818316Swollmanstatic int 201918316Swollmanwalk_age(struct radix_node *rn, 202046303Smarkm struct walkarg *argp UNUSED) 202118316Swollman{ 202218316Swollman#define RT ((struct rt_entry *)rn) 202318316Swollman struct interface *ifp; 202418316Swollman struct rt_spare *rts; 202518316Swollman int i; 202618316Swollman 202718316Swollman 202818316Swollman /* age all of the spare routes, including the primary route 202918316Swollman * currently in use 203018316Swollman */ 203118316Swollman rts = RT->rt_spares; 203218316Swollman for (i = NUM_SPARES; i != 0; i--, rts++) { 203318316Swollman 203418316Swollman ifp = rts->rts_ifp; 203518316Swollman if (i == NUM_SPARES) { 203618316Swollman if (!AGE_RT(RT->rt_state, ifp)) { 203718316Swollman /* Keep various things from deciding ageless 203818316Swollman * routes are stale 203918316Swollman */ 204018316Swollman rts->rts_time = now.tv_sec; 204118316Swollman continue; 204218316Swollman } 204318316Swollman 204418316Swollman /* forget RIP routes after RIP has been turned off. 204518316Swollman */ 204618316Swollman if (rip_sock < 0) { 204718316Swollman rtdelete(RT); 204818316Swollman return 0; 204918316Swollman } 205018316Swollman } 205118316Swollman 205218316Swollman /* age failing routes 205318316Swollman */ 205418316Swollman if (age_bad_gate == rts->rts_gate 205518316Swollman && rts->rts_time >= now_stale) { 205618316Swollman rts->rts_time -= SUPPLY_INTERVAL; 205718316Swollman } 205818316Swollman 205918316Swollman /* trash the spare routes when they go bad */ 206018316Swollman if (rts->rts_metric < HOPCNT_INFINITY 206146303Smarkm && now_garbage > rts->rts_time 206246303Smarkm && i != NUM_SPARES) 206346303Smarkm rts_delete(RT, rts); 206418316Swollman } 206518316Swollman 206618316Swollman 206718316Swollman /* finished if the active route is still fresh */ 206818316Swollman if (now_stale <= RT->rt_time) 206918316Swollman return 0; 207018316Swollman 207118316Swollman /* try to switch to an alternative */ 207218316Swollman rtswitch(RT, 0); 207318316Swollman 2074229778Suqs /* Delete a dead route after it has been publicly mourned. */ 207518316Swollman if (now_garbage > RT->rt_time) { 207618316Swollman rtdelete(RT); 207718316Swollman return 0; 207818316Swollman } 207918316Swollman 208018316Swollman /* Start poisoning a bad route before deleting it. */ 208146303Smarkm if (now.tv_sec - RT->rt_time > EXPIRE_TIME) { 208246303Smarkm struct rt_spare new = RT->rt_spares[0]; 208346303Smarkm new.rts_metric = HOPCNT_INFINITY; 208446303Smarkm rtchange(RT, RT->rt_state, &new, 0); 208546303Smarkm } 208618316Swollman return 0; 208718316Swollman} 208818316Swollman 208918316Swollman 209018316Swollman/* Watch for dead routes and interfaces. 209118316Swollman */ 209218316Swollmanvoid 209318316Swollmanage(naddr bad_gate) 209418316Swollman{ 209518316Swollman struct interface *ifp; 209619885Swollman int need_query = 0; 209718316Swollman 209819885Swollman /* If not listening to RIP, there is no need to age the routes in 209919885Swollman * the table. 210019885Swollman */ 210119885Swollman age_timer.tv_sec = (now.tv_sec 210219885Swollman + ((rip_sock < 0) ? NEVER : SUPPLY_INTERVAL)); 210318316Swollman 210419885Swollman /* Check for dead IS_REMOTE interfaces by timing their 210519885Swollman * transmissions. 210619885Swollman */ 2107190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 210819885Swollman if (!(ifp->int_state & IS_REMOTE)) 210919885Swollman continue; 211018316Swollman 211119885Swollman /* ignore unreachable remote interfaces */ 211219885Swollman if (!check_remote(ifp)) 211319885Swollman continue; 211446303Smarkm 211519885Swollman /* Restore remote interface that has become reachable 211618316Swollman */ 211719885Swollman if (ifp->int_state & IS_BROKE) 211819885Swollman if_ok(ifp, "remote "); 211918316Swollman 212019885Swollman if (ifp->int_act_time != NEVER 212119885Swollman && now.tv_sec - ifp->int_act_time > EXPIRE_TIME) { 212219885Swollman msglog("remote interface %s to %s timed out after" 212346303Smarkm " %ld:%ld", 212419885Swollman ifp->int_name, 212519885Swollman naddr_ntoa(ifp->int_dstaddr), 2126190712Sphk (long)(now.tv_sec - ifp->int_act_time)/60, 2127190712Sphk (long)(now.tv_sec - ifp->int_act_time)%60); 212819885Swollman if_sick(ifp); 212918316Swollman } 213019885Swollman 213119885Swollman /* If we have not heard from the other router 213219885Swollman * recently, ask it. 213319885Swollman */ 213419885Swollman if (now.tv_sec >= ifp->int_query_time) { 213519885Swollman ifp->int_query_time = NEVER; 213619885Swollman need_query = 1; 213719885Swollman } 213818316Swollman } 213918316Swollman 214018316Swollman /* Age routes. */ 214118316Swollman age_bad_gate = bad_gate; 214218316Swollman (void)rn_walktree(rhead, walk_age, 0); 214318316Swollman 214446303Smarkm /* delete old redirected routes to keep the kernel table small 214546303Smarkm * and prevent blackholes 214646303Smarkm */ 214746303Smarkm del_redirects(bad_gate, now.tv_sec-STALE_TIME); 214846303Smarkm 214918316Swollman /* Update the kernel routing table. */ 215018316Swollman fix_kern(); 215119885Swollman 215219885Swollman /* poke reticent remote gateways */ 215319885Swollman if (need_query) 215419885Swollman rip_query(); 215518316Swollman} 2156