10Sstevel@tonic-gate /*
2*11418SSowmini.Varadhan@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
30Sstevel@tonic-gate * Use is subject to license terms.
40Sstevel@tonic-gate *
50Sstevel@tonic-gate * Copyright (c) 1983, 1988, 1993
60Sstevel@tonic-gate * The Regents of the University of California. All rights reserved.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without
90Sstevel@tonic-gate * modification, are permitted provided that the following conditions
100Sstevel@tonic-gate * are met:
110Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
120Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer.
130Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
140Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the
150Sstevel@tonic-gate * documentation and/or other materials provided with the distribution.
160Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software
170Sstevel@tonic-gate * must display the following acknowledgment:
180Sstevel@tonic-gate * This product includes software developed by the University of
190Sstevel@tonic-gate * California, Berkeley and its contributors.
200Sstevel@tonic-gate * 4. Neither the name of the University nor the names of its contributors
210Sstevel@tonic-gate * may be used to endorse or promote products derived from this software
220Sstevel@tonic-gate * without specific prior written permission.
230Sstevel@tonic-gate *
240Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
250Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
260Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
270Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
280Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
290Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
300Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
310Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
320Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
330Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
340Sstevel@tonic-gate * SUCH DAMAGE.
350Sstevel@tonic-gate *
360Sstevel@tonic-gate * $FreeBSD: src/sbin/routed/table.c,v 1.15 2000/08/11 08:24:38 sheldonh Exp $
370Sstevel@tonic-gate */
380Sstevel@tonic-gate
390Sstevel@tonic-gate #include "defs.h"
400Sstevel@tonic-gate #include <fcntl.h>
410Sstevel@tonic-gate #include <stropts.h>
420Sstevel@tonic-gate #include <sys/tihdr.h>
430Sstevel@tonic-gate #include <inet/mib2.h>
440Sstevel@tonic-gate #include <inet/ip.h>
450Sstevel@tonic-gate
460Sstevel@tonic-gate /* This structure is used to store a disassembled routing socket message. */
470Sstevel@tonic-gate struct rt_addrinfo {
480Sstevel@tonic-gate int rti_addrs;
490Sstevel@tonic-gate struct sockaddr_storage *rti_info[RTAX_MAX];
500Sstevel@tonic-gate };
510Sstevel@tonic-gate
520Sstevel@tonic-gate static struct rt_spare *rts_better(struct rt_entry *);
530Sstevel@tonic-gate static struct rt_spare rts_empty = EMPTY_RT_SPARE;
540Sstevel@tonic-gate static void set_need_flash(void);
550Sstevel@tonic-gate static void rtbad(struct rt_entry *, struct interface *);
560Sstevel@tonic-gate static int rt_xaddrs(struct rt_addrinfo *, struct sockaddr_storage *,
570Sstevel@tonic-gate char *, int);
580Sstevel@tonic-gate static struct interface *gwkludge_iflookup(in_addr_t, in_addr_t, in_addr_t);
597738SRishi.Srivatsavai@Sun.COM static struct interface *lifp_iflookup(in_addr_t, const char *);
600Sstevel@tonic-gate
610Sstevel@tonic-gate struct radix_node_head *rhead; /* root of the radix tree */
620Sstevel@tonic-gate
630Sstevel@tonic-gate /* Flash update needed. _B_TRUE to suppress the 1st. */
640Sstevel@tonic-gate boolean_t need_flash = _B_TRUE;
650Sstevel@tonic-gate
660Sstevel@tonic-gate struct timeval age_timer; /* next check of old routes */
670Sstevel@tonic-gate struct timeval need_kern = { /* need to update kernel table */
680Sstevel@tonic-gate EPOCH+MIN_WAITTIME-1, 0
690Sstevel@tonic-gate };
700Sstevel@tonic-gate
710Sstevel@tonic-gate static uint32_t total_routes;
720Sstevel@tonic-gate
730Sstevel@tonic-gate #define ROUNDUP_LONG(a) \
740Sstevel@tonic-gate ((a) > 0 ? (1 + (((a) - 1) | (sizeof (long) - 1))) : sizeof (long))
750Sstevel@tonic-gate
760Sstevel@tonic-gate /*
770Sstevel@tonic-gate * It is desirable to "aggregate" routes, to combine differing routes of
780Sstevel@tonic-gate * the same metric and next hop into a common route with a smaller netmask
790Sstevel@tonic-gate * or to suppress redundant routes, routes that add no information to
800Sstevel@tonic-gate * routes with smaller netmasks.
810Sstevel@tonic-gate *
820Sstevel@tonic-gate * A route is redundant if and only if any and all routes with smaller
830Sstevel@tonic-gate * but matching netmasks and nets are the same. Since routes are
840Sstevel@tonic-gate * kept sorted in the radix tree, redundant routes always come second.
850Sstevel@tonic-gate *
860Sstevel@tonic-gate * There are two kinds of aggregations. First, two routes of the same bit
870Sstevel@tonic-gate * mask and differing only in the least significant bit of the network
880Sstevel@tonic-gate * number can be combined into a single route with a coarser mask.
890Sstevel@tonic-gate *
900Sstevel@tonic-gate * Second, a route can be suppressed in favor of another route with a more
910Sstevel@tonic-gate * coarse mask provided no incompatible routes with intermediate masks
920Sstevel@tonic-gate * are present. The second kind of aggregation involves suppressing routes.
930Sstevel@tonic-gate * A route must not be suppressed if an incompatible route exists with
940Sstevel@tonic-gate * an intermediate mask, since the suppressed route would be covered
950Sstevel@tonic-gate * by the intermediate.
960Sstevel@tonic-gate *
970Sstevel@tonic-gate * This code relies on the radix tree walk encountering routes
980Sstevel@tonic-gate * sorted first by address, with the smallest address first.
990Sstevel@tonic-gate */
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate static struct ag_info ag_slots[NUM_AG_SLOTS], *ag_avail, *ag_corsest,
1020Sstevel@tonic-gate *ag_finest;
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate #ifdef DEBUG_AG
1050Sstevel@tonic-gate #define CHECK_AG() do { int acnt = 0; struct ag_info *cag; \
1060Sstevel@tonic-gate for (cag = ag_avail; cag != NULL; cag = cag->ag_fine) \
1070Sstevel@tonic-gate acnt++; \
1080Sstevel@tonic-gate for (cag = ag_corsest; cag != NULL; cag = cag->ag_fine) \
1090Sstevel@tonic-gate acnt++; \
1100Sstevel@tonic-gate if (acnt != NUM_AG_SLOTS) \
1110Sstevel@tonic-gate abort(); \
1120Sstevel@tonic-gate } while (_B_FALSE)
1130Sstevel@tonic-gate #else
1140Sstevel@tonic-gate #define CHECK_AG() (void)0
1150Sstevel@tonic-gate #endif
1160Sstevel@tonic-gate
1170Sstevel@tonic-gate
1180Sstevel@tonic-gate /*
1190Sstevel@tonic-gate * Output the contents of an aggregation table slot.
1200Sstevel@tonic-gate * This function must always be immediately followed with the deletion
1210Sstevel@tonic-gate * of the target slot.
1220Sstevel@tonic-gate */
1230Sstevel@tonic-gate static void
ag_out(struct ag_info * ag,void (* out)(struct ag_info *))1240Sstevel@tonic-gate ag_out(struct ag_info *ag, void (*out)(struct ag_info *))
1250Sstevel@tonic-gate {
1260Sstevel@tonic-gate struct ag_info *ag_cors;
1270Sstevel@tonic-gate uint32_t bit;
1280Sstevel@tonic-gate
1290Sstevel@tonic-gate
1300Sstevel@tonic-gate /* Forget it if this route should not be output for split-horizon. */
1310Sstevel@tonic-gate if (ag->ag_state & AGS_SPLIT_HZ)
1320Sstevel@tonic-gate return;
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate /*
1350Sstevel@tonic-gate * If we output both the even and odd twins, then the immediate parent,
1360Sstevel@tonic-gate * if it is present, is redundant, unless the parent manages to
1370Sstevel@tonic-gate * aggregate into something coarser.
1380Sstevel@tonic-gate * On successive calls, this code detects the even and odd twins,
1390Sstevel@tonic-gate * and marks the parent.
1400Sstevel@tonic-gate *
1410Sstevel@tonic-gate * Note that the order in which the radix tree code emits routes
1420Sstevel@tonic-gate * ensures that the twins are seen before the parent is emitted.
1430Sstevel@tonic-gate */
1440Sstevel@tonic-gate ag_cors = ag->ag_cors;
1450Sstevel@tonic-gate if (ag_cors != NULL &&
1460Sstevel@tonic-gate ag_cors->ag_mask == (ag->ag_mask << 1) &&
1470Sstevel@tonic-gate ag_cors->ag_dst_h == (ag->ag_dst_h & ag_cors->ag_mask)) {
1480Sstevel@tonic-gate ag_cors->ag_state |= ((ag_cors->ag_dst_h == ag->ag_dst_h) ?
1490Sstevel@tonic-gate AGS_REDUN0 : AGS_REDUN1);
1500Sstevel@tonic-gate }
1510Sstevel@tonic-gate
1520Sstevel@tonic-gate /*
1530Sstevel@tonic-gate * Skip it if this route is itself redundant.
1540Sstevel@tonic-gate *
1550Sstevel@tonic-gate * It is ok to change the contents of the slot here, since it is
1560Sstevel@tonic-gate * always deleted next.
1570Sstevel@tonic-gate */
1580Sstevel@tonic-gate if (ag->ag_state & AGS_REDUN0) {
1590Sstevel@tonic-gate if (ag->ag_state & AGS_REDUN1)
1600Sstevel@tonic-gate return; /* quit if fully redundant */
1610Sstevel@tonic-gate /* make it finer if it is half-redundant */
1620Sstevel@tonic-gate bit = (-ag->ag_mask) >> 1;
1630Sstevel@tonic-gate ag->ag_dst_h |= bit;
1640Sstevel@tonic-gate ag->ag_mask |= bit;
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate } else if (ag->ag_state & AGS_REDUN1) {
1670Sstevel@tonic-gate /* make it finer if it is half-redundant */
1680Sstevel@tonic-gate bit = (-ag->ag_mask) >> 1;
1690Sstevel@tonic-gate ag->ag_mask |= bit;
1700Sstevel@tonic-gate }
1710Sstevel@tonic-gate out(ag);
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate static void
ag_del(struct ag_info * ag)1760Sstevel@tonic-gate ag_del(struct ag_info *ag)
1770Sstevel@tonic-gate {
1780Sstevel@tonic-gate CHECK_AG();
1790Sstevel@tonic-gate
1800Sstevel@tonic-gate if (ag->ag_cors == NULL)
1810Sstevel@tonic-gate ag_corsest = ag->ag_fine;
1820Sstevel@tonic-gate else
1830Sstevel@tonic-gate ag->ag_cors->ag_fine = ag->ag_fine;
1840Sstevel@tonic-gate
1850Sstevel@tonic-gate if (ag->ag_fine == NULL)
1860Sstevel@tonic-gate ag_finest = ag->ag_cors;
1870Sstevel@tonic-gate else
1880Sstevel@tonic-gate ag->ag_fine->ag_cors = ag->ag_cors;
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate ag->ag_fine = ag_avail;
1910Sstevel@tonic-gate ag_avail = ag;
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate CHECK_AG();
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate /* Look for a route that can suppress the given route. */
1980Sstevel@tonic-gate static struct ag_info *
ag_find_suppressor(struct ag_info * ag)1990Sstevel@tonic-gate ag_find_suppressor(struct ag_info *ag)
2000Sstevel@tonic-gate {
2010Sstevel@tonic-gate struct ag_info *ag_cors;
2020Sstevel@tonic-gate in_addr_t dst_h = ag->ag_dst_h;
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate for (ag_cors = ag->ag_cors; ag_cors != NULL;
2050Sstevel@tonic-gate ag_cors = ag_cors->ag_cors) {
2060Sstevel@tonic-gate
2070Sstevel@tonic-gate if ((dst_h & ag_cors->ag_mask) == ag_cors->ag_dst_h) {
2080Sstevel@tonic-gate /*
2090Sstevel@tonic-gate * We found a route with a coarser mask that covers
2100Sstevel@tonic-gate * the given target. It can suppress the target
2110Sstevel@tonic-gate * only if it has a good enough metric and it
2120Sstevel@tonic-gate * either has the same (gateway, ifp), or if its state
2130Sstevel@tonic-gate * includes AGS_CORS_GATE or the target's state
2140Sstevel@tonic-gate * includes AGS_FINE_GATE.
2150Sstevel@tonic-gate */
2160Sstevel@tonic-gate if (ag_cors->ag_pref <= ag->ag_pref &&
2170Sstevel@tonic-gate (((ag->ag_nhop == ag_cors->ag_nhop) &&
2180Sstevel@tonic-gate (ag->ag_ifp == ag_cors->ag_ifp)) ||
2190Sstevel@tonic-gate ag_cors->ag_state & AGS_CORS_GATE ||
2200Sstevel@tonic-gate ag->ag_state & AGS_FINE_GATE)) {
2210Sstevel@tonic-gate return (ag_cors);
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate }
2250Sstevel@tonic-gate
2260Sstevel@tonic-gate return (NULL);
2270Sstevel@tonic-gate }
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate /*
2310Sstevel@tonic-gate * Flush routes waiting for aggregation.
2320Sstevel@tonic-gate * This must not suppress a route unless it is known that among all routes
2330Sstevel@tonic-gate * with coarser masks that match it, the one with the longest mask is
2340Sstevel@tonic-gate * appropriate. This is ensured by scanning the routes in lexical order,
2350Sstevel@tonic-gate * and with the most restrictive mask first among routes to the same
2360Sstevel@tonic-gate * destination.
2370Sstevel@tonic-gate */
2380Sstevel@tonic-gate void
ag_flush(in_addr_t lim_dst_h,in_addr_t lim_mask,void (* out)(struct ag_info *))2390Sstevel@tonic-gate ag_flush(in_addr_t lim_dst_h, /* flush routes to here */
2400Sstevel@tonic-gate in_addr_t lim_mask, /* matching this mask */
2410Sstevel@tonic-gate void (*out)(struct ag_info *))
2420Sstevel@tonic-gate {
2430Sstevel@tonic-gate struct ag_info *ag, *ag_cors, *ag_supr;
2440Sstevel@tonic-gate in_addr_t dst_h;
2450Sstevel@tonic-gate
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate for (ag = ag_finest; ag != NULL && ag->ag_mask >= lim_mask;
2480Sstevel@tonic-gate ag = ag_cors) {
2490Sstevel@tonic-gate /* Get the next route now, before we delete ag. */
2500Sstevel@tonic-gate ag_cors = ag->ag_cors;
2510Sstevel@tonic-gate
2520Sstevel@tonic-gate /* Work on only the specified routes. */
2530Sstevel@tonic-gate dst_h = ag->ag_dst_h;
2540Sstevel@tonic-gate if ((dst_h & lim_mask) != lim_dst_h)
2550Sstevel@tonic-gate continue;
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate /*
2580Sstevel@tonic-gate * Don't try to suppress the route if its state doesn't
2590Sstevel@tonic-gate * include AGS_SUPPRESS.
2600Sstevel@tonic-gate */
2610Sstevel@tonic-gate if (!(ag->ag_state & AGS_SUPPRESS)) {
2620Sstevel@tonic-gate ag_out(ag, out);
2630Sstevel@tonic-gate ag_del(ag);
2640Sstevel@tonic-gate continue;
2650Sstevel@tonic-gate }
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate ag_supr = ag_find_suppressor(ag);
2680Sstevel@tonic-gate if (ag_supr == NULL) {
2690Sstevel@tonic-gate /*
2700Sstevel@tonic-gate * We didn't find a route which suppresses the
2710Sstevel@tonic-gate * target, so the target can go out.
2720Sstevel@tonic-gate */
2730Sstevel@tonic-gate ag_out(ag, out);
2740Sstevel@tonic-gate } else {
2750Sstevel@tonic-gate /*
2760Sstevel@tonic-gate * We found a route which suppresses the target, so
2770Sstevel@tonic-gate * don't output the target.
2780Sstevel@tonic-gate */
2790Sstevel@tonic-gate if (TRACEACTIONS) {
2800Sstevel@tonic-gate trace_misc("aggregated away %s",
2810Sstevel@tonic-gate rtname(htonl(ag->ag_dst_h), ag->ag_mask,
2820Sstevel@tonic-gate ag->ag_nhop));
2830Sstevel@tonic-gate trace_misc("on coarser route %s",
2840Sstevel@tonic-gate rtname(htonl(ag_supr->ag_dst_h),
2850Sstevel@tonic-gate ag_supr->ag_mask, ag_supr->ag_nhop));
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate /*
2880Sstevel@tonic-gate * If the suppressed target was redundant, then
2890Sstevel@tonic-gate * mark the suppressor as redundant.
2900Sstevel@tonic-gate */
2910Sstevel@tonic-gate if (AG_IS_REDUN(ag->ag_state) &&
2920Sstevel@tonic-gate ag_supr->ag_mask == (ag->ag_mask<<1)) {
2930Sstevel@tonic-gate if (ag_supr->ag_dst_h == dst_h)
2940Sstevel@tonic-gate ag_supr->ag_state |= AGS_REDUN0;
2950Sstevel@tonic-gate else
2960Sstevel@tonic-gate ag_supr->ag_state |= AGS_REDUN1;
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate if (ag->ag_tag != ag_supr->ag_tag)
2990Sstevel@tonic-gate ag_supr->ag_tag = 0;
3000Sstevel@tonic-gate if (ag->ag_nhop != ag_supr->ag_nhop)
3010Sstevel@tonic-gate ag_supr->ag_nhop = 0;
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate
3040Sstevel@tonic-gate /* The route has either been output or suppressed */
3050Sstevel@tonic-gate ag_del(ag);
3060Sstevel@tonic-gate }
3070Sstevel@tonic-gate
3080Sstevel@tonic-gate CHECK_AG();
3090Sstevel@tonic-gate }
3100Sstevel@tonic-gate
3110Sstevel@tonic-gate
3120Sstevel@tonic-gate /* Try to aggregate a route with previous routes. */
3130Sstevel@tonic-gate void
ag_check(in_addr_t dst,in_addr_t mask,in_addr_t gate,struct interface * ifp,in_addr_t nhop,uint8_t metric,uint8_t pref,uint32_t seqno,uint16_t tag,uint16_t state,void (* out)(struct ag_info *))3140Sstevel@tonic-gate ag_check(in_addr_t dst,
3150Sstevel@tonic-gate in_addr_t mask,
3160Sstevel@tonic-gate in_addr_t gate,
3170Sstevel@tonic-gate struct interface *ifp,
3180Sstevel@tonic-gate in_addr_t nhop,
3190Sstevel@tonic-gate uint8_t metric,
3200Sstevel@tonic-gate uint8_t pref,
3210Sstevel@tonic-gate uint32_t seqno,
3220Sstevel@tonic-gate uint16_t tag,
3230Sstevel@tonic-gate uint16_t state,
3240Sstevel@tonic-gate void (*out)(struct ag_info *)) /* output using this */
3250Sstevel@tonic-gate {
3260Sstevel@tonic-gate struct ag_info *ag, *nag, *ag_cors;
3270Sstevel@tonic-gate in_addr_t xaddr;
3280Sstevel@tonic-gate int tmp;
3290Sstevel@tonic-gate struct interface *xifp;
3300Sstevel@tonic-gate
3310Sstevel@tonic-gate dst = ntohl(dst);
3320Sstevel@tonic-gate
3330Sstevel@tonic-gate /*
3340Sstevel@tonic-gate * Don't bother trying to aggregate routes with non-contiguous
3350Sstevel@tonic-gate * subnet masks.
3360Sstevel@tonic-gate *
3370Sstevel@tonic-gate * (X & -X) contains a single bit if and only if X is a power of 2.
3380Sstevel@tonic-gate * (X + (X & -X)) == 0 if and only if X is a power of 2.
3390Sstevel@tonic-gate */
3400Sstevel@tonic-gate if ((mask & -mask) + mask != 0) {
3410Sstevel@tonic-gate struct ag_info nc_ag;
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate nc_ag.ag_dst_h = dst;
3440Sstevel@tonic-gate nc_ag.ag_mask = mask;
3450Sstevel@tonic-gate nc_ag.ag_gate = gate;
3460Sstevel@tonic-gate nc_ag.ag_ifp = ifp;
3470Sstevel@tonic-gate nc_ag.ag_nhop = nhop;
3480Sstevel@tonic-gate nc_ag.ag_metric = metric;
3490Sstevel@tonic-gate nc_ag.ag_pref = pref;
3500Sstevel@tonic-gate nc_ag.ag_tag = tag;
3510Sstevel@tonic-gate nc_ag.ag_state = state;
3520Sstevel@tonic-gate nc_ag.ag_seqno = seqno;
3530Sstevel@tonic-gate out(&nc_ag);
3540Sstevel@tonic-gate return;
3550Sstevel@tonic-gate }
3560Sstevel@tonic-gate
3570Sstevel@tonic-gate /* Search for the right slot in the aggregation table. */
3580Sstevel@tonic-gate ag_cors = NULL;
3590Sstevel@tonic-gate ag = ag_corsest;
3600Sstevel@tonic-gate while (ag != NULL) {
3610Sstevel@tonic-gate if (ag->ag_mask >= mask)
3620Sstevel@tonic-gate break;
3630Sstevel@tonic-gate
3640Sstevel@tonic-gate /*
3650Sstevel@tonic-gate * Suppress old routes (i.e. combine with compatible routes
3660Sstevel@tonic-gate * with coarser masks) as we look for the right slot in the
3670Sstevel@tonic-gate * aggregation table for the new route.
3680Sstevel@tonic-gate * A route to an address less than the current destination
3690Sstevel@tonic-gate * will not be affected by the current route or any route
3700Sstevel@tonic-gate * seen hereafter. That means it is safe to suppress it.
3710Sstevel@tonic-gate * This check keeps poor routes (e.g. with large hop counts)
3720Sstevel@tonic-gate * from preventing suppression of finer routes.
3730Sstevel@tonic-gate */
3740Sstevel@tonic-gate if (ag_cors != NULL && ag->ag_dst_h < dst &&
3750Sstevel@tonic-gate (ag->ag_state & AGS_SUPPRESS) &&
3760Sstevel@tonic-gate ag_cors->ag_pref <= ag->ag_pref &&
3770Sstevel@tonic-gate (ag->ag_dst_h & ag_cors->ag_mask) == ag_cors->ag_dst_h &&
3780Sstevel@tonic-gate ((ag_cors->ag_nhop == ag->ag_nhop &&
3790Sstevel@tonic-gate (ag_cors->ag_ifp == ag->ag_ifp))||
3804513Skcpoon (ag->ag_state & AGS_FINE_GATE) ||
3814513Skcpoon (ag_cors->ag_state & AGS_CORS_GATE))) {
3820Sstevel@tonic-gate /*
3830Sstevel@tonic-gate * If the suppressed target was redundant,
3840Sstevel@tonic-gate * then mark the suppressor redundant.
3850Sstevel@tonic-gate */
3860Sstevel@tonic-gate if (AG_IS_REDUN(ag->ag_state) &&
3870Sstevel@tonic-gate ag_cors->ag_mask == (ag->ag_mask << 1)) {
3880Sstevel@tonic-gate if (ag_cors->ag_dst_h == dst)
3890Sstevel@tonic-gate ag_cors->ag_state |= AGS_REDUN0;
3900Sstevel@tonic-gate else
3910Sstevel@tonic-gate ag_cors->ag_state |= AGS_REDUN1;
3920Sstevel@tonic-gate }
3930Sstevel@tonic-gate if (ag->ag_tag != ag_cors->ag_tag)
3940Sstevel@tonic-gate ag_cors->ag_tag = 0;
3950Sstevel@tonic-gate if (ag->ag_nhop != ag_cors->ag_nhop)
3960Sstevel@tonic-gate ag_cors->ag_nhop = 0;
3970Sstevel@tonic-gate ag_del(ag);
3980Sstevel@tonic-gate CHECK_AG();
3990Sstevel@tonic-gate } else {
4000Sstevel@tonic-gate ag_cors = ag;
4010Sstevel@tonic-gate }
4020Sstevel@tonic-gate ag = ag_cors->ag_fine;
4030Sstevel@tonic-gate }
4040Sstevel@tonic-gate
4050Sstevel@tonic-gate /*
4060Sstevel@tonic-gate * If we find the even/odd twin of the new route, and if the
4070Sstevel@tonic-gate * masks and so forth are equal, we can aggregate them.
4080Sstevel@tonic-gate * We can probably promote one of the pair.
4090Sstevel@tonic-gate *
4100Sstevel@tonic-gate * Since the routes are encountered in lexical order,
4110Sstevel@tonic-gate * the new route must be odd. However, the second or later
4120Sstevel@tonic-gate * times around this loop, it could be the even twin promoted
4130Sstevel@tonic-gate * from the even/odd pair of twins of the finer route.
4140Sstevel@tonic-gate */
4150Sstevel@tonic-gate while (ag != NULL && ag->ag_mask == mask &&
4160Sstevel@tonic-gate ((ag->ag_dst_h ^ dst) & (mask<<1)) == 0) {
4170Sstevel@tonic-gate
4180Sstevel@tonic-gate /*
4190Sstevel@tonic-gate * Here we know the target route and the route in the current
4200Sstevel@tonic-gate * slot have the same netmasks and differ by at most the
4210Sstevel@tonic-gate * last bit. They are either for the same destination, or
4220Sstevel@tonic-gate * for an even/odd pair of destinations.
4230Sstevel@tonic-gate */
4240Sstevel@tonic-gate if (ag->ag_dst_h == dst) {
4250Sstevel@tonic-gate if (ag->ag_nhop == nhop && ag->ag_ifp == ifp) {
4260Sstevel@tonic-gate /*
4270Sstevel@tonic-gate * We have two routes to the same destination,
4280Sstevel@tonic-gate * with the same nexthop and interface.
4290Sstevel@tonic-gate * Routes are encountered in lexical order,
4300Sstevel@tonic-gate * so a route is never promoted until the
4310Sstevel@tonic-gate * parent route is already present. So we
4320Sstevel@tonic-gate * know that the new route is a promoted (or
4330Sstevel@tonic-gate * aggregated) pair and the route already in
4340Sstevel@tonic-gate * the slot is the explicit route.
4350Sstevel@tonic-gate *
4360Sstevel@tonic-gate * Prefer the best route if their metrics
4370Sstevel@tonic-gate * differ, or the aggregated one if not,
4380Sstevel@tonic-gate * following a sort of longest-match rule.
4390Sstevel@tonic-gate */
4400Sstevel@tonic-gate if (pref <= ag->ag_pref) {
4410Sstevel@tonic-gate ag->ag_gate = gate;
4420Sstevel@tonic-gate ag->ag_ifp = ifp;
4430Sstevel@tonic-gate ag->ag_nhop = nhop;
4440Sstevel@tonic-gate ag->ag_tag = tag;
4450Sstevel@tonic-gate ag->ag_metric = metric;
4460Sstevel@tonic-gate ag->ag_pref = pref;
4470Sstevel@tonic-gate if (seqno > ag->ag_seqno)
4480Sstevel@tonic-gate ag->ag_seqno = seqno;
4490Sstevel@tonic-gate tmp = ag->ag_state;
4500Sstevel@tonic-gate ag->ag_state = state;
4510Sstevel@tonic-gate state = tmp;
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate
4540Sstevel@tonic-gate /*
4550Sstevel@tonic-gate * Some bits are set if they are set on
4560Sstevel@tonic-gate * either route, except when the route is
4570Sstevel@tonic-gate * for an interface.
4580Sstevel@tonic-gate */
4590Sstevel@tonic-gate if (!(ag->ag_state & AGS_IF))
4600Sstevel@tonic-gate ag->ag_state |=
4610Sstevel@tonic-gate (state & (AGS_AGGREGATE_EITHER |
4620Sstevel@tonic-gate AGS_REDUN0 | AGS_REDUN1));
4630Sstevel@tonic-gate
4640Sstevel@tonic-gate return;
4650Sstevel@tonic-gate } else {
4660Sstevel@tonic-gate /*
4670Sstevel@tonic-gate * multiple routes to same dest/mask with
4680Sstevel@tonic-gate * differing gate nexthop/or ifp. Flush
4690Sstevel@tonic-gate * both out.
4700Sstevel@tonic-gate */
4710Sstevel@tonic-gate break;
4720Sstevel@tonic-gate }
4730Sstevel@tonic-gate }
4740Sstevel@tonic-gate
4750Sstevel@tonic-gate /*
4760Sstevel@tonic-gate * If one of the routes can be promoted and the other can
4770Sstevel@tonic-gate * be suppressed, it may be possible to combine them or
4780Sstevel@tonic-gate * worthwhile to promote one.
4790Sstevel@tonic-gate *
4800Sstevel@tonic-gate * Any route that can be promoted is always
4810Sstevel@tonic-gate * marked to be eligible to be suppressed.
4820Sstevel@tonic-gate */
4830Sstevel@tonic-gate if (!((state & AGS_AGGREGATE) &&
4840Sstevel@tonic-gate (ag->ag_state & AGS_SUPPRESS)) &&
4850Sstevel@tonic-gate !((ag->ag_state & AGS_AGGREGATE) && (state & AGS_SUPPRESS)))
4860Sstevel@tonic-gate break;
4870Sstevel@tonic-gate
4880Sstevel@tonic-gate /*
4890Sstevel@tonic-gate * A pair of even/odd twin routes can be combined
4900Sstevel@tonic-gate * if either is redundant, or if they are via the
4910Sstevel@tonic-gate * same gateway and have the same metric.
4920Sstevel@tonic-gate */
4930Sstevel@tonic-gate if (AG_IS_REDUN(ag->ag_state) || AG_IS_REDUN(state) ||
4940Sstevel@tonic-gate (ag->ag_nhop == nhop && ag->ag_ifp == ifp &&
4950Sstevel@tonic-gate ag->ag_pref == pref &&
4960Sstevel@tonic-gate (state & ag->ag_state & AGS_AGGREGATE) != 0)) {
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate /*
4990Sstevel@tonic-gate * We have both the even and odd pairs.
5000Sstevel@tonic-gate * Since the routes are encountered in order,
5010Sstevel@tonic-gate * the route in the slot must be the even twin.
5020Sstevel@tonic-gate *
5030Sstevel@tonic-gate * Combine and promote (aggregate) the pair of routes.
5040Sstevel@tonic-gate */
5050Sstevel@tonic-gate if (seqno < ag->ag_seqno)
5060Sstevel@tonic-gate seqno = ag->ag_seqno;
5070Sstevel@tonic-gate if (!AG_IS_REDUN(state))
5080Sstevel@tonic-gate state &= ~AGS_REDUN1;
5090Sstevel@tonic-gate if (AG_IS_REDUN(ag->ag_state))
5100Sstevel@tonic-gate state |= AGS_REDUN0;
5110Sstevel@tonic-gate else
5120Sstevel@tonic-gate state &= ~AGS_REDUN0;
5130Sstevel@tonic-gate state |= (ag->ag_state & AGS_AGGREGATE_EITHER);
5140Sstevel@tonic-gate if (ag->ag_tag != tag)
5150Sstevel@tonic-gate tag = 0;
5160Sstevel@tonic-gate if (ag->ag_nhop != nhop)
5170Sstevel@tonic-gate nhop = 0;
5180Sstevel@tonic-gate
5190Sstevel@tonic-gate /*
5200Sstevel@tonic-gate * Get rid of the even twin that was already
5210Sstevel@tonic-gate * in the slot.
5220Sstevel@tonic-gate */
5230Sstevel@tonic-gate ag_del(ag);
5240Sstevel@tonic-gate
5250Sstevel@tonic-gate } else if (ag->ag_pref >= pref &&
5260Sstevel@tonic-gate (ag->ag_state & AGS_AGGREGATE)) {
5270Sstevel@tonic-gate /*
5280Sstevel@tonic-gate * If we cannot combine the pair, maybe the route
5290Sstevel@tonic-gate * with the worse metric can be promoted.
5300Sstevel@tonic-gate *
5310Sstevel@tonic-gate * Promote the old, even twin, by giving its slot
5320Sstevel@tonic-gate * in the table to the new, odd twin.
5330Sstevel@tonic-gate */
5340Sstevel@tonic-gate ag->ag_dst_h = dst;
5350Sstevel@tonic-gate
5360Sstevel@tonic-gate xaddr = ag->ag_gate;
5370Sstevel@tonic-gate ag->ag_gate = gate;
5380Sstevel@tonic-gate gate = xaddr;
5390Sstevel@tonic-gate
5400Sstevel@tonic-gate xifp = ag->ag_ifp;
5410Sstevel@tonic-gate ag->ag_ifp = ifp;
5420Sstevel@tonic-gate ifp = xifp;
5430Sstevel@tonic-gate
5440Sstevel@tonic-gate xaddr = ag->ag_nhop;
5450Sstevel@tonic-gate ag->ag_nhop = nhop;
5460Sstevel@tonic-gate nhop = xaddr;
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate tmp = ag->ag_tag;
5490Sstevel@tonic-gate ag->ag_tag = tag;
5500Sstevel@tonic-gate tag = tmp;
5510Sstevel@tonic-gate
5520Sstevel@tonic-gate /*
5530Sstevel@tonic-gate * The promoted route is even-redundant only if the
5540Sstevel@tonic-gate * even twin was fully redundant. It is not
5550Sstevel@tonic-gate * odd-redundant because the odd-twin will still be
5560Sstevel@tonic-gate * in the table.
5570Sstevel@tonic-gate */
5580Sstevel@tonic-gate tmp = ag->ag_state;
5590Sstevel@tonic-gate if (!AG_IS_REDUN(tmp))
5600Sstevel@tonic-gate tmp &= ~AGS_REDUN0;
5610Sstevel@tonic-gate tmp &= ~AGS_REDUN1;
5620Sstevel@tonic-gate ag->ag_state = state;
5630Sstevel@tonic-gate state = tmp;
5640Sstevel@tonic-gate
5650Sstevel@tonic-gate tmp = ag->ag_metric;
5660Sstevel@tonic-gate ag->ag_metric = metric;
5670Sstevel@tonic-gate metric = tmp;
5680Sstevel@tonic-gate
5690Sstevel@tonic-gate tmp = ag->ag_pref;
5700Sstevel@tonic-gate ag->ag_pref = pref;
5710Sstevel@tonic-gate pref = tmp;
5720Sstevel@tonic-gate
5730Sstevel@tonic-gate /* take the newest sequence number */
5740Sstevel@tonic-gate if (seqno <= ag->ag_seqno)
5750Sstevel@tonic-gate seqno = ag->ag_seqno;
5760Sstevel@tonic-gate else
5770Sstevel@tonic-gate ag->ag_seqno = seqno;
5780Sstevel@tonic-gate
5790Sstevel@tonic-gate } else {
5800Sstevel@tonic-gate if (!(state & AGS_AGGREGATE))
5810Sstevel@tonic-gate break; /* cannot promote either twin */
5820Sstevel@tonic-gate
5830Sstevel@tonic-gate /*
5840Sstevel@tonic-gate * Promote the new, odd twin by shaving its
5850Sstevel@tonic-gate * mask and address.
5860Sstevel@tonic-gate * The promoted route is odd-redundant only if the
5870Sstevel@tonic-gate * odd twin was fully redundant. It is not
5880Sstevel@tonic-gate * even-redundant because the even twin is still in
5890Sstevel@tonic-gate * the table.
5900Sstevel@tonic-gate */
5910Sstevel@tonic-gate if (!AG_IS_REDUN(state))
5920Sstevel@tonic-gate state &= ~AGS_REDUN1;
5930Sstevel@tonic-gate state &= ~AGS_REDUN0;
5940Sstevel@tonic-gate if (seqno < ag->ag_seqno)
5950Sstevel@tonic-gate seqno = ag->ag_seqno;
5960Sstevel@tonic-gate else
5970Sstevel@tonic-gate ag->ag_seqno = seqno;
5980Sstevel@tonic-gate }
5990Sstevel@tonic-gate
6000Sstevel@tonic-gate mask <<= 1;
6010Sstevel@tonic-gate dst &= mask;
6020Sstevel@tonic-gate
6030Sstevel@tonic-gate if (ag_cors == NULL) {
6040Sstevel@tonic-gate ag = ag_corsest;
6050Sstevel@tonic-gate break;
6060Sstevel@tonic-gate }
6070Sstevel@tonic-gate ag = ag_cors;
6080Sstevel@tonic-gate ag_cors = ag->ag_cors;
6090Sstevel@tonic-gate }
6100Sstevel@tonic-gate
6110Sstevel@tonic-gate /*
6120Sstevel@tonic-gate * When we can no longer promote and combine routes,
6130Sstevel@tonic-gate * flush the old route in the target slot. Also flush
6140Sstevel@tonic-gate * any finer routes that we know will never be aggregated by
6150Sstevel@tonic-gate * the new route.
6160Sstevel@tonic-gate *
6170Sstevel@tonic-gate * In case we moved toward coarser masks,
6180Sstevel@tonic-gate * get back where we belong
6190Sstevel@tonic-gate */
6200Sstevel@tonic-gate if (ag != NULL && ag->ag_mask < mask) {
6210Sstevel@tonic-gate ag_cors = ag;
6220Sstevel@tonic-gate ag = ag->ag_fine;
6230Sstevel@tonic-gate }
6240Sstevel@tonic-gate
6250Sstevel@tonic-gate /* Empty the target slot */
6260Sstevel@tonic-gate if (ag != NULL && ag->ag_mask == mask) {
6270Sstevel@tonic-gate ag_flush(ag->ag_dst_h, ag->ag_mask, out);
6280Sstevel@tonic-gate ag = (ag_cors == NULL) ? ag_corsest : ag_cors->ag_fine;
6290Sstevel@tonic-gate }
6300Sstevel@tonic-gate
6310Sstevel@tonic-gate #ifdef DEBUG_AG
6320Sstevel@tonic-gate if (ag == NULL && ag_cors != ag_finest)
6330Sstevel@tonic-gate abort();
6340Sstevel@tonic-gate if (ag_cors == NULL && ag != ag_corsest)
6350Sstevel@tonic-gate abort();
6360Sstevel@tonic-gate if (ag != NULL && ag->ag_cors != ag_cors)
6370Sstevel@tonic-gate abort();
6380Sstevel@tonic-gate if (ag_cors != NULL && ag_cors->ag_fine != ag)
6390Sstevel@tonic-gate abort();
6400Sstevel@tonic-gate CHECK_AG();
6410Sstevel@tonic-gate #endif
6420Sstevel@tonic-gate
6430Sstevel@tonic-gate /* Save the new route on the end of the table. */
6440Sstevel@tonic-gate nag = ag_avail;
6450Sstevel@tonic-gate ag_avail = nag->ag_fine;
6460Sstevel@tonic-gate
6470Sstevel@tonic-gate nag->ag_dst_h = dst;
6480Sstevel@tonic-gate nag->ag_mask = mask;
6490Sstevel@tonic-gate nag->ag_ifp = ifp;
6500Sstevel@tonic-gate nag->ag_gate = gate;
6510Sstevel@tonic-gate nag->ag_nhop = nhop;
6520Sstevel@tonic-gate nag->ag_metric = metric;
6530Sstevel@tonic-gate nag->ag_pref = pref;
6540Sstevel@tonic-gate nag->ag_tag = tag;
6550Sstevel@tonic-gate nag->ag_state = state;
6560Sstevel@tonic-gate nag->ag_seqno = seqno;
6570Sstevel@tonic-gate
6580Sstevel@tonic-gate nag->ag_fine = ag;
6590Sstevel@tonic-gate if (ag != NULL)
6600Sstevel@tonic-gate ag->ag_cors = nag;
6610Sstevel@tonic-gate else
6620Sstevel@tonic-gate ag_finest = nag;
6630Sstevel@tonic-gate nag->ag_cors = ag_cors;
6640Sstevel@tonic-gate if (ag_cors == NULL)
6650Sstevel@tonic-gate ag_corsest = nag;
6660Sstevel@tonic-gate else
6670Sstevel@tonic-gate ag_cors->ag_fine = nag;
6680Sstevel@tonic-gate CHECK_AG();
6690Sstevel@tonic-gate }
6700Sstevel@tonic-gate
6710Sstevel@tonic-gate
6720Sstevel@tonic-gate static const char *
rtm_type_name(uchar_t type)6730Sstevel@tonic-gate rtm_type_name(uchar_t type)
6740Sstevel@tonic-gate {
6750Sstevel@tonic-gate static const char *rtm_types[] = {
6760Sstevel@tonic-gate "RTM_ADD",
6770Sstevel@tonic-gate "RTM_DELETE",
6780Sstevel@tonic-gate "RTM_CHANGE",
6790Sstevel@tonic-gate "RTM_GET",
6800Sstevel@tonic-gate "RTM_LOSING",
6810Sstevel@tonic-gate "RTM_REDIRECT",
6820Sstevel@tonic-gate "RTM_MISS",
6830Sstevel@tonic-gate "RTM_LOCK",
6840Sstevel@tonic-gate "RTM_OLDADD",
6850Sstevel@tonic-gate "RTM_OLDDEL",
6860Sstevel@tonic-gate "RTM_RESOLVE",
6870Sstevel@tonic-gate "RTM_NEWADDR",
6880Sstevel@tonic-gate "RTM_DELADDR",
6890Sstevel@tonic-gate "RTM_IFINFO",
69011076SCathy.Zhou@Sun.COM "RTM_CHGMADDR",
69111076SCathy.Zhou@Sun.COM "RTM_FREEMADDR"
6920Sstevel@tonic-gate };
6930Sstevel@tonic-gate #define NEW_RTM_PAT "RTM type %#x"
6940Sstevel@tonic-gate static char name0[sizeof (NEW_RTM_PAT) + 2];
6950Sstevel@tonic-gate
6960Sstevel@tonic-gate if (type > sizeof (rtm_types) / sizeof (rtm_types[0]) || type == 0) {
6970Sstevel@tonic-gate (void) snprintf(name0, sizeof (name0), NEW_RTM_PAT, type);
6980Sstevel@tonic-gate return (name0);
6990Sstevel@tonic-gate } else {
7000Sstevel@tonic-gate return (rtm_types[type-1]);
7010Sstevel@tonic-gate }
7020Sstevel@tonic-gate #undef NEW_RTM_PAT
7030Sstevel@tonic-gate }
7040Sstevel@tonic-gate
7050Sstevel@tonic-gate
7060Sstevel@tonic-gate static void
dump_rt_msg(const char * act,struct rt_msghdr * rtm,int mlen)7070Sstevel@tonic-gate dump_rt_msg(const char *act, struct rt_msghdr *rtm, int mlen)
7080Sstevel@tonic-gate {
7090Sstevel@tonic-gate const char *mtype;
7100Sstevel@tonic-gate uchar_t *cp;
7110Sstevel@tonic-gate int i, j;
7120Sstevel@tonic-gate char buffer[16*3 + 1], *ibs;
7130Sstevel@tonic-gate struct ifa_msghdr *ifam;
7140Sstevel@tonic-gate struct if_msghdr *ifm;
7150Sstevel@tonic-gate
7160Sstevel@tonic-gate switch (rtm->rtm_type) {
7170Sstevel@tonic-gate case RTM_NEWADDR:
7180Sstevel@tonic-gate case RTM_DELADDR:
71911076SCathy.Zhou@Sun.COM case RTM_FREEADDR:
72011076SCathy.Zhou@Sun.COM case RTM_CHGADDR:
7210Sstevel@tonic-gate mtype = "ifam";
7220Sstevel@tonic-gate break;
7230Sstevel@tonic-gate case RTM_IFINFO:
7240Sstevel@tonic-gate mtype = "ifm";
7250Sstevel@tonic-gate break;
7260Sstevel@tonic-gate default:
7270Sstevel@tonic-gate mtype = "rtm";
7280Sstevel@tonic-gate break;
7290Sstevel@tonic-gate }
7300Sstevel@tonic-gate trace_misc("%s %s %d bytes", act, mtype, mlen);
7310Sstevel@tonic-gate if (mlen > rtm->rtm_msglen) {
7320Sstevel@tonic-gate trace_misc("%s: extra %d bytes ignored", mtype,
7330Sstevel@tonic-gate mlen - rtm->rtm_msglen);
7340Sstevel@tonic-gate mlen = rtm->rtm_msglen;
7350Sstevel@tonic-gate } else if (mlen < rtm->rtm_msglen) {
7360Sstevel@tonic-gate trace_misc("%s: truncated by %d bytes", mtype,
7370Sstevel@tonic-gate rtm->rtm_msglen - mlen);
7380Sstevel@tonic-gate }
7390Sstevel@tonic-gate switch (rtm->rtm_type) {
7400Sstevel@tonic-gate case RTM_NEWADDR:
7410Sstevel@tonic-gate case RTM_DELADDR:
74211076SCathy.Zhou@Sun.COM case RTM_CHGADDR:
74311076SCathy.Zhou@Sun.COM case RTM_FREEADDR:
7440Sstevel@tonic-gate ifam = (struct ifa_msghdr *)rtm;
7450Sstevel@tonic-gate trace_misc("ifam: msglen %d version %d type %d addrs %X",
7460Sstevel@tonic-gate ifam->ifam_msglen, ifam->ifam_version, ifam->ifam_type,
7470Sstevel@tonic-gate ifam->ifam_addrs);
7480Sstevel@tonic-gate trace_misc("ifam: flags %X index %d metric %d",
7490Sstevel@tonic-gate ifam->ifam_flags, ifam->ifam_index, ifam->ifam_metric);
7500Sstevel@tonic-gate cp = (uchar_t *)(ifam + 1);
7510Sstevel@tonic-gate break;
7520Sstevel@tonic-gate case RTM_IFINFO:
7530Sstevel@tonic-gate ifm = (struct if_msghdr *)rtm;
7540Sstevel@tonic-gate trace_misc("ifm: msglen %d version %d type %d addrs %X",
7550Sstevel@tonic-gate ifm->ifm_msglen, ifm->ifm_version, ifm->ifm_type,
7560Sstevel@tonic-gate ifm->ifm_addrs);
7570Sstevel@tonic-gate ibs = if_bit_string(ifm->ifm_flags, _B_TRUE);
7580Sstevel@tonic-gate if (ibs == NULL) {
7590Sstevel@tonic-gate trace_misc("ifm: flags %#x index %d", ifm->ifm_flags,
7600Sstevel@tonic-gate ifm->ifm_index);
7610Sstevel@tonic-gate } else {
7620Sstevel@tonic-gate trace_misc("ifm: flags %s index %d", ibs,
7630Sstevel@tonic-gate ifm->ifm_index);
7640Sstevel@tonic-gate free(ibs);
7650Sstevel@tonic-gate }
7660Sstevel@tonic-gate cp = (uchar_t *)(ifm + 1);
7670Sstevel@tonic-gate break;
7680Sstevel@tonic-gate default:
7690Sstevel@tonic-gate trace_misc("rtm: msglen %d version %d type %d index %d",
7700Sstevel@tonic-gate rtm->rtm_msglen, rtm->rtm_version, rtm->rtm_type,
7710Sstevel@tonic-gate rtm->rtm_index);
7720Sstevel@tonic-gate trace_misc("rtm: flags %X addrs %X pid %d seq %d",
7730Sstevel@tonic-gate rtm->rtm_flags, rtm->rtm_addrs, rtm->rtm_pid, rtm->rtm_seq);
7740Sstevel@tonic-gate trace_misc("rtm: errno %d use %d inits %X", rtm->rtm_errno,
7750Sstevel@tonic-gate rtm->rtm_use, rtm->rtm_inits);
7760Sstevel@tonic-gate cp = (uchar_t *)(rtm + 1);
7770Sstevel@tonic-gate break;
7780Sstevel@tonic-gate }
7790Sstevel@tonic-gate i = mlen - (cp - (uint8_t *)rtm);
7800Sstevel@tonic-gate while (i > 0) {
7810Sstevel@tonic-gate buffer[0] = '\0';
7820Sstevel@tonic-gate ibs = buffer;
7830Sstevel@tonic-gate for (j = 0; j < 16 && i > 0; j++, i--)
7840Sstevel@tonic-gate ibs += sprintf(ibs, " %02X", *cp++);
7850Sstevel@tonic-gate trace_misc("addr%s", buffer);
7860Sstevel@tonic-gate }
7870Sstevel@tonic-gate }
7880Sstevel@tonic-gate
7890Sstevel@tonic-gate /*
7900Sstevel@tonic-gate * Tell the kernel to add, delete or change a route
7910Sstevel@tonic-gate * Pass k_state from khash in for diagnostic info.
7920Sstevel@tonic-gate */
7930Sstevel@tonic-gate static void
rtioctl(int action,in_addr_t dst,in_addr_t gate,in_addr_t mask,struct interface * ifp,uint8_t metric,int flags)7940Sstevel@tonic-gate rtioctl(int action, /* RTM_DELETE, etc */
7950Sstevel@tonic-gate in_addr_t dst,
7960Sstevel@tonic-gate in_addr_t gate,
7970Sstevel@tonic-gate in_addr_t mask,
7980Sstevel@tonic-gate struct interface *ifp,
7990Sstevel@tonic-gate uint8_t metric,
8000Sstevel@tonic-gate int flags)
8010Sstevel@tonic-gate {
8020Sstevel@tonic-gate static int rt_sock_seqno = 0;
8030Sstevel@tonic-gate struct {
8040Sstevel@tonic-gate struct rt_msghdr w_rtm;
8050Sstevel@tonic-gate struct sockaddr_in w_dst;
8060Sstevel@tonic-gate struct sockaddr_in w_gate;
8070Sstevel@tonic-gate uint8_t w_space[512];
8080Sstevel@tonic-gate } w;
8090Sstevel@tonic-gate struct sockaddr_in w_mask;
8100Sstevel@tonic-gate struct sockaddr_dl w_ifp;
8110Sstevel@tonic-gate uint8_t *cp;
8120Sstevel@tonic-gate long cc;
8130Sstevel@tonic-gate #define PAT " %-10s %s metric=%d flags=%#x"
8140Sstevel@tonic-gate #define ARGS rtm_type_name(action), rtname(dst, mask, gate), metric, flags
8150Sstevel@tonic-gate
8160Sstevel@tonic-gate again:
8170Sstevel@tonic-gate (void) memset(&w, 0, sizeof (w));
8180Sstevel@tonic-gate (void) memset(&w_mask, 0, sizeof (w_mask));
8190Sstevel@tonic-gate (void) memset(&w_ifp, 0, sizeof (w_ifp));
8200Sstevel@tonic-gate cp = w.w_space;
8210Sstevel@tonic-gate w.w_rtm.rtm_msglen = sizeof (struct rt_msghdr) +
8220Sstevel@tonic-gate 2 * ROUNDUP_LONG(sizeof (struct sockaddr_in));
8230Sstevel@tonic-gate w.w_rtm.rtm_version = RTM_VERSION;
8240Sstevel@tonic-gate w.w_rtm.rtm_type = action;
8250Sstevel@tonic-gate w.w_rtm.rtm_flags = flags;
8260Sstevel@tonic-gate w.w_rtm.rtm_seq = ++rt_sock_seqno;
8270Sstevel@tonic-gate w.w_rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
8280Sstevel@tonic-gate if (metric != 0 || action == RTM_CHANGE) {
8290Sstevel@tonic-gate w.w_rtm.rtm_rmx.rmx_hopcount = metric;
8300Sstevel@tonic-gate w.w_rtm.rtm_inits |= RTV_HOPCOUNT;
8310Sstevel@tonic-gate }
8320Sstevel@tonic-gate w.w_dst.sin_family = AF_INET;
8330Sstevel@tonic-gate w.w_dst.sin_addr.s_addr = dst;
8340Sstevel@tonic-gate w.w_gate.sin_family = AF_INET;
8350Sstevel@tonic-gate w.w_gate.sin_addr.s_addr = gate;
8360Sstevel@tonic-gate if (mask == HOST_MASK) {
8370Sstevel@tonic-gate w.w_rtm.rtm_flags |= RTF_HOST;
8380Sstevel@tonic-gate } else {
8390Sstevel@tonic-gate w.w_rtm.rtm_addrs |= RTA_NETMASK;
8400Sstevel@tonic-gate w_mask.sin_family = AF_INET;
8410Sstevel@tonic-gate w_mask.sin_addr.s_addr = htonl(mask);
8420Sstevel@tonic-gate (void) memmove(cp, &w_mask, sizeof (w_mask));
8430Sstevel@tonic-gate cp += ROUNDUP_LONG(sizeof (struct sockaddr_in));
8440Sstevel@tonic-gate w.w_rtm.rtm_msglen += ROUNDUP_LONG(sizeof (struct sockaddr_in));
8450Sstevel@tonic-gate }
8460Sstevel@tonic-gate if (ifp == NULL)
8470Sstevel@tonic-gate ifp = iflookup(gate);
8480Sstevel@tonic-gate
8497738SRishi.Srivatsavai@Sun.COM if (ifp == NULL || (ifp->int_phys == NULL)) {
8500Sstevel@tonic-gate trace_misc("no ifp for" PAT, ARGS);
8510Sstevel@tonic-gate } else {
8520Sstevel@tonic-gate if (ifp->int_phys->phyi_index > UINT16_MAX) {
8530Sstevel@tonic-gate trace_misc("ifindex %d is too big for sdl_index",
8540Sstevel@tonic-gate ifp->int_phys->phyi_index);
8550Sstevel@tonic-gate } else {
8560Sstevel@tonic-gate w_ifp.sdl_family = AF_LINK;
8570Sstevel@tonic-gate w.w_rtm.rtm_addrs |= RTA_IFP;
8580Sstevel@tonic-gate w_ifp.sdl_index = ifp->int_phys->phyi_index;
8590Sstevel@tonic-gate (void) memmove(cp, &w_ifp, sizeof (w_ifp));
8600Sstevel@tonic-gate w.w_rtm.rtm_msglen +=
8610Sstevel@tonic-gate ROUNDUP_LONG(sizeof (struct sockaddr_dl));
8620Sstevel@tonic-gate }
8630Sstevel@tonic-gate }
8640Sstevel@tonic-gate
8650Sstevel@tonic-gate
8660Sstevel@tonic-gate if (!no_install) {
8670Sstevel@tonic-gate if (TRACERTS)
8680Sstevel@tonic-gate dump_rt_msg("write", &w.w_rtm, w.w_rtm.rtm_msglen);
8690Sstevel@tonic-gate cc = write(rt_sock, &w, w.w_rtm.rtm_msglen);
8700Sstevel@tonic-gate if (cc < 0) {
8710Sstevel@tonic-gate if (errno == ESRCH && (action == RTM_CHANGE ||
8720Sstevel@tonic-gate action == RTM_DELETE)) {
8730Sstevel@tonic-gate trace_act("route disappeared before" PAT, ARGS);
8740Sstevel@tonic-gate if (action == RTM_CHANGE) {
8750Sstevel@tonic-gate action = RTM_ADD;
8760Sstevel@tonic-gate goto again;
8770Sstevel@tonic-gate }
8780Sstevel@tonic-gate return;
8790Sstevel@tonic-gate }
8800Sstevel@tonic-gate writelog(LOG_WARNING, "write(rt_sock)" PAT ": %s ",
8810Sstevel@tonic-gate ARGS, rip_strerror(errno));
8820Sstevel@tonic-gate return;
8830Sstevel@tonic-gate } else if (cc != w.w_rtm.rtm_msglen) {
8840Sstevel@tonic-gate msglog("write(rt_sock) wrote %ld instead of %d for" PAT,
8850Sstevel@tonic-gate cc, w.w_rtm.rtm_msglen, ARGS);
8860Sstevel@tonic-gate return;
8870Sstevel@tonic-gate }
8880Sstevel@tonic-gate }
8890Sstevel@tonic-gate if (TRACEKERNEL)
8900Sstevel@tonic-gate trace_misc("write kernel" PAT, ARGS);
8910Sstevel@tonic-gate #undef PAT
8920Sstevel@tonic-gate #undef ARGS
8930Sstevel@tonic-gate }
8940Sstevel@tonic-gate
8950Sstevel@tonic-gate
8960Sstevel@tonic-gate /* Hash table containing our image of the kernel forwarding table. */
8970Sstevel@tonic-gate #define KHASH_SIZE 71 /* should be prime */
8980Sstevel@tonic-gate #define KHASH(a, m) khash_bins[((a) ^ (m)) % KHASH_SIZE]
8990Sstevel@tonic-gate static struct khash *khash_bins[KHASH_SIZE];
9000Sstevel@tonic-gate
9010Sstevel@tonic-gate #define K_KEEP_LIM 30 /* k_keep */
9020Sstevel@tonic-gate
9030Sstevel@tonic-gate static struct khash *
kern_find(in_addr_t dst,in_addr_t mask,in_addr_t gate,struct interface * ifp,struct khash *** ppk)9040Sstevel@tonic-gate kern_find(in_addr_t dst, in_addr_t mask, in_addr_t gate,
9050Sstevel@tonic-gate struct interface *ifp, struct khash ***ppk)
9060Sstevel@tonic-gate {
9070Sstevel@tonic-gate struct khash *k, **pk;
9080Sstevel@tonic-gate
9090Sstevel@tonic-gate for (pk = &KHASH(dst, mask); (k = *pk) != NULL; pk = &k->k_next) {
9100Sstevel@tonic-gate if (k->k_dst == dst && k->k_mask == mask &&
9110Sstevel@tonic-gate (gate == 0 || k->k_gate == gate) &&
9120Sstevel@tonic-gate (ifp == NULL || k->k_ifp == ifp)) {
9130Sstevel@tonic-gate break;
9140Sstevel@tonic-gate }
9150Sstevel@tonic-gate }
9160Sstevel@tonic-gate if (ppk != NULL)
9170Sstevel@tonic-gate *ppk = pk;
9180Sstevel@tonic-gate return (k);
9190Sstevel@tonic-gate }
9200Sstevel@tonic-gate
9210Sstevel@tonic-gate
9220Sstevel@tonic-gate /*
9230Sstevel@tonic-gate * Find out if there is an alternate route to a given destination
9240Sstevel@tonic-gate * off of a given interface.
9250Sstevel@tonic-gate */
9260Sstevel@tonic-gate static struct khash *
kern_alternate(in_addr_t dst,in_addr_t mask,in_addr_t gate,struct interface * ifp,struct khash *** ppk)9270Sstevel@tonic-gate kern_alternate(in_addr_t dst, in_addr_t mask, in_addr_t gate,
9280Sstevel@tonic-gate struct interface *ifp, struct khash ***ppk)
9290Sstevel@tonic-gate {
9300Sstevel@tonic-gate struct khash *k, **pk;
9310Sstevel@tonic-gate
9320Sstevel@tonic-gate for (pk = &KHASH(dst, mask); (k = *pk) != NULL; pk = &k->k_next) {
9330Sstevel@tonic-gate if (k->k_dst == dst && k->k_mask == mask &&
9340Sstevel@tonic-gate (k->k_gate != gate) &&
9350Sstevel@tonic-gate (k->k_ifp == ifp)) {
9360Sstevel@tonic-gate break;
9370Sstevel@tonic-gate }
9380Sstevel@tonic-gate }
9390Sstevel@tonic-gate if (ppk != NULL)
9400Sstevel@tonic-gate *ppk = pk;
9410Sstevel@tonic-gate return (k);
9420Sstevel@tonic-gate }
9430Sstevel@tonic-gate
9440Sstevel@tonic-gate static struct khash *
kern_add(in_addr_t dst,uint32_t mask,in_addr_t gate,struct interface * ifp)9450Sstevel@tonic-gate kern_add(in_addr_t dst, uint32_t mask, in_addr_t gate, struct interface *ifp)
9460Sstevel@tonic-gate {
9470Sstevel@tonic-gate struct khash *k, **pk;
9480Sstevel@tonic-gate
9490Sstevel@tonic-gate k = kern_find(dst, mask, gate, ifp, &pk);
9500Sstevel@tonic-gate if (k != NULL)
9510Sstevel@tonic-gate return (k);
9520Sstevel@tonic-gate
9530Sstevel@tonic-gate k = rtmalloc(sizeof (*k), "kern_add");
9540Sstevel@tonic-gate
9550Sstevel@tonic-gate (void) memset(k, 0, sizeof (*k));
9560Sstevel@tonic-gate k->k_dst = dst;
9570Sstevel@tonic-gate k->k_mask = mask;
9580Sstevel@tonic-gate k->k_state = KS_NEW;
9590Sstevel@tonic-gate k->k_keep = now.tv_sec;
9600Sstevel@tonic-gate k->k_gate = gate;
9610Sstevel@tonic-gate k->k_ifp = ifp;
9620Sstevel@tonic-gate *pk = k;
9630Sstevel@tonic-gate
9640Sstevel@tonic-gate return (k);
9650Sstevel@tonic-gate }
9660Sstevel@tonic-gate
9670Sstevel@tonic-gate /* delete all khash entries that are wired through the interface ifp */
9680Sstevel@tonic-gate void
kern_flush_ifp(struct interface * ifp)9690Sstevel@tonic-gate kern_flush_ifp(struct interface *ifp)
9700Sstevel@tonic-gate {
9710Sstevel@tonic-gate struct khash *k, *kprev, *knext;
9720Sstevel@tonic-gate int i;
9730Sstevel@tonic-gate
9740Sstevel@tonic-gate for (i = 0; i < KHASH_SIZE; i++) {
9750Sstevel@tonic-gate kprev = NULL;
9760Sstevel@tonic-gate for (k = khash_bins[i]; k != NULL; k = knext) {
9770Sstevel@tonic-gate knext = k->k_next;
9780Sstevel@tonic-gate if (k->k_ifp == ifp) {
9790Sstevel@tonic-gate if (kprev != NULL)
9800Sstevel@tonic-gate kprev->k_next = k->k_next;
9810Sstevel@tonic-gate else
9820Sstevel@tonic-gate khash_bins[i] = k->k_next;
9830Sstevel@tonic-gate free(k);
9840Sstevel@tonic-gate continue;
9850Sstevel@tonic-gate }
9860Sstevel@tonic-gate kprev = k;
9870Sstevel@tonic-gate }
9880Sstevel@tonic-gate }
9890Sstevel@tonic-gate }
9900Sstevel@tonic-gate
9910Sstevel@tonic-gate /*
9920Sstevel@tonic-gate * rewire khash entries that currently go through oldifp to
9930Sstevel@tonic-gate * go through newifp.
9940Sstevel@tonic-gate */
9950Sstevel@tonic-gate void
kern_rewire_ifp(struct interface * oldifp,struct interface * newifp)9960Sstevel@tonic-gate kern_rewire_ifp(struct interface *oldifp, struct interface *newifp)
9970Sstevel@tonic-gate {
9980Sstevel@tonic-gate struct khash *k;
9990Sstevel@tonic-gate int i;
10000Sstevel@tonic-gate
10010Sstevel@tonic-gate for (i = 0; i < KHASH_SIZE; i++) {
10020Sstevel@tonic-gate for (k = khash_bins[i]; k; k = k->k_next) {
10030Sstevel@tonic-gate if (k->k_ifp == oldifp) {
10040Sstevel@tonic-gate k->k_ifp = newifp;
10050Sstevel@tonic-gate trace_misc("kern_rewire_ifp k 0x%lx "
10060Sstevel@tonic-gate "from %s to %s", k, oldifp->int_name,
10070Sstevel@tonic-gate newifp->int_name);
10080Sstevel@tonic-gate }
10090Sstevel@tonic-gate }
10100Sstevel@tonic-gate }
10110Sstevel@tonic-gate }
10120Sstevel@tonic-gate
10130Sstevel@tonic-gate /*
10140Sstevel@tonic-gate * Check that a static route it is still in the daemon table, and not
10150Sstevel@tonic-gate * deleted by interfaces coming and going. This is also the routine
10160Sstevel@tonic-gate * responsible for adding new static routes to the daemon table.
10170Sstevel@tonic-gate */
10180Sstevel@tonic-gate static void
kern_check_static(struct khash * k,struct interface * ifp)10190Sstevel@tonic-gate kern_check_static(struct khash *k, struct interface *ifp)
10200Sstevel@tonic-gate {
10210Sstevel@tonic-gate struct rt_entry *rt;
10220Sstevel@tonic-gate struct rt_spare new;
10230Sstevel@tonic-gate uint16_t rt_state = RS_STATIC;
10240Sstevel@tonic-gate
10250Sstevel@tonic-gate (void) memset(&new, 0, sizeof (new));
10260Sstevel@tonic-gate new.rts_ifp = ifp;
10270Sstevel@tonic-gate new.rts_gate = k->k_gate;
10280Sstevel@tonic-gate new.rts_router = (ifp != NULL) ? ifp->int_addr : loopaddr;
10290Sstevel@tonic-gate new.rts_metric = k->k_metric;
10300Sstevel@tonic-gate new.rts_time = now.tv_sec;
10310Sstevel@tonic-gate new.rts_origin = RO_STATIC;
10320Sstevel@tonic-gate
10330Sstevel@tonic-gate rt = rtget(k->k_dst, k->k_mask);
10340Sstevel@tonic-gate if ((ifp != NULL && !IS_IFF_ROUTING(ifp->int_if_flags)) ||
10350Sstevel@tonic-gate (k->k_state & KS_PRIVATE))
10360Sstevel@tonic-gate rt_state |= RS_NOPROPAGATE;
10370Sstevel@tonic-gate
10380Sstevel@tonic-gate if (rt != NULL) {
10390Sstevel@tonic-gate if ((rt->rt_state & RS_STATIC) == 0) {
10400Sstevel@tonic-gate /*
10410Sstevel@tonic-gate * We are already tracking this dest/mask
10420Sstevel@tonic-gate * via RIP/RDISC. Ignore the static route,
10430Sstevel@tonic-gate * because we don't currently have a good
10440Sstevel@tonic-gate * way to compare metrics on static routes
10450Sstevel@tonic-gate * with rip metrics, and therefore cannot
10460Sstevel@tonic-gate * mix and match the two.
10470Sstevel@tonic-gate */
10480Sstevel@tonic-gate return;
10490Sstevel@tonic-gate }
10500Sstevel@tonic-gate rt_state |= rt->rt_state;
10510Sstevel@tonic-gate if (rt->rt_state != rt_state)
10520Sstevel@tonic-gate rtchange(rt, rt_state, &new, 0);
10530Sstevel@tonic-gate } else {
10540Sstevel@tonic-gate rtadd(k->k_dst, k->k_mask, rt_state, &new);
10550Sstevel@tonic-gate }
10560Sstevel@tonic-gate }
10570Sstevel@tonic-gate
10580Sstevel@tonic-gate
10590Sstevel@tonic-gate /* operate on a kernel entry */
10600Sstevel@tonic-gate static void
kern_ioctl(struct khash * k,int action,int flags)10610Sstevel@tonic-gate kern_ioctl(struct khash *k,
10620Sstevel@tonic-gate int action, /* RTM_DELETE, etc */
10630Sstevel@tonic-gate int flags)
10640Sstevel@tonic-gate {
10650Sstevel@tonic-gate if (((k->k_state & (KS_IF|KS_PASSIVE)) == KS_IF) ||
10660Sstevel@tonic-gate (k->k_state & KS_DEPRE_IF)) {
10670Sstevel@tonic-gate /*
10680Sstevel@tonic-gate * Prevent execution of RTM_DELETE, RTM_ADD or
10690Sstevel@tonic-gate * RTM_CHANGE of interface routes
10700Sstevel@tonic-gate */
10710Sstevel@tonic-gate trace_act("Blocking execution of %s %s --> %s ",
10720Sstevel@tonic-gate rtm_type_name(action),
10730Sstevel@tonic-gate addrname(k->k_dst, k->k_mask, 0), naddr_ntoa(k->k_gate));
10740Sstevel@tonic-gate return;
10750Sstevel@tonic-gate }
10760Sstevel@tonic-gate
10770Sstevel@tonic-gate switch (action) {
10780Sstevel@tonic-gate case RTM_DELETE:
10790Sstevel@tonic-gate k->k_state &= ~KS_DYNAMIC;
10800Sstevel@tonic-gate if (k->k_state & KS_DELETED)
10810Sstevel@tonic-gate return;
10820Sstevel@tonic-gate k->k_state |= KS_DELETED;
10830Sstevel@tonic-gate break;
10840Sstevel@tonic-gate case RTM_ADD:
10850Sstevel@tonic-gate k->k_state &= ~KS_DELETED;
10860Sstevel@tonic-gate break;
10870Sstevel@tonic-gate case RTM_CHANGE:
10880Sstevel@tonic-gate if (k->k_state & KS_DELETED) {
10890Sstevel@tonic-gate action = RTM_ADD;
10900Sstevel@tonic-gate k->k_state &= ~KS_DELETED;
10910Sstevel@tonic-gate }
10920Sstevel@tonic-gate break;
10930Sstevel@tonic-gate }
10940Sstevel@tonic-gate
1095*11418SSowmini.Varadhan@Sun.COM /*
1096*11418SSowmini.Varadhan@Sun.COM * We should be doing an RTM_CHANGE for a KS_CHANGE, but
1097*11418SSowmini.Varadhan@Sun.COM * RTM_CHANGE in the kernel is not currently multipath-aware and
1098*11418SSowmini.Varadhan@Sun.COM * assumes that RTF_GATEWAY implies that the gateway of the route for
1099*11418SSowmini.Varadhan@Sun.COM * dst has to be changed. Moreover, the only change that in.routed
1100*11418SSowmini.Varadhan@Sun.COM * wants to implement is a change in the ks_metric (rmx_hopcount)
1101*11418SSowmini.Varadhan@Sun.COM * which the kernel ignores anway, so we skip the RTM_CHANGE operation
1102*11418SSowmini.Varadhan@Sun.COM * on the kernel
1103*11418SSowmini.Varadhan@Sun.COM */
1104*11418SSowmini.Varadhan@Sun.COM if (action != RTM_CHANGE) {
1105*11418SSowmini.Varadhan@Sun.COM rtioctl(action, k->k_dst, k->k_gate, k->k_mask, k->k_ifp,
1106*11418SSowmini.Varadhan@Sun.COM k->k_metric, flags);
1107*11418SSowmini.Varadhan@Sun.COM }
11080Sstevel@tonic-gate }
11090Sstevel@tonic-gate
11100Sstevel@tonic-gate
11110Sstevel@tonic-gate /* add a route the kernel told us */
11120Sstevel@tonic-gate static void
rtm_add(struct rt_msghdr * rtm,struct rt_addrinfo * info,time_t keep,boolean_t interf_route,struct interface * ifptr)11130Sstevel@tonic-gate rtm_add(struct rt_msghdr *rtm,
11140Sstevel@tonic-gate struct rt_addrinfo *info,
11150Sstevel@tonic-gate time_t keep,
11160Sstevel@tonic-gate boolean_t interf_route,
11170Sstevel@tonic-gate struct interface *ifptr)
11180Sstevel@tonic-gate {
11190Sstevel@tonic-gate struct khash *k;
11200Sstevel@tonic-gate struct interface *ifp = ifptr;
11210Sstevel@tonic-gate in_addr_t mask, gate = 0;
11220Sstevel@tonic-gate static struct msg_limit msg_no_ifp;
11230Sstevel@tonic-gate
11240Sstevel@tonic-gate if (rtm->rtm_flags & RTF_HOST) {
11250Sstevel@tonic-gate mask = HOST_MASK;
11260Sstevel@tonic-gate } else if (INFO_MASK(info) != 0) {
11270Sstevel@tonic-gate mask = ntohl(S_ADDR(INFO_MASK(info)));
11280Sstevel@tonic-gate } else {
11290Sstevel@tonic-gate writelog(LOG_WARNING,
11300Sstevel@tonic-gate "ignore %s without mask", rtm_type_name(rtm->rtm_type));
11310Sstevel@tonic-gate return;
11320Sstevel@tonic-gate }
11330Sstevel@tonic-gate
11340Sstevel@tonic-gate /*
11350Sstevel@tonic-gate * Find the interface toward the gateway.
11360Sstevel@tonic-gate */
11370Sstevel@tonic-gate if (INFO_GATE(info) != NULL)
11380Sstevel@tonic-gate gate = S_ADDR(INFO_GATE(info));
11390Sstevel@tonic-gate
11400Sstevel@tonic-gate if (ifp == NULL) {
11410Sstevel@tonic-gate if (INFO_GATE(info) != NULL)
11420Sstevel@tonic-gate ifp = iflookup(gate);
11432781Ssowmini if (ifp == NULL) {
11440Sstevel@tonic-gate msglim(&msg_no_ifp, gate,
11450Sstevel@tonic-gate "route %s --> %s nexthop is not directly connected",
11460Sstevel@tonic-gate addrname(S_ADDR(INFO_DST(info)), mask, 0),
11470Sstevel@tonic-gate naddr_ntoa(gate));
11482781Ssowmini }
11490Sstevel@tonic-gate }
11500Sstevel@tonic-gate
11510Sstevel@tonic-gate k = kern_add(S_ADDR(INFO_DST(info)), mask, gate, ifp);
11520Sstevel@tonic-gate
11530Sstevel@tonic-gate if (k->k_state & KS_NEW)
11540Sstevel@tonic-gate k->k_keep = now.tv_sec+keep;
11550Sstevel@tonic-gate if (INFO_GATE(info) == 0) {
11560Sstevel@tonic-gate trace_act("note %s without gateway",
11570Sstevel@tonic-gate rtm_type_name(rtm->rtm_type));
11580Sstevel@tonic-gate k->k_metric = HOPCNT_INFINITY;
11590Sstevel@tonic-gate } else if (INFO_GATE(info)->ss_family != AF_INET) {
11600Sstevel@tonic-gate trace_act("note %s with gateway AF=%d",
11610Sstevel@tonic-gate rtm_type_name(rtm->rtm_type),
11620Sstevel@tonic-gate INFO_GATE(info)->ss_family);
11630Sstevel@tonic-gate k->k_metric = HOPCNT_INFINITY;
11640Sstevel@tonic-gate } else {
11650Sstevel@tonic-gate k->k_gate = S_ADDR(INFO_GATE(info));
11660Sstevel@tonic-gate k->k_metric = rtm->rtm_rmx.rmx_hopcount;
11670Sstevel@tonic-gate if (k->k_metric < 0)
11680Sstevel@tonic-gate k->k_metric = 0;
11690Sstevel@tonic-gate else if (k->k_metric > HOPCNT_INFINITY-1)
11700Sstevel@tonic-gate k->k_metric = HOPCNT_INFINITY-1;
11710Sstevel@tonic-gate }
11720Sstevel@tonic-gate
11730Sstevel@tonic-gate if ((k->k_state & KS_NEW) && interf_route) {
11740Sstevel@tonic-gate if (k->k_gate != 0 && findifaddr(k->k_gate) == NULL)
11750Sstevel@tonic-gate k->k_state |= KS_DEPRE_IF;
11760Sstevel@tonic-gate else
11770Sstevel@tonic-gate k->k_state |= KS_IF;
11780Sstevel@tonic-gate }
11790Sstevel@tonic-gate
11800Sstevel@tonic-gate k->k_state &= ~(KS_NEW | KS_DELETE | KS_ADD | KS_CHANGE | KS_DEL_ADD |
11810Sstevel@tonic-gate KS_STATIC | KS_GATEWAY | KS_DELETED | KS_PRIVATE | KS_CHECK);
11820Sstevel@tonic-gate if (rtm->rtm_flags & RTF_GATEWAY)
11830Sstevel@tonic-gate k->k_state |= KS_GATEWAY;
11840Sstevel@tonic-gate if (rtm->rtm_flags & RTF_STATIC)
11850Sstevel@tonic-gate k->k_state |= KS_STATIC;
11860Sstevel@tonic-gate if (rtm->rtm_flags & RTF_PRIVATE)
11870Sstevel@tonic-gate k->k_state |= KS_PRIVATE;
11880Sstevel@tonic-gate
11890Sstevel@tonic-gate
11900Sstevel@tonic-gate if (rtm->rtm_flags & (RTF_DYNAMIC | RTF_MODIFIED)) {
11910Sstevel@tonic-gate if (INFO_AUTHOR(info) != 0 &&
11920Sstevel@tonic-gate INFO_AUTHOR(info)->ss_family == AF_INET)
11930Sstevel@tonic-gate ifp = iflookup(S_ADDR(INFO_AUTHOR(info)));
11940Sstevel@tonic-gate else
11950Sstevel@tonic-gate ifp = NULL;
11960Sstevel@tonic-gate if (should_supply(ifp) && (ifp == NULL ||
11970Sstevel@tonic-gate !(ifp->int_state & IS_REDIRECT_OK))) {
11980Sstevel@tonic-gate /*
11990Sstevel@tonic-gate * Routers are not supposed to listen to redirects,
12000Sstevel@tonic-gate * so delete it if it came via an unknown interface
12010Sstevel@tonic-gate * or the interface does not have special permission.
12020Sstevel@tonic-gate */
12030Sstevel@tonic-gate k->k_state &= ~KS_DYNAMIC;
12040Sstevel@tonic-gate k->k_state |= KS_DELETE;
12050Sstevel@tonic-gate LIM_SEC(need_kern, 0);
12060Sstevel@tonic-gate trace_act("mark for deletion redirected %s --> %s"
12070Sstevel@tonic-gate " via %s",
12080Sstevel@tonic-gate addrname(k->k_dst, k->k_mask, 0),
12090Sstevel@tonic-gate naddr_ntoa(k->k_gate),
12100Sstevel@tonic-gate ifp ? ifp->int_name : "unknown interface");
12110Sstevel@tonic-gate } else {
12120Sstevel@tonic-gate k->k_state |= KS_DYNAMIC;
12130Sstevel@tonic-gate k->k_redirect_time = now.tv_sec;
12140Sstevel@tonic-gate trace_act("accept redirected %s --> %s via %s",
12150Sstevel@tonic-gate addrname(k->k_dst, k->k_mask, 0),
12160Sstevel@tonic-gate naddr_ntoa(k->k_gate),
12170Sstevel@tonic-gate ifp ? ifp->int_name : "unknown interface");
12180Sstevel@tonic-gate }
12190Sstevel@tonic-gate return;
12200Sstevel@tonic-gate }
12210Sstevel@tonic-gate
12220Sstevel@tonic-gate /*
12230Sstevel@tonic-gate * If it is not a static route, quit until the next comparison
12240Sstevel@tonic-gate * between the kernel and daemon tables, when it will be deleted.
12250Sstevel@tonic-gate */
12260Sstevel@tonic-gate if (!(k->k_state & KS_STATIC)) {
12270Sstevel@tonic-gate if (!(k->k_state & (KS_IF|KS_DEPRE_IF|KS_FILE)))
12280Sstevel@tonic-gate k->k_state |= KS_DELETE;
12290Sstevel@tonic-gate LIM_SEC(need_kern, k->k_keep);
12300Sstevel@tonic-gate return;
12310Sstevel@tonic-gate }
12320Sstevel@tonic-gate
12330Sstevel@tonic-gate /*
12340Sstevel@tonic-gate * Put static routes with real metrics into the daemon table so
12350Sstevel@tonic-gate * they can be advertised.
12360Sstevel@tonic-gate */
12370Sstevel@tonic-gate
12380Sstevel@tonic-gate kern_check_static(k, ifp);
12390Sstevel@tonic-gate }
12400Sstevel@tonic-gate
12410Sstevel@tonic-gate
12420Sstevel@tonic-gate /* deal with packet loss */
12430Sstevel@tonic-gate static void
rtm_lose(struct rt_msghdr * rtm,struct rt_addrinfo * info)12440Sstevel@tonic-gate rtm_lose(struct rt_msghdr *rtm, struct rt_addrinfo *info)
12450Sstevel@tonic-gate {
124610640SSowmini.Varadhan@Sun.COM struct rt_spare new, *rts, *losing_rts = NULL;
124710640SSowmini.Varadhan@Sun.COM struct rt_entry *rt;
124810640SSowmini.Varadhan@Sun.COM int i, spares;
124910640SSowmini.Varadhan@Sun.COM
12500Sstevel@tonic-gate if (INFO_GATE(info) == NULL || INFO_GATE(info)->ss_family != AF_INET) {
12510Sstevel@tonic-gate trace_act("ignore %s without gateway",
12520Sstevel@tonic-gate rtm_type_name(rtm->rtm_type));
12530Sstevel@tonic-gate age(0);
12540Sstevel@tonic-gate return;
12550Sstevel@tonic-gate }
12560Sstevel@tonic-gate
125710640SSowmini.Varadhan@Sun.COM rt = rtfind(S_ADDR(INFO_DST(info)));
125810640SSowmini.Varadhan@Sun.COM if (rt != NULL) {
125910640SSowmini.Varadhan@Sun.COM spares = 0;
126010640SSowmini.Varadhan@Sun.COM for (i = 0; i < rt->rt_num_spares; i++) {
126110640SSowmini.Varadhan@Sun.COM rts = &rt->rt_spares[i];
126210640SSowmini.Varadhan@Sun.COM if (rts->rts_gate == S_ADDR(INFO_GATE(info))) {
126310640SSowmini.Varadhan@Sun.COM losing_rts = rts;
126410640SSowmini.Varadhan@Sun.COM continue;
126510640SSowmini.Varadhan@Sun.COM }
126610640SSowmini.Varadhan@Sun.COM if (rts->rts_gate != 0 && rts->rts_ifp != &dummy_ifp)
126710640SSowmini.Varadhan@Sun.COM spares++;
126810640SSowmini.Varadhan@Sun.COM }
126910640SSowmini.Varadhan@Sun.COM }
127010640SSowmini.Varadhan@Sun.COM if (rt == NULL || losing_rts == NULL) {
127110640SSowmini.Varadhan@Sun.COM trace_act("Ignore RTM_LOSING because no route found"
127210640SSowmini.Varadhan@Sun.COM " for %s through %s",
127310640SSowmini.Varadhan@Sun.COM naddr_ntoa(S_ADDR(INFO_DST(info))),
127410640SSowmini.Varadhan@Sun.COM naddr_ntoa(S_ADDR(INFO_GATE(info))));
127510640SSowmini.Varadhan@Sun.COM return;
127610640SSowmini.Varadhan@Sun.COM }
127710640SSowmini.Varadhan@Sun.COM if (spares == 0) {
127810640SSowmini.Varadhan@Sun.COM trace_act("Got RTM_LOSING, but no alternatives to gw %s."
127910640SSowmini.Varadhan@Sun.COM " deprecating route to metric 15",
128010640SSowmini.Varadhan@Sun.COM naddr_ntoa(S_ADDR(INFO_GATE(info))));
128110640SSowmini.Varadhan@Sun.COM new = *losing_rts;
128210640SSowmini.Varadhan@Sun.COM new.rts_metric = HOPCNT_INFINITY - 1;
128310640SSowmini.Varadhan@Sun.COM rtchange(rt, rt->rt_state, &new, 0);
128410640SSowmini.Varadhan@Sun.COM return;
128510640SSowmini.Varadhan@Sun.COM }
128610640SSowmini.Varadhan@Sun.COM trace_act("Got RTM_LOSING. Found a route with %d alternates", spares);
12870Sstevel@tonic-gate if (rdisc_ok)
12880Sstevel@tonic-gate rdisc_age(S_ADDR(INFO_GATE(info)));
12890Sstevel@tonic-gate age(S_ADDR(INFO_GATE(info)));
12900Sstevel@tonic-gate }
12910Sstevel@tonic-gate
12920Sstevel@tonic-gate
12930Sstevel@tonic-gate /*
12940Sstevel@tonic-gate * Make the gateway slot of an info structure point to something
12950Sstevel@tonic-gate * useful. If it is not already useful, but it specifies an interface,
12960Sstevel@tonic-gate * then fill in the sockaddr_in provided and point it there.
12970Sstevel@tonic-gate */
12980Sstevel@tonic-gate static int
get_info_gate(struct sockaddr_storage ** ssp,struct sockaddr_in * sin)12990Sstevel@tonic-gate get_info_gate(struct sockaddr_storage **ssp, struct sockaddr_in *sin)
13000Sstevel@tonic-gate {
13010Sstevel@tonic-gate struct sockaddr_dl *sdl = (struct sockaddr_dl *)*ssp;
13020Sstevel@tonic-gate struct interface *ifp;
13030Sstevel@tonic-gate
13040Sstevel@tonic-gate if (sdl == NULL)
13050Sstevel@tonic-gate return (0);
13060Sstevel@tonic-gate if ((sdl)->sdl_family == AF_INET)
13070Sstevel@tonic-gate return (1);
13080Sstevel@tonic-gate if ((sdl)->sdl_family != AF_LINK)
13090Sstevel@tonic-gate return (0);
13100Sstevel@tonic-gate
13110Sstevel@tonic-gate ifp = ifwithindex(sdl->sdl_index, _B_TRUE);
13120Sstevel@tonic-gate if (ifp == NULL)
13130Sstevel@tonic-gate return (0);
13140Sstevel@tonic-gate
13150Sstevel@tonic-gate sin->sin_addr.s_addr = ifp->int_addr;
13160Sstevel@tonic-gate sin->sin_family = AF_INET;
13170Sstevel@tonic-gate /* LINTED */
13180Sstevel@tonic-gate *ssp = (struct sockaddr_storage *)sin;
13190Sstevel@tonic-gate
13200Sstevel@tonic-gate return (1);
13210Sstevel@tonic-gate }
13220Sstevel@tonic-gate
13230Sstevel@tonic-gate
13240Sstevel@tonic-gate /*
13250Sstevel@tonic-gate * Clean the kernel table by copying it to the daemon image.
13260Sstevel@tonic-gate * Eventually the daemon will delete any extra routes.
13270Sstevel@tonic-gate */
13280Sstevel@tonic-gate void
sync_kern(void)13290Sstevel@tonic-gate sync_kern(void)
13300Sstevel@tonic-gate {
13310Sstevel@tonic-gate int i;
13320Sstevel@tonic-gate struct khash *k;
13330Sstevel@tonic-gate struct {
13340Sstevel@tonic-gate struct T_optmgmt_req req;
13350Sstevel@tonic-gate struct opthdr hdr;
13360Sstevel@tonic-gate } req;
13370Sstevel@tonic-gate union {
13380Sstevel@tonic-gate struct T_optmgmt_ack ack;
13390Sstevel@tonic-gate unsigned char space[64];
13400Sstevel@tonic-gate } ack;
13410Sstevel@tonic-gate struct opthdr *rh;
13420Sstevel@tonic-gate struct strbuf cbuf, dbuf;
13430Sstevel@tonic-gate int ipfd, nroutes, flags, r;
13440Sstevel@tonic-gate mib2_ipRouteEntry_t routes[8];
13450Sstevel@tonic-gate mib2_ipRouteEntry_t *rp;
13460Sstevel@tonic-gate struct rt_msghdr rtm;
13470Sstevel@tonic-gate struct rt_addrinfo info;
13480Sstevel@tonic-gate struct sockaddr_in sin_dst;
13490Sstevel@tonic-gate struct sockaddr_in sin_gate;
13500Sstevel@tonic-gate struct sockaddr_in sin_mask;
13510Sstevel@tonic-gate struct sockaddr_in sin_author;
13520Sstevel@tonic-gate struct interface *ifp;
13530Sstevel@tonic-gate char ifname[LIFNAMSIZ + 1];
13540Sstevel@tonic-gate
13550Sstevel@tonic-gate for (i = 0; i < KHASH_SIZE; i++) {
13560Sstevel@tonic-gate for (k = khash_bins[i]; k != NULL; k = k->k_next) {
13570Sstevel@tonic-gate if (!(k->k_state & (KS_IF|KS_DEPRE_IF)))
13580Sstevel@tonic-gate k->k_state |= KS_CHECK;
13590Sstevel@tonic-gate }
13600Sstevel@tonic-gate }
13610Sstevel@tonic-gate
13620Sstevel@tonic-gate ipfd = open(IP_DEV_NAME, O_RDWR);
13630Sstevel@tonic-gate if (ipfd == -1) {
13640Sstevel@tonic-gate msglog("open " IP_DEV_NAME ": %s", rip_strerror(errno));
13650Sstevel@tonic-gate goto hash_clean;
13660Sstevel@tonic-gate }
13670Sstevel@tonic-gate
13680Sstevel@tonic-gate req.req.PRIM_type = T_OPTMGMT_REQ;
13690Sstevel@tonic-gate req.req.OPT_offset = (caddr_t)&req.hdr - (caddr_t)&req;
13700Sstevel@tonic-gate req.req.OPT_length = sizeof (req.hdr);
13710Sstevel@tonic-gate req.req.MGMT_flags = T_CURRENT;
13720Sstevel@tonic-gate
13730Sstevel@tonic-gate req.hdr.level = MIB2_IP;
13740Sstevel@tonic-gate req.hdr.name = 0;
13750Sstevel@tonic-gate req.hdr.len = 0;
13760Sstevel@tonic-gate
13770Sstevel@tonic-gate cbuf.buf = (caddr_t)&req;
13780Sstevel@tonic-gate cbuf.len = sizeof (req);
13790Sstevel@tonic-gate
13800Sstevel@tonic-gate if (putmsg(ipfd, &cbuf, NULL, 0) == -1) {
13810Sstevel@tonic-gate msglog("T_OPTMGMT_REQ putmsg: %s", rip_strerror(errno));
13820Sstevel@tonic-gate goto hash_clean;
13830Sstevel@tonic-gate }
13840Sstevel@tonic-gate
13850Sstevel@tonic-gate for (;;) {
13860Sstevel@tonic-gate cbuf.buf = (caddr_t)&ack;
13870Sstevel@tonic-gate cbuf.maxlen = sizeof (ack);
13880Sstevel@tonic-gate dbuf.buf = (caddr_t)routes;
13890Sstevel@tonic-gate dbuf.maxlen = sizeof (routes);
13900Sstevel@tonic-gate flags = 0;
13910Sstevel@tonic-gate r = getmsg(ipfd, &cbuf, &dbuf, &flags);
13920Sstevel@tonic-gate if (r == -1) {
13930Sstevel@tonic-gate msglog("T_OPTMGMT_REQ getmsg: %s", rip_strerror(errno));
13940Sstevel@tonic-gate goto hash_clean;
13950Sstevel@tonic-gate }
13960Sstevel@tonic-gate
13970Sstevel@tonic-gate if (cbuf.len < sizeof (struct T_optmgmt_ack) ||
13980Sstevel@tonic-gate ack.ack.PRIM_type != T_OPTMGMT_ACK ||
13990Sstevel@tonic-gate ack.ack.MGMT_flags != T_SUCCESS ||
14000Sstevel@tonic-gate ack.ack.OPT_length < sizeof (struct opthdr)) {
14010Sstevel@tonic-gate msglog("bad T_OPTMGMT response; len=%d prim=%d "
14020Sstevel@tonic-gate "flags=%d optlen=%d", cbuf.len, ack.ack.PRIM_type,
14030Sstevel@tonic-gate ack.ack.MGMT_flags, ack.ack.OPT_length);
14040Sstevel@tonic-gate goto hash_clean;
14050Sstevel@tonic-gate }
14060Sstevel@tonic-gate /* LINTED */
14070Sstevel@tonic-gate rh = (struct opthdr *)((caddr_t)&ack + ack.ack.OPT_offset);
14080Sstevel@tonic-gate if (rh->level == 0 && rh->name == 0) {
14090Sstevel@tonic-gate break;
14100Sstevel@tonic-gate }
14110Sstevel@tonic-gate if (rh->level != MIB2_IP || rh->name != MIB2_IP_21) {
14120Sstevel@tonic-gate while (r == MOREDATA) {
14130Sstevel@tonic-gate r = getmsg(ipfd, NULL, &dbuf, &flags);
14140Sstevel@tonic-gate }
14150Sstevel@tonic-gate continue;
14160Sstevel@tonic-gate }
14170Sstevel@tonic-gate break;
14180Sstevel@tonic-gate }
14190Sstevel@tonic-gate
14200Sstevel@tonic-gate (void) memset(&rtm, 0, sizeof (rtm));
14210Sstevel@tonic-gate (void) memset(&info, 0, sizeof (info));
14220Sstevel@tonic-gate (void) memset(&sin_dst, 0, sizeof (sin_dst));
14230Sstevel@tonic-gate (void) memset(&sin_gate, 0, sizeof (sin_gate));
14240Sstevel@tonic-gate (void) memset(&sin_mask, 0, sizeof (sin_mask));
14250Sstevel@tonic-gate (void) memset(&sin_author, 0, sizeof (sin_author));
14260Sstevel@tonic-gate sin_dst.sin_family = AF_INET;
14270Sstevel@tonic-gate /* LINTED */
14280Sstevel@tonic-gate info.rti_info[RTAX_DST] = (struct sockaddr_storage *)&sin_dst;
14290Sstevel@tonic-gate sin_gate.sin_family = AF_INET;
14300Sstevel@tonic-gate /* LINTED */
14310Sstevel@tonic-gate info.rti_info[RTAX_GATEWAY] = (struct sockaddr_storage *)&sin_gate;
14320Sstevel@tonic-gate sin_mask.sin_family = AF_INET;
14330Sstevel@tonic-gate /* LINTED */
14340Sstevel@tonic-gate info.rti_info[RTAX_NETMASK] = (struct sockaddr_storage *)&sin_mask;
14350Sstevel@tonic-gate sin_dst.sin_family = AF_INET;
14360Sstevel@tonic-gate /* LINTED */
14370Sstevel@tonic-gate info.rti_info[RTAX_AUTHOR] = (struct sockaddr_storage *)&sin_author;
14380Sstevel@tonic-gate
14390Sstevel@tonic-gate for (;;) {
14400Sstevel@tonic-gate nroutes = dbuf.len / sizeof (mib2_ipRouteEntry_t);
14410Sstevel@tonic-gate for (rp = routes; nroutes > 0; ++rp, nroutes--) {
14420Sstevel@tonic-gate
14430Sstevel@tonic-gate /*
14440Sstevel@tonic-gate * Ignore IRE cache, broadcast, and local address
14450Sstevel@tonic-gate * entries; they're not subject to routing socket
14460Sstevel@tonic-gate * control.
14470Sstevel@tonic-gate */
14480Sstevel@tonic-gate if (rp->ipRouteInfo.re_ire_type &
14490Sstevel@tonic-gate (IRE_BROADCAST | IRE_CACHE | IRE_LOCAL))
14500Sstevel@tonic-gate continue;
14510Sstevel@tonic-gate
14524513Skcpoon /* ignore multicast and link local addresses */
14534513Skcpoon if (IN_MULTICAST(ntohl(rp->ipRouteDest)) ||
14544513Skcpoon IN_LINKLOCAL(ntohl(rp->ipRouteDest))) {
14550Sstevel@tonic-gate continue;
14564513Skcpoon }
14570Sstevel@tonic-gate
14580Sstevel@tonic-gate
14590Sstevel@tonic-gate #ifdef DEBUG_KERNEL_ROUTE_READ
14600Sstevel@tonic-gate (void) fprintf(stderr, "route type %d, ire type %08X, "
14610Sstevel@tonic-gate "flags %08X: %s", rp->ipRouteType,
14620Sstevel@tonic-gate rp->ipRouteInfo.re_ire_type,
14630Sstevel@tonic-gate rp->ipRouteInfo.re_flags,
14640Sstevel@tonic-gate naddr_ntoa(rp->ipRouteDest));
14650Sstevel@tonic-gate (void) fprintf(stderr, " %s",
14660Sstevel@tonic-gate naddr_ntoa(rp->ipRouteMask));
14670Sstevel@tonic-gate (void) fprintf(stderr, " %s\n",
14680Sstevel@tonic-gate naddr_ntoa(rp->ipRouteNextHop));
14690Sstevel@tonic-gate #endif
14700Sstevel@tonic-gate
14710Sstevel@tonic-gate /* Fake up the needed entries */
14720Sstevel@tonic-gate rtm.rtm_flags = rp->ipRouteInfo.re_flags;
14730Sstevel@tonic-gate rtm.rtm_type = RTM_GET;
14740Sstevel@tonic-gate rtm.rtm_rmx.rmx_hopcount = rp->ipRouteMetric1;
14750Sstevel@tonic-gate
14760Sstevel@tonic-gate (void) memset(ifname, 0, sizeof (ifname));
14770Sstevel@tonic-gate if (rp->ipRouteIfIndex.o_length <
14780Sstevel@tonic-gate sizeof (rp->ipRouteIfIndex.o_bytes))
14790Sstevel@tonic-gate rp->ipRouteIfIndex.o_bytes[
14800Sstevel@tonic-gate rp->ipRouteIfIndex.o_length] = '\0';
14810Sstevel@tonic-gate (void) strncpy(ifname,
14820Sstevel@tonic-gate rp->ipRouteIfIndex.o_bytes,
14830Sstevel@tonic-gate sizeof (ifname));
14840Sstevel@tonic-gate
14850Sstevel@tonic-gate /*
14860Sstevel@tonic-gate * First try to match up on gwkludge entries
14877738SRishi.Srivatsavai@Sun.COM * before trying to match ifp by name/nexthop.
14880Sstevel@tonic-gate */
14890Sstevel@tonic-gate if ((ifp = gwkludge_iflookup(rp->ipRouteDest,
1490551Sbw rp->ipRouteNextHop,
14912781Ssowmini ntohl(rp->ipRouteMask))) == NULL) {
14927738SRishi.Srivatsavai@Sun.COM ifp = lifp_iflookup(rp->ipRouteNextHop, ifname);
14932781Ssowmini }
14940Sstevel@tonic-gate
14957738SRishi.Srivatsavai@Sun.COM #ifdef DEBUG_KERNEL_ROUTE_READ
14967738SRishi.Srivatsavai@Sun.COM if (ifp != NULL) {
14977738SRishi.Srivatsavai@Sun.COM (void) fprintf(stderr, " found interface"
14987738SRishi.Srivatsavai@Sun.COM " %-4s #%-3d ", ifp->int_name,
14997738SRishi.Srivatsavai@Sun.COM (ifp->int_phys != NULL) ?
15007738SRishi.Srivatsavai@Sun.COM ifp->int_phys->phyi_index : 0);
15017738SRishi.Srivatsavai@Sun.COM (void) fprintf(stderr, "%-15s-->%-15s \n",
15027738SRishi.Srivatsavai@Sun.COM naddr_ntoa(ifp->int_addr),
15037738SRishi.Srivatsavai@Sun.COM addrname(((ifp->int_if_flags &
15047738SRishi.Srivatsavai@Sun.COM IFF_POINTOPOINT) ?
15057738SRishi.Srivatsavai@Sun.COM ifp->int_dstaddr : htonl(ifp->int_net)),
15067738SRishi.Srivatsavai@Sun.COM ifp->int_mask, 1));
15077738SRishi.Srivatsavai@Sun.COM }
15087738SRishi.Srivatsavai@Sun.COM #endif
15097738SRishi.Srivatsavai@Sun.COM
15100Sstevel@tonic-gate info.rti_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
15110Sstevel@tonic-gate if (rp->ipRouteInfo.re_ire_type & IRE_HOST_REDIRECT)
15120Sstevel@tonic-gate info.rti_addrs |= RTA_AUTHOR;
15130Sstevel@tonic-gate sin_dst.sin_addr.s_addr = rp->ipRouteDest;
15140Sstevel@tonic-gate sin_gate.sin_addr.s_addr = rp->ipRouteNextHop;
15150Sstevel@tonic-gate sin_mask.sin_addr.s_addr = rp->ipRouteMask;
15160Sstevel@tonic-gate sin_author.sin_addr.s_addr =
15170Sstevel@tonic-gate rp->ipRouteInfo.re_src_addr;
15180Sstevel@tonic-gate
15190Sstevel@tonic-gate /*
15200Sstevel@tonic-gate * Note static routes and interface routes, and also
15210Sstevel@tonic-gate * preload the image of the kernel table so that
15220Sstevel@tonic-gate * we can later clean it, as well as avoid making
15230Sstevel@tonic-gate * unneeded changes. Keep the old kernel routes for a
15240Sstevel@tonic-gate * few seconds to allow a RIP or router-discovery
15250Sstevel@tonic-gate * response to be heard.
15260Sstevel@tonic-gate */
15270Sstevel@tonic-gate rtm_add(&rtm, &info, MAX_WAITTIME,
15280Sstevel@tonic-gate ((rp->ipRouteInfo.re_ire_type &
15290Sstevel@tonic-gate (IRE_INTERFACE|IRE_LOOPBACK)) != 0), ifp);
15300Sstevel@tonic-gate }
15310Sstevel@tonic-gate if (r == 0) {
15320Sstevel@tonic-gate break;
15330Sstevel@tonic-gate }
15340Sstevel@tonic-gate r = getmsg(ipfd, NULL, &dbuf, &flags);
15350Sstevel@tonic-gate }
15360Sstevel@tonic-gate
15370Sstevel@tonic-gate hash_clean:
15380Sstevel@tonic-gate if (ipfd != -1)
15390Sstevel@tonic-gate (void) close(ipfd);
15400Sstevel@tonic-gate for (i = 0; i < KHASH_SIZE; i++) {
15410Sstevel@tonic-gate for (k = khash_bins[i]; k != NULL; k = k->k_next) {
15420Sstevel@tonic-gate
15430Sstevel@tonic-gate /*
15440Sstevel@tonic-gate * KS_DELETED routes have been removed from the
15450Sstevel@tonic-gate * kernel, but we keep them around for reasons
15460Sstevel@tonic-gate * stated in del_static(), so we skip the check
15470Sstevel@tonic-gate * for KS_DELETED routes here.
15480Sstevel@tonic-gate */
15490Sstevel@tonic-gate if ((k->k_state & (KS_CHECK|KS_DELETED)) == KS_CHECK) {
15500Sstevel@tonic-gate
15514513Skcpoon if (!(k->k_state & KS_DYNAMIC)) {
15524513Skcpoon writelog(LOG_WARNING,
15534513Skcpoon "%s --> %s disappeared from kernel",
15544513Skcpoon addrname(k->k_dst, k->k_mask, 0),
15554513Skcpoon naddr_ntoa(k->k_gate));
15564513Skcpoon }
15570Sstevel@tonic-gate del_static(k->k_dst, k->k_mask, k->k_gate,
15580Sstevel@tonic-gate k->k_ifp, 1);
15590Sstevel@tonic-gate
15600Sstevel@tonic-gate }
15610Sstevel@tonic-gate }
15620Sstevel@tonic-gate }
15630Sstevel@tonic-gate }
15640Sstevel@tonic-gate
15650Sstevel@tonic-gate
15660Sstevel@tonic-gate /* Listen to announcements from the kernel */
15670Sstevel@tonic-gate void
read_rt(void)15680Sstevel@tonic-gate read_rt(void)
15690Sstevel@tonic-gate {
15700Sstevel@tonic-gate long cc;
15710Sstevel@tonic-gate struct interface *ifp;
15720Sstevel@tonic-gate struct sockaddr_in gate_sin;
15730Sstevel@tonic-gate in_addr_t mask, gate;
15740Sstevel@tonic-gate union {
15750Sstevel@tonic-gate struct {
15760Sstevel@tonic-gate struct rt_msghdr rtm;
15770Sstevel@tonic-gate struct sockaddr_storage addrs[RTA_NUMBITS];
15780Sstevel@tonic-gate } r;
15790Sstevel@tonic-gate struct if_msghdr ifm;
15800Sstevel@tonic-gate } m;
15810Sstevel@tonic-gate char str[100], *strp;
15820Sstevel@tonic-gate struct rt_addrinfo info;
15830Sstevel@tonic-gate
15840Sstevel@tonic-gate
15850Sstevel@tonic-gate for (;;) {
15860Sstevel@tonic-gate cc = read(rt_sock, &m, sizeof (m));
15870Sstevel@tonic-gate if (cc <= 0) {
15880Sstevel@tonic-gate if (cc < 0 && errno != EWOULDBLOCK)
15890Sstevel@tonic-gate LOGERR("read(rt_sock)");
15900Sstevel@tonic-gate return;
15910Sstevel@tonic-gate }
15920Sstevel@tonic-gate
15930Sstevel@tonic-gate if (TRACERTS)
15940Sstevel@tonic-gate dump_rt_msg("read", &m.r.rtm, cc);
15950Sstevel@tonic-gate
15960Sstevel@tonic-gate if (cc < m.r.rtm.rtm_msglen) {
15970Sstevel@tonic-gate msglog("routing message truncated (%d < %d)",
15980Sstevel@tonic-gate cc, m.r.rtm.rtm_msglen);
15990Sstevel@tonic-gate }
16000Sstevel@tonic-gate
16010Sstevel@tonic-gate if (m.r.rtm.rtm_version != RTM_VERSION) {
16020Sstevel@tonic-gate msglog("bogus routing message version %d",
16030Sstevel@tonic-gate m.r.rtm.rtm_version);
16040Sstevel@tonic-gate continue;
16050Sstevel@tonic-gate }
16060Sstevel@tonic-gate
16070Sstevel@tonic-gate ifp = NULL;
16080Sstevel@tonic-gate
16090Sstevel@tonic-gate if (m.r.rtm.rtm_type == RTM_IFINFO ||
16100Sstevel@tonic-gate m.r.rtm.rtm_type == RTM_NEWADDR ||
16110Sstevel@tonic-gate m.r.rtm.rtm_type == RTM_DELADDR) {
16120Sstevel@tonic-gate strp = if_bit_string(m.ifm.ifm_flags, _B_TRUE);
16130Sstevel@tonic-gate if (strp == NULL) {
16140Sstevel@tonic-gate strp = str;
16150Sstevel@tonic-gate (void) sprintf(str, "%#x", m.ifm.ifm_flags);
16160Sstevel@tonic-gate }
16170Sstevel@tonic-gate ifp = ifwithindex(m.ifm.ifm_index,
16180Sstevel@tonic-gate m.r.rtm.rtm_type != RTM_DELADDR);
16190Sstevel@tonic-gate if (ifp == NULL) {
16200Sstevel@tonic-gate char ifname[LIFNAMSIZ], *ifnamep;
16210Sstevel@tonic-gate
16220Sstevel@tonic-gate ifnamep = if_indextoname(m.ifm.ifm_index,
16230Sstevel@tonic-gate ifname);
16240Sstevel@tonic-gate if (ifnamep == NULL) {
16250Sstevel@tonic-gate trace_act("note %s with flags %s"
16260Sstevel@tonic-gate " for unknown interface index #%d",
16270Sstevel@tonic-gate rtm_type_name(m.r.rtm.rtm_type),
16280Sstevel@tonic-gate strp, m.ifm.ifm_index);
16290Sstevel@tonic-gate } else {
16300Sstevel@tonic-gate trace_act("note %s with flags %s"
16310Sstevel@tonic-gate " for unknown interface %s",
16320Sstevel@tonic-gate rtm_type_name(m.r.rtm.rtm_type),
16330Sstevel@tonic-gate strp, ifnamep);
16340Sstevel@tonic-gate }
16350Sstevel@tonic-gate } else {
16360Sstevel@tonic-gate trace_act("note %s with flags %s for %s",
16370Sstevel@tonic-gate rtm_type_name(m.r.rtm.rtm_type),
16380Sstevel@tonic-gate strp, ifp->int_name);
16390Sstevel@tonic-gate }
16400Sstevel@tonic-gate if (strp != str)
16410Sstevel@tonic-gate free(strp);
16420Sstevel@tonic-gate
16430Sstevel@tonic-gate /*
16440Sstevel@tonic-gate * After being informed of a change to an interface,
16450Sstevel@tonic-gate * check them all now if the check would otherwise
16460Sstevel@tonic-gate * be a long time from now, if the interface is
16470Sstevel@tonic-gate * not known, or if the interface has been turned
16480Sstevel@tonic-gate * off or on.
16490Sstevel@tonic-gate */
16500Sstevel@tonic-gate if (ifscan_timer.tv_sec-now.tv_sec >=
16510Sstevel@tonic-gate CHECK_BAD_INTERVAL || ifp == NULL ||
16520Sstevel@tonic-gate ((ifp->int_if_flags ^ m.ifm.ifm_flags) &
16534513Skcpoon IFF_UP) != 0)
16540Sstevel@tonic-gate ifscan_timer.tv_sec = now.tv_sec;
16550Sstevel@tonic-gate continue;
165611076SCathy.Zhou@Sun.COM } else if (m.r.rtm.rtm_type == RTM_CHGADDR ||
165711076SCathy.Zhou@Sun.COM m.r.rtm.rtm_type == RTM_FREEADDR) {
165811076SCathy.Zhou@Sun.COM continue;
16590Sstevel@tonic-gate } else {
16600Sstevel@tonic-gate if (m.r.rtm.rtm_index != 0)
16610Sstevel@tonic-gate ifp = ifwithindex(m.r.rtm.rtm_index, 1);
16620Sstevel@tonic-gate }
16630Sstevel@tonic-gate
16640Sstevel@tonic-gate (void) strlcpy(str, rtm_type_name(m.r.rtm.rtm_type),
16650Sstevel@tonic-gate sizeof (str));
16660Sstevel@tonic-gate strp = &str[strlen(str)];
16670Sstevel@tonic-gate if (m.r.rtm.rtm_type <= RTM_CHANGE)
16680Sstevel@tonic-gate strp += snprintf(strp, sizeof (str) - (strp - str),
16690Sstevel@tonic-gate " from pid %d", (int)m.r.rtm.rtm_pid);
16700Sstevel@tonic-gate
16710Sstevel@tonic-gate /* LINTED */
16720Sstevel@tonic-gate (void) rt_xaddrs(&info, (struct sockaddr_storage *)(&m.r.rtm +
16730Sstevel@tonic-gate 1), (char *)&m + cc, m.r.rtm.rtm_addrs);
16740Sstevel@tonic-gate
16750Sstevel@tonic-gate if (INFO_DST(&info) == 0) {
16760Sstevel@tonic-gate trace_act("ignore %s without dst", str);
16770Sstevel@tonic-gate continue;
16780Sstevel@tonic-gate }
16790Sstevel@tonic-gate
16800Sstevel@tonic-gate if (INFO_DST(&info)->ss_family != AF_INET) {
16810Sstevel@tonic-gate trace_act("ignore %s for AF %d", str,
16820Sstevel@tonic-gate INFO_DST(&info)->ss_family);
16830Sstevel@tonic-gate continue;
16840Sstevel@tonic-gate }
16850Sstevel@tonic-gate
16860Sstevel@tonic-gate mask = ((INFO_MASK(&info) != 0) ?
16870Sstevel@tonic-gate ntohl(S_ADDR(INFO_MASK(&info))) :
16880Sstevel@tonic-gate (m.r.rtm.rtm_flags & RTF_HOST) ?
16890Sstevel@tonic-gate HOST_MASK : std_mask(S_ADDR(INFO_DST(&info))));
16900Sstevel@tonic-gate
16910Sstevel@tonic-gate strp += snprintf(strp, sizeof (str) - (strp - str), ": %s",
16920Sstevel@tonic-gate addrname(S_ADDR(INFO_DST(&info)), mask, 0));
16930Sstevel@tonic-gate
16944513Skcpoon if (IN_MULTICAST(ntohl(S_ADDR(INFO_DST(&info)))) ||
16954513Skcpoon IN_LINKLOCAL(ntohl(S_ADDR(INFO_DST(&info))))) {
16964513Skcpoon trace_act("ignore multicast/link local %s", str);
16970Sstevel@tonic-gate continue;
16980Sstevel@tonic-gate }
16990Sstevel@tonic-gate
17000Sstevel@tonic-gate if (m.r.rtm.rtm_flags & RTF_LLINFO) {
17010Sstevel@tonic-gate trace_act("ignore ARP %s", str);
17020Sstevel@tonic-gate continue;
17030Sstevel@tonic-gate }
17040Sstevel@tonic-gate
17050Sstevel@tonic-gate if (get_info_gate(&INFO_GATE(&info), &gate_sin)) {
17060Sstevel@tonic-gate gate = S_ADDR(INFO_GATE(&info));
17070Sstevel@tonic-gate strp += snprintf(strp, sizeof (str) - (strp - str),
17080Sstevel@tonic-gate " --> %s", naddr_ntoa(gate));
17090Sstevel@tonic-gate } else {
17100Sstevel@tonic-gate gate = 0;
17110Sstevel@tonic-gate }
17120Sstevel@tonic-gate
17130Sstevel@tonic-gate if (INFO_AUTHOR(&info) != 0)
17140Sstevel@tonic-gate strp += snprintf(strp, sizeof (str) - (strp - str),
17150Sstevel@tonic-gate " by authority of %s",
17160Sstevel@tonic-gate saddr_ntoa(INFO_AUTHOR(&info)));
17170Sstevel@tonic-gate
17180Sstevel@tonic-gate switch (m.r.rtm.rtm_type) {
17190Sstevel@tonic-gate case RTM_ADD:
17200Sstevel@tonic-gate case RTM_CHANGE:
17210Sstevel@tonic-gate case RTM_REDIRECT:
17220Sstevel@tonic-gate if (m.r.rtm.rtm_errno != 0) {
17230Sstevel@tonic-gate trace_act("ignore %s with \"%s\" error",
17240Sstevel@tonic-gate str, rip_strerror(m.r.rtm.rtm_errno));
17250Sstevel@tonic-gate } else {
17260Sstevel@tonic-gate trace_act("%s", str);
17270Sstevel@tonic-gate rtm_add(&m.r.rtm, &info, 0,
17280Sstevel@tonic-gate !(m.r.rtm.rtm_flags & RTF_GATEWAY) &&
17290Sstevel@tonic-gate m.r.rtm.rtm_type != RTM_REDIRECT, ifp);
17300Sstevel@tonic-gate
17310Sstevel@tonic-gate }
17320Sstevel@tonic-gate break;
17330Sstevel@tonic-gate
17340Sstevel@tonic-gate case RTM_DELETE:
17350Sstevel@tonic-gate if (m.r.rtm.rtm_errno != 0 &&
17360Sstevel@tonic-gate m.r.rtm.rtm_errno != ESRCH) {
17370Sstevel@tonic-gate trace_act("ignore %s with \"%s\" error",
17380Sstevel@tonic-gate str, rip_strerror(m.r.rtm.rtm_errno));
17390Sstevel@tonic-gate } else {
17400Sstevel@tonic-gate trace_act("%s", str);
17410Sstevel@tonic-gate del_static(S_ADDR(INFO_DST(&info)), mask,
17420Sstevel@tonic-gate gate, ifp, 1);
17430Sstevel@tonic-gate }
17440Sstevel@tonic-gate break;
17450Sstevel@tonic-gate
17460Sstevel@tonic-gate case RTM_LOSING:
17470Sstevel@tonic-gate trace_act("%s", str);
17480Sstevel@tonic-gate rtm_lose(&m.r.rtm, &info);
17490Sstevel@tonic-gate break;
17500Sstevel@tonic-gate
17510Sstevel@tonic-gate default:
17520Sstevel@tonic-gate trace_act("ignore %s", str);
17530Sstevel@tonic-gate break;
17540Sstevel@tonic-gate }
17550Sstevel@tonic-gate }
17560Sstevel@tonic-gate }
17570Sstevel@tonic-gate
17580Sstevel@tonic-gate
17590Sstevel@tonic-gate /*
17600Sstevel@tonic-gate * Disassemble a routing message. The result is an array of pointers
17610Sstevel@tonic-gate * to sockaddr_storage structures stored in the info argument.
17620Sstevel@tonic-gate *
17630Sstevel@tonic-gate * ss is a pointer to the beginning of the data following the
17640Sstevel@tonic-gate * rt_msghdr contained in the routing socket message, which consists
17650Sstevel@tonic-gate * of a string of concatenated sockaddr structure of different types.
17661676Sjpk *
17671676Sjpk * Extended attributes can be appended at the end of the list.
17680Sstevel@tonic-gate */
17690Sstevel@tonic-gate static int
rt_xaddrs(struct rt_addrinfo * info,struct sockaddr_storage * ss,char * lim,int addrs)17700Sstevel@tonic-gate rt_xaddrs(struct rt_addrinfo *info,
17710Sstevel@tonic-gate struct sockaddr_storage *ss,
17720Sstevel@tonic-gate char *lim,
17730Sstevel@tonic-gate int addrs)
17740Sstevel@tonic-gate {
17750Sstevel@tonic-gate int retv = 0;
17760Sstevel@tonic-gate int i;
17770Sstevel@tonic-gate int abit;
17780Sstevel@tonic-gate int complaints;
17790Sstevel@tonic-gate static int prev_complaints;
17800Sstevel@tonic-gate
17810Sstevel@tonic-gate #define XBAD_AF 0x1
17820Sstevel@tonic-gate #define XBAD_SHORT 0x2
17830Sstevel@tonic-gate #define XBAD_LONG 0x4
17840Sstevel@tonic-gate
17850Sstevel@tonic-gate (void) memset(info, 0, sizeof (*info));
17860Sstevel@tonic-gate info->rti_addrs = addrs;
17870Sstevel@tonic-gate complaints = 0;
17880Sstevel@tonic-gate for (i = 0, abit = 1; i < RTAX_MAX && (char *)ss < lim;
17890Sstevel@tonic-gate i++, abit <<= 1) {
17900Sstevel@tonic-gate if ((addrs & abit) == 0)
17910Sstevel@tonic-gate continue;
17920Sstevel@tonic-gate info->rti_info[i] = ss;
17930Sstevel@tonic-gate /* Horrible interface here */
17940Sstevel@tonic-gate switch (ss->ss_family) {
17950Sstevel@tonic-gate case AF_UNIX:
17960Sstevel@tonic-gate /* LINTED */
17970Sstevel@tonic-gate ss = (struct sockaddr_storage *)(
17980Sstevel@tonic-gate (struct sockaddr_un *)ss + 1);
17990Sstevel@tonic-gate break;
18000Sstevel@tonic-gate case AF_INET:
18010Sstevel@tonic-gate /* LINTED */
18020Sstevel@tonic-gate ss = (struct sockaddr_storage *)(
18030Sstevel@tonic-gate (struct sockaddr_in *)ss + 1);
18040Sstevel@tonic-gate break;
18050Sstevel@tonic-gate case AF_LINK:
18060Sstevel@tonic-gate /* LINTED */
18070Sstevel@tonic-gate ss = (struct sockaddr_storage *)(
18080Sstevel@tonic-gate (struct sockaddr_dl *)ss + 1);
18090Sstevel@tonic-gate break;
18100Sstevel@tonic-gate case AF_INET6:
18110Sstevel@tonic-gate /* LINTED */
18120Sstevel@tonic-gate ss = (struct sockaddr_storage *)(
18130Sstevel@tonic-gate (struct sockaddr_in6 *)ss + 1);
18140Sstevel@tonic-gate break;
18150Sstevel@tonic-gate default:
18160Sstevel@tonic-gate if (!(prev_complaints & XBAD_AF))
18170Sstevel@tonic-gate writelog(LOG_WARNING,
18180Sstevel@tonic-gate "unknown address family %d "
18190Sstevel@tonic-gate "encountered", ss->ss_family);
18200Sstevel@tonic-gate if (complaints & XBAD_AF)
18210Sstevel@tonic-gate goto xaddr_done;
18220Sstevel@tonic-gate /* LINTED */
18230Sstevel@tonic-gate ss = (struct sockaddr_storage *)(
18240Sstevel@tonic-gate (struct sockaddr *)ss + 1);
18250Sstevel@tonic-gate complaints |= XBAD_AF;
18260Sstevel@tonic-gate info->rti_addrs &= abit - 1;
18270Sstevel@tonic-gate addrs = info->rti_addrs;
18280Sstevel@tonic-gate retv = -1;
18290Sstevel@tonic-gate break;
18300Sstevel@tonic-gate }
18310Sstevel@tonic-gate if ((char *)ss > lim) {
18320Sstevel@tonic-gate if (!(prev_complaints & XBAD_SHORT))
18330Sstevel@tonic-gate msglog("sockaddr %d too short by %d "
18340Sstevel@tonic-gate "bytes", i + 1, (char *)ss - lim);
18350Sstevel@tonic-gate complaints |= XBAD_SHORT;
18360Sstevel@tonic-gate info->rti_info[i] = NULL;
18370Sstevel@tonic-gate info->rti_addrs &= abit - 1;
18380Sstevel@tonic-gate retv = -1;
18390Sstevel@tonic-gate goto xaddr_done;
18400Sstevel@tonic-gate }
18410Sstevel@tonic-gate }
18421676Sjpk
18431676Sjpk while (((char *)ss + sizeof (rtm_ext_t)) <= lim) {
18441676Sjpk rtm_ext_t *tp;
18451676Sjpk char *nxt;
18461676Sjpk
18471676Sjpk /* LINTED: alignment */
18481676Sjpk tp = (rtm_ext_t *)ss;
18491676Sjpk nxt = (char *)(tp + 1) + tp->rtmex_len;
18501676Sjpk
18511676Sjpk if (!IS_P2ALIGNED(tp->rtmex_len, sizeof (uint32_t)) ||
18521676Sjpk nxt > lim) {
18531676Sjpk break;
18541676Sjpk }
18551676Sjpk
18561676Sjpk /* LINTED: alignment */
18571676Sjpk ss = (struct sockaddr_storage *)nxt;
18581676Sjpk }
18591676Sjpk
18600Sstevel@tonic-gate if ((char *)ss != lim) {
18611676Sjpk if ((char *)ss > lim) {
18621676Sjpk if (!(prev_complaints & XBAD_SHORT))
18631676Sjpk msglog("routing message too short by %d bytes",
18641676Sjpk (char *)ss - lim);
18651676Sjpk complaints |= XBAD_SHORT;
18661676Sjpk } else if (!(prev_complaints & XBAD_LONG)) {
18670Sstevel@tonic-gate msglog("%d bytes of routing message left over",
18680Sstevel@tonic-gate lim - (char *)ss);
18691676Sjpk complaints |= XBAD_LONG;
18701676Sjpk }
18710Sstevel@tonic-gate retv = -1;
18720Sstevel@tonic-gate }
18730Sstevel@tonic-gate xaddr_done:
18740Sstevel@tonic-gate prev_complaints = complaints;
18750Sstevel@tonic-gate return (retv);
18760Sstevel@tonic-gate }
18770Sstevel@tonic-gate
18780Sstevel@tonic-gate /* after aggregating, note routes that belong in the kernel */
18790Sstevel@tonic-gate static void
kern_out(struct ag_info * ag)18800Sstevel@tonic-gate kern_out(struct ag_info *ag)
18810Sstevel@tonic-gate {
18820Sstevel@tonic-gate struct khash *k;
18832781Ssowmini struct interface *ifp;
18842781Ssowmini
18852781Ssowmini ifp = ag->ag_ifp;
18862781Ssowmini
18870Sstevel@tonic-gate /*
18880Sstevel@tonic-gate * Do not install bad routes if they are not already present.
18890Sstevel@tonic-gate * This includes routes that had RS_NET_SYN for interfaces that
18900Sstevel@tonic-gate * recently died.
18910Sstevel@tonic-gate */
18920Sstevel@tonic-gate if (ag->ag_metric == HOPCNT_INFINITY) {
18930Sstevel@tonic-gate k = kern_find(htonl(ag->ag_dst_h), ag->ag_mask,
18940Sstevel@tonic-gate ag->ag_nhop, ag->ag_ifp, NULL);
18950Sstevel@tonic-gate if (k == NULL)
18960Sstevel@tonic-gate return;
18970Sstevel@tonic-gate } else {
18980Sstevel@tonic-gate k = kern_add(htonl(ag->ag_dst_h), ag->ag_mask, ag->ag_nhop,
18992781Ssowmini ifp);
19000Sstevel@tonic-gate }
19010Sstevel@tonic-gate
19020Sstevel@tonic-gate if (k->k_state & KS_NEW) {
19030Sstevel@tonic-gate /* will need to add new entry to the kernel table */
19040Sstevel@tonic-gate k->k_state = KS_ADD;
19050Sstevel@tonic-gate if (ag->ag_state & AGS_GATEWAY)
19060Sstevel@tonic-gate k->k_state |= KS_GATEWAY;
19070Sstevel@tonic-gate if (ag->ag_state & AGS_IF)
19080Sstevel@tonic-gate k->k_state |= KS_IF;
19090Sstevel@tonic-gate if (ag->ag_state & AGS_PASSIVE)
19100Sstevel@tonic-gate k->k_state |= KS_PASSIVE;
19110Sstevel@tonic-gate if (ag->ag_state & AGS_FILE)
19120Sstevel@tonic-gate k->k_state |= KS_FILE;
19130Sstevel@tonic-gate k->k_gate = ag->ag_nhop;
19142781Ssowmini k->k_ifp = ifp;
19150Sstevel@tonic-gate k->k_metric = ag->ag_metric;
19160Sstevel@tonic-gate return;
19170Sstevel@tonic-gate }
19180Sstevel@tonic-gate
19190Sstevel@tonic-gate if ((k->k_state & (KS_STATIC|KS_DEPRE_IF)) ||
19200Sstevel@tonic-gate ((k->k_state & (KS_IF|KS_PASSIVE)) == KS_IF)) {
19210Sstevel@tonic-gate return;
19220Sstevel@tonic-gate }
19230Sstevel@tonic-gate
19240Sstevel@tonic-gate /* modify existing kernel entry if necessary */
19250Sstevel@tonic-gate if (k->k_gate == ag->ag_nhop && k->k_ifp == ag->ag_ifp &&
19260Sstevel@tonic-gate k->k_metric != ag->ag_metric) {
19270Sstevel@tonic-gate /*
19280Sstevel@tonic-gate * Must delete bad interface routes etc.
19290Sstevel@tonic-gate * to change them.
19300Sstevel@tonic-gate */
19310Sstevel@tonic-gate if (k->k_metric == HOPCNT_INFINITY)
19320Sstevel@tonic-gate k->k_state |= KS_DEL_ADD;
19330Sstevel@tonic-gate k->k_gate = ag->ag_nhop;
19340Sstevel@tonic-gate k->k_metric = ag->ag_metric;
19350Sstevel@tonic-gate k->k_state |= KS_CHANGE;
19360Sstevel@tonic-gate }
19370Sstevel@tonic-gate
19380Sstevel@tonic-gate /*
19390Sstevel@tonic-gate * If the daemon thinks the route should exist, forget
19400Sstevel@tonic-gate * about any redirections.
19410Sstevel@tonic-gate * If the daemon thinks the route should exist, eventually
19420Sstevel@tonic-gate * override manual intervention by the operator.
19430Sstevel@tonic-gate */
19440Sstevel@tonic-gate if ((k->k_state & (KS_DYNAMIC | KS_DELETED)) != 0) {
19450Sstevel@tonic-gate k->k_state &= ~KS_DYNAMIC;
19460Sstevel@tonic-gate k->k_state |= (KS_ADD | KS_DEL_ADD);
19470Sstevel@tonic-gate }
19480Sstevel@tonic-gate
19490Sstevel@tonic-gate if ((k->k_state & KS_GATEWAY) && !(ag->ag_state & AGS_GATEWAY)) {
19500Sstevel@tonic-gate k->k_state &= ~KS_GATEWAY;
19510Sstevel@tonic-gate k->k_state |= (KS_ADD | KS_DEL_ADD);
19520Sstevel@tonic-gate } else if (!(k->k_state & KS_GATEWAY) && (ag->ag_state & AGS_GATEWAY)) {
19530Sstevel@tonic-gate k->k_state |= KS_GATEWAY;
19540Sstevel@tonic-gate k->k_state |= (KS_ADD | KS_DEL_ADD);
19550Sstevel@tonic-gate }
19560Sstevel@tonic-gate
19570Sstevel@tonic-gate /*
19580Sstevel@tonic-gate * Deleting-and-adding is necessary to change aspects of a route.
19590Sstevel@tonic-gate * Just delete instead of deleting and then adding a bad route.
19600Sstevel@tonic-gate * Otherwise, we want to keep the route in the kernel.
19610Sstevel@tonic-gate */
19620Sstevel@tonic-gate if (k->k_metric == HOPCNT_INFINITY && (k->k_state & KS_DEL_ADD))
19630Sstevel@tonic-gate k->k_state |= KS_DELETE;
19640Sstevel@tonic-gate else
19650Sstevel@tonic-gate k->k_state &= ~KS_DELETE;
19660Sstevel@tonic-gate #undef RT
19670Sstevel@tonic-gate }
19680Sstevel@tonic-gate
19690Sstevel@tonic-gate /*
19700Sstevel@tonic-gate * Update our image of the kernel forwarding table using the given
19710Sstevel@tonic-gate * route from our internal routing table.
19720Sstevel@tonic-gate */
19730Sstevel@tonic-gate
19740Sstevel@tonic-gate /*ARGSUSED1*/
19750Sstevel@tonic-gate static int
walk_kern(struct radix_node * rn,void * argp)19760Sstevel@tonic-gate walk_kern(struct radix_node *rn, void *argp)
19770Sstevel@tonic-gate {
19780Sstevel@tonic-gate #define RT ((struct rt_entry *)rn)
19790Sstevel@tonic-gate uint8_t metric, pref;
19800Sstevel@tonic-gate uint_t ags = 0;
19810Sstevel@tonic-gate int i;
19820Sstevel@tonic-gate struct rt_spare *rts;
19830Sstevel@tonic-gate
19840Sstevel@tonic-gate /* Do not install synthetic routes */
19850Sstevel@tonic-gate if (RT->rt_state & RS_NET_SYN)
19860Sstevel@tonic-gate return (0);
19870Sstevel@tonic-gate
19880Sstevel@tonic-gate /*
19890Sstevel@tonic-gate * Do not install static routes here. Only
19900Sstevel@tonic-gate * read_rt->rtm_add->kern_add should install those
19910Sstevel@tonic-gate */
19920Sstevel@tonic-gate if ((RT->rt_state & RS_STATIC) &&
19930Sstevel@tonic-gate (RT->rt_spares[0].rts_origin != RO_FILE))
19940Sstevel@tonic-gate return (0);
19950Sstevel@tonic-gate
19960Sstevel@tonic-gate /* Do not clobber kernel if this is a route for a dead interface */
19970Sstevel@tonic-gate if (RT->rt_state & RS_BADIF)
19980Sstevel@tonic-gate return (0);
19990Sstevel@tonic-gate
20000Sstevel@tonic-gate if (!(RT->rt_state & RS_IF)) {
20010Sstevel@tonic-gate /* This is an ordinary route, not for an interface. */
20020Sstevel@tonic-gate
20030Sstevel@tonic-gate /*
20040Sstevel@tonic-gate * aggregate, ordinary good routes without regard to
20050Sstevel@tonic-gate * their metric
20060Sstevel@tonic-gate */
20070Sstevel@tonic-gate pref = 1;
20080Sstevel@tonic-gate ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_AGGREGATE);
20090Sstevel@tonic-gate
20100Sstevel@tonic-gate /*
20110Sstevel@tonic-gate * Do not install host routes directly to hosts, to avoid
20120Sstevel@tonic-gate * interfering with ARP entries in the kernel table.
20130Sstevel@tonic-gate */
20140Sstevel@tonic-gate if (RT_ISHOST(RT) && ntohl(RT->rt_dst) == RT->rt_gate)
20150Sstevel@tonic-gate return (0);
20160Sstevel@tonic-gate
20170Sstevel@tonic-gate } else {
20180Sstevel@tonic-gate /*
20190Sstevel@tonic-gate * This is an interface route.
20200Sstevel@tonic-gate * Do not install routes for "external" remote interfaces.
20210Sstevel@tonic-gate */
20220Sstevel@tonic-gate if (RT->rt_ifp != NULL && (RT->rt_ifp->int_state & IS_EXTERNAL))
20230Sstevel@tonic-gate return (0);
20240Sstevel@tonic-gate
20250Sstevel@tonic-gate /* Interfaces should override received routes. */
20260Sstevel@tonic-gate pref = 0;
20270Sstevel@tonic-gate ags |= (AGS_IF | AGS_CORS_GATE);
20280Sstevel@tonic-gate if (RT->rt_ifp != NULL &&
20290Sstevel@tonic-gate !(RT->rt_ifp->int_if_flags & IFF_LOOPBACK) &&
20300Sstevel@tonic-gate (RT->rt_ifp->int_state & (IS_PASSIVE|IS_ALIAS)) ==
20310Sstevel@tonic-gate IS_PASSIVE) {
20320Sstevel@tonic-gate ags |= AGS_PASSIVE;
20330Sstevel@tonic-gate }
20340Sstevel@tonic-gate
20350Sstevel@tonic-gate /*
20360Sstevel@tonic-gate * If it is not an interface, or an alias for an interface,
20370Sstevel@tonic-gate * it must be a "gateway."
20380Sstevel@tonic-gate *
20390Sstevel@tonic-gate * If it is a "remote" interface, it is also a "gateway" to
20400Sstevel@tonic-gate * the kernel if is not a alias.
20410Sstevel@tonic-gate */
2042879Sbw if (RT->rt_ifp == NULL || (RT->rt_ifp->int_state & IS_REMOTE)) {
2043879Sbw
2044879Sbw ags |= (AGS_GATEWAY | AGS_SUPPRESS);
2045879Sbw
2046879Sbw /*
2047879Sbw * Do not aggregate IS_PASSIVE routes.
2048879Sbw */
2049879Sbw if (!(RT->rt_ifp->int_state & IS_PASSIVE))
2050879Sbw ags |= AGS_AGGREGATE;
2051879Sbw }
20520Sstevel@tonic-gate }
20530Sstevel@tonic-gate
20540Sstevel@tonic-gate metric = RT->rt_metric;
20550Sstevel@tonic-gate if (metric == HOPCNT_INFINITY) {
20560Sstevel@tonic-gate /* If the route is dead, try hard to aggregate. */
20570Sstevel@tonic-gate pref = HOPCNT_INFINITY;
20580Sstevel@tonic-gate ags |= (AGS_FINE_GATE | AGS_SUPPRESS);
20590Sstevel@tonic-gate ags &= ~(AGS_IF | AGS_CORS_GATE);
20600Sstevel@tonic-gate }
20610Sstevel@tonic-gate
20620Sstevel@tonic-gate /*
20630Sstevel@tonic-gate * dump all routes that have the same metric as rt_spares[0]
20640Sstevel@tonic-gate * into the kern_table, to be added to the kernel.
20650Sstevel@tonic-gate */
20660Sstevel@tonic-gate for (i = 0; i < RT->rt_num_spares; i++) {
20670Sstevel@tonic-gate rts = &RT->rt_spares[i];
20680Sstevel@tonic-gate
20690Sstevel@tonic-gate /* Do not install external routes */
20700Sstevel@tonic-gate if (rts->rts_flags & RTS_EXTERNAL)
20710Sstevel@tonic-gate continue;
20720Sstevel@tonic-gate
20730Sstevel@tonic-gate if (rts->rts_metric == metric) {
20740Sstevel@tonic-gate ag_check(RT->rt_dst, RT->rt_mask,
20750Sstevel@tonic-gate rts->rts_router, rts->rts_ifp, rts->rts_gate,
20760Sstevel@tonic-gate metric, pref, 0, 0,
20770Sstevel@tonic-gate (rts->rts_origin & RO_FILE) ? (ags|AGS_FILE) : ags,
20780Sstevel@tonic-gate kern_out);
20790Sstevel@tonic-gate }
20800Sstevel@tonic-gate }
20810Sstevel@tonic-gate return (0);
20820Sstevel@tonic-gate #undef RT
20830Sstevel@tonic-gate }
20840Sstevel@tonic-gate
20850Sstevel@tonic-gate
20860Sstevel@tonic-gate /* Update the kernel table to match the daemon table. */
20870Sstevel@tonic-gate static void
fix_kern(void)20880Sstevel@tonic-gate fix_kern(void)
20890Sstevel@tonic-gate {
20900Sstevel@tonic-gate int i;
20910Sstevel@tonic-gate struct khash *k, *pk, *knext;
20920Sstevel@tonic-gate
20930Sstevel@tonic-gate
20940Sstevel@tonic-gate need_kern = age_timer;
20950Sstevel@tonic-gate
20960Sstevel@tonic-gate /* Walk daemon table, updating the copy of the kernel table. */
20970Sstevel@tonic-gate (void) rn_walktree(rhead, walk_kern, NULL);
20980Sstevel@tonic-gate ag_flush(0, 0, kern_out);
20990Sstevel@tonic-gate
21000Sstevel@tonic-gate for (i = 0; i < KHASH_SIZE; i++) {
21010Sstevel@tonic-gate pk = NULL;
21020Sstevel@tonic-gate for (k = khash_bins[i]; k != NULL; k = knext) {
21030Sstevel@tonic-gate knext = k->k_next;
21040Sstevel@tonic-gate
21050Sstevel@tonic-gate /* Do not touch local interface routes */
21060Sstevel@tonic-gate if ((k->k_state & KS_DEPRE_IF) ||
21070Sstevel@tonic-gate (k->k_state & (KS_IF|KS_PASSIVE)) == KS_IF) {
21080Sstevel@tonic-gate pk = k;
21090Sstevel@tonic-gate continue;
21100Sstevel@tonic-gate }
21110Sstevel@tonic-gate
21120Sstevel@tonic-gate /* Do not touch static routes */
21130Sstevel@tonic-gate if (k->k_state & KS_STATIC) {
21140Sstevel@tonic-gate kern_check_static(k, 0);
21150Sstevel@tonic-gate pk = k;
21160Sstevel@tonic-gate continue;
21170Sstevel@tonic-gate }
21180Sstevel@tonic-gate
21190Sstevel@tonic-gate /* check hold on routes deleted by the operator */
21200Sstevel@tonic-gate if (k->k_keep > now.tv_sec) {
21210Sstevel@tonic-gate /* ensure we check when the hold is over */
21220Sstevel@tonic-gate LIM_SEC(need_kern, k->k_keep);
21230Sstevel@tonic-gate pk = k;
21240Sstevel@tonic-gate continue;
21250Sstevel@tonic-gate }
21260Sstevel@tonic-gate
21270Sstevel@tonic-gate if ((k->k_state & KS_DELETE) &&
21280Sstevel@tonic-gate !(k->k_state & KS_DYNAMIC)) {
21290Sstevel@tonic-gate if ((k->k_dst == RIP_DEFAULT) &&
21300Sstevel@tonic-gate (k->k_ifp != NULL) &&
21310Sstevel@tonic-gate (kern_alternate(RIP_DEFAULT,
21320Sstevel@tonic-gate k->k_mask, k->k_gate, k->k_ifp,
21330Sstevel@tonic-gate NULL) == NULL))
21340Sstevel@tonic-gate rdisc_restore(k->k_ifp);
21350Sstevel@tonic-gate kern_ioctl(k, RTM_DELETE, 0);
21360Sstevel@tonic-gate if (pk != NULL)
21370Sstevel@tonic-gate pk->k_next = knext;
21380Sstevel@tonic-gate else
21390Sstevel@tonic-gate khash_bins[i] = knext;
21400Sstevel@tonic-gate free(k);
21410Sstevel@tonic-gate continue;
21420Sstevel@tonic-gate }
21430Sstevel@tonic-gate
21440Sstevel@tonic-gate if (k->k_state & KS_DEL_ADD)
21450Sstevel@tonic-gate kern_ioctl(k, RTM_DELETE, 0);
21460Sstevel@tonic-gate
21470Sstevel@tonic-gate if (k->k_state & KS_ADD) {
21480Sstevel@tonic-gate if ((k->k_dst == RIP_DEFAULT) &&
21490Sstevel@tonic-gate (k->k_ifp != NULL))
21500Sstevel@tonic-gate rdisc_suppress(k->k_ifp);
21510Sstevel@tonic-gate kern_ioctl(k, RTM_ADD,
21520Sstevel@tonic-gate ((0 != (k->k_state & (KS_GATEWAY |
21534513Skcpoon KS_DYNAMIC))) ? RTF_GATEWAY : 0));
21540Sstevel@tonic-gate } else if (k->k_state & KS_CHANGE) {
2155*11418SSowmini.Varadhan@Sun.COM kern_ioctl(k, RTM_CHANGE,
21560Sstevel@tonic-gate ((0 != (k->k_state & (KS_GATEWAY |
21574513Skcpoon KS_DYNAMIC))) ? RTF_GATEWAY : 0));
21580Sstevel@tonic-gate }
21590Sstevel@tonic-gate k->k_state &= ~(KS_ADD|KS_CHANGE|KS_DEL_ADD);
21600Sstevel@tonic-gate
21610Sstevel@tonic-gate /*
21620Sstevel@tonic-gate * Mark this route to be deleted in the next cycle.
21630Sstevel@tonic-gate * This deletes routes that disappear from the
21640Sstevel@tonic-gate * daemon table, since the normal aging code
21650Sstevel@tonic-gate * will clear the bit for routes that have not
21660Sstevel@tonic-gate * disappeared from the daemon table.
21670Sstevel@tonic-gate */
21680Sstevel@tonic-gate k->k_state |= KS_DELETE;
21690Sstevel@tonic-gate pk = k;
21700Sstevel@tonic-gate }
21710Sstevel@tonic-gate }
21720Sstevel@tonic-gate }
21730Sstevel@tonic-gate
21740Sstevel@tonic-gate
21750Sstevel@tonic-gate /* Delete a static route in the image of the kernel table. */
21760Sstevel@tonic-gate void
del_static(in_addr_t dst,in_addr_t mask,in_addr_t gate,struct interface * ifp,int gone)21770Sstevel@tonic-gate del_static(in_addr_t dst, in_addr_t mask, in_addr_t gate,
21780Sstevel@tonic-gate struct interface *ifp, int gone)
21790Sstevel@tonic-gate {
21800Sstevel@tonic-gate struct khash *k;
21810Sstevel@tonic-gate struct rt_entry *rt;
21820Sstevel@tonic-gate
21830Sstevel@tonic-gate /*
21840Sstevel@tonic-gate * Just mark it in the table to be deleted next time the kernel
21850Sstevel@tonic-gate * table is updated.
21860Sstevel@tonic-gate * If it has already been deleted, mark it as such, and set its
21870Sstevel@tonic-gate * keep-timer so that it will not be deleted again for a while.
21880Sstevel@tonic-gate * This lets the operator delete a route added by the daemon
21890Sstevel@tonic-gate * and add a replacement.
21900Sstevel@tonic-gate */
21910Sstevel@tonic-gate k = kern_find(dst, mask, gate, ifp, NULL);
21920Sstevel@tonic-gate if (k != NULL && (gate == 0 || k->k_gate == gate)) {
21930Sstevel@tonic-gate k->k_state &= ~(KS_STATIC | KS_DYNAMIC | KS_CHECK);
21940Sstevel@tonic-gate k->k_state |= KS_DELETE;
21950Sstevel@tonic-gate if (gone) {
21960Sstevel@tonic-gate k->k_state |= KS_DELETED;
21970Sstevel@tonic-gate k->k_keep = now.tv_sec + K_KEEP_LIM;
21980Sstevel@tonic-gate }
21990Sstevel@tonic-gate }
22000Sstevel@tonic-gate
22010Sstevel@tonic-gate rt = rtget(dst, mask);
22020Sstevel@tonic-gate if (rt != NULL && (rt->rt_state & RS_STATIC))
22030Sstevel@tonic-gate rtbad(rt, NULL);
22040Sstevel@tonic-gate }
22050Sstevel@tonic-gate
22060Sstevel@tonic-gate
22070Sstevel@tonic-gate /*
22080Sstevel@tonic-gate * Delete all routes generated from ICMP Redirects that use a given gateway,
22090Sstevel@tonic-gate * as well as old redirected routes.
22100Sstevel@tonic-gate */
22110Sstevel@tonic-gate void
del_redirects(in_addr_t bad_gate,time_t old)22120Sstevel@tonic-gate del_redirects(in_addr_t bad_gate, time_t old)
22130Sstevel@tonic-gate {
22140Sstevel@tonic-gate int i;
22150Sstevel@tonic-gate struct khash *k;
22160Sstevel@tonic-gate boolean_t dosupply = should_supply(NULL);
22170Sstevel@tonic-gate
22180Sstevel@tonic-gate for (i = 0; i < KHASH_SIZE; i++) {
22190Sstevel@tonic-gate for (k = khash_bins[i]; k != NULL; k = k->k_next) {
22200Sstevel@tonic-gate if (!(k->k_state & KS_DYNAMIC) ||
22210Sstevel@tonic-gate (k->k_state & (KS_STATIC|KS_IF|KS_DEPRE_IF)))
22220Sstevel@tonic-gate continue;
22230Sstevel@tonic-gate
22240Sstevel@tonic-gate if (k->k_gate != bad_gate && k->k_redirect_time > old &&
22250Sstevel@tonic-gate !dosupply)
22260Sstevel@tonic-gate continue;
22270Sstevel@tonic-gate
22280Sstevel@tonic-gate k->k_state |= KS_DELETE;
22290Sstevel@tonic-gate k->k_state &= ~KS_DYNAMIC;
22300Sstevel@tonic-gate need_kern.tv_sec = now.tv_sec;
22310Sstevel@tonic-gate trace_act("mark redirected %s --> %s for deletion",
22320Sstevel@tonic-gate addrname(k->k_dst, k->k_mask, 0),
22330Sstevel@tonic-gate naddr_ntoa(k->k_gate));
22340Sstevel@tonic-gate }
22350Sstevel@tonic-gate }
22360Sstevel@tonic-gate }
22370Sstevel@tonic-gate
22380Sstevel@tonic-gate /* Start the daemon tables. */
22390Sstevel@tonic-gate void
rtinit(void)22400Sstevel@tonic-gate rtinit(void)
22410Sstevel@tonic-gate {
22420Sstevel@tonic-gate int i;
22430Sstevel@tonic-gate struct ag_info *ag;
22440Sstevel@tonic-gate
22450Sstevel@tonic-gate /* Initialize the radix trees */
22460Sstevel@tonic-gate rn_init();
22470Sstevel@tonic-gate (void) rn_inithead((void**)&rhead, 32);
22480Sstevel@tonic-gate
22490Sstevel@tonic-gate /* mark all of the slots in the table free */
22500Sstevel@tonic-gate ag_avail = ag_slots;
22510Sstevel@tonic-gate for (ag = ag_slots, i = 1; i < NUM_AG_SLOTS; i++) {
22520Sstevel@tonic-gate ag->ag_fine = ag+1;
22530Sstevel@tonic-gate ag++;
22540Sstevel@tonic-gate }
22550Sstevel@tonic-gate }
22560Sstevel@tonic-gate
22570Sstevel@tonic-gate
22580Sstevel@tonic-gate static struct sockaddr_in dst_sock = {AF_INET};
22590Sstevel@tonic-gate static struct sockaddr_in mask_sock = {AF_INET};
22600Sstevel@tonic-gate
22610Sstevel@tonic-gate
22620Sstevel@tonic-gate static void
set_need_flash(void)22630Sstevel@tonic-gate set_need_flash(void)
22640Sstevel@tonic-gate {
22650Sstevel@tonic-gate if (!need_flash) {
22660Sstevel@tonic-gate need_flash = _B_TRUE;
22670Sstevel@tonic-gate /*
22680Sstevel@tonic-gate * Do not send the flash update immediately. Wait a little
22690Sstevel@tonic-gate * while to hear from other routers.
22700Sstevel@tonic-gate */
22710Sstevel@tonic-gate no_flash.tv_sec = now.tv_sec + MIN_WAITTIME;
22720Sstevel@tonic-gate }
22730Sstevel@tonic-gate }
22740Sstevel@tonic-gate
22750Sstevel@tonic-gate
22760Sstevel@tonic-gate /* Get a particular routing table entry */
22770Sstevel@tonic-gate struct rt_entry *
rtget(in_addr_t dst,in_addr_t mask)22780Sstevel@tonic-gate rtget(in_addr_t dst, in_addr_t mask)
22790Sstevel@tonic-gate {
22800Sstevel@tonic-gate struct rt_entry *rt;
22810Sstevel@tonic-gate
22820Sstevel@tonic-gate dst_sock.sin_addr.s_addr = dst;
22830Sstevel@tonic-gate mask_sock.sin_addr.s_addr = htonl(mask);
22840Sstevel@tonic-gate rt = (struct rt_entry *)rhead->rnh_lookup(&dst_sock, &mask_sock, rhead);
22850Sstevel@tonic-gate if (rt == NULL || rt->rt_dst != dst || rt->rt_mask != mask)
22860Sstevel@tonic-gate return (NULL);
22870Sstevel@tonic-gate
22880Sstevel@tonic-gate return (rt);
22890Sstevel@tonic-gate }
22900Sstevel@tonic-gate
22910Sstevel@tonic-gate
22920Sstevel@tonic-gate /* Find a route to dst as the kernel would. */
22930Sstevel@tonic-gate struct rt_entry *
rtfind(in_addr_t dst)22940Sstevel@tonic-gate rtfind(in_addr_t dst)
22950Sstevel@tonic-gate {
22960Sstevel@tonic-gate dst_sock.sin_addr.s_addr = dst;
22970Sstevel@tonic-gate return ((struct rt_entry *)rhead->rnh_matchaddr(&dst_sock, rhead));
22980Sstevel@tonic-gate }
22990Sstevel@tonic-gate
23000Sstevel@tonic-gate /* add a route to the table */
23010Sstevel@tonic-gate void
rtadd(in_addr_t dst,in_addr_t mask,uint16_t state,struct rt_spare * new)23020Sstevel@tonic-gate rtadd(in_addr_t dst,
23030Sstevel@tonic-gate in_addr_t mask,
23040Sstevel@tonic-gate uint16_t state, /* rt_state for the entry */
23050Sstevel@tonic-gate struct rt_spare *new)
23060Sstevel@tonic-gate {
23070Sstevel@tonic-gate struct rt_entry *rt;
23080Sstevel@tonic-gate in_addr_t smask;
23090Sstevel@tonic-gate int i;
23100Sstevel@tonic-gate struct rt_spare *rts;
23110Sstevel@tonic-gate
23120Sstevel@tonic-gate /* This is the only function that increments total_routes. */
23130Sstevel@tonic-gate if (total_routes == MAX_ROUTES) {
23140Sstevel@tonic-gate msglog("have maximum (%d) routes", total_routes);
23150Sstevel@tonic-gate return;
23160Sstevel@tonic-gate }
23170Sstevel@tonic-gate
23180Sstevel@tonic-gate rt = rtmalloc(sizeof (*rt), "rtadd");
23190Sstevel@tonic-gate (void) memset(rt, 0, sizeof (*rt));
23200Sstevel@tonic-gate rt->rt_spares = rtmalloc(SPARE_INC * sizeof (struct rt_spare),
23210Sstevel@tonic-gate "rtadd");
23220Sstevel@tonic-gate rt->rt_num_spares = SPARE_INC;
23230Sstevel@tonic-gate (void) memset(rt->rt_spares, 0, SPARE_INC * sizeof (struct rt_spare));
23240Sstevel@tonic-gate for (rts = rt->rt_spares, i = rt->rt_num_spares; i != 0; i--, rts++)
23250Sstevel@tonic-gate rts->rts_metric = HOPCNT_INFINITY;
23260Sstevel@tonic-gate
23270Sstevel@tonic-gate rt->rt_nodes->rn_key = (uint8_t *)&rt->rt_dst_sock;
23280Sstevel@tonic-gate rt->rt_dst = dst;
23290Sstevel@tonic-gate rt->rt_dst_sock.sin_family = AF_INET;
23300Sstevel@tonic-gate if (mask != HOST_MASK) {
23310Sstevel@tonic-gate smask = std_mask(dst);
23320Sstevel@tonic-gate if ((smask & ~mask) == 0 && mask > smask)
23330Sstevel@tonic-gate state |= RS_SUBNET;
23340Sstevel@tonic-gate }
23350Sstevel@tonic-gate mask_sock.sin_addr.s_addr = htonl(mask);
23360Sstevel@tonic-gate rt->rt_mask = mask;
23370Sstevel@tonic-gate rt->rt_spares[0] = *new;
23380Sstevel@tonic-gate rt->rt_state = state;
23390Sstevel@tonic-gate rt->rt_time = now.tv_sec;
23400Sstevel@tonic-gate rt->rt_poison_metric = HOPCNT_INFINITY;
23410Sstevel@tonic-gate rt->rt_seqno = update_seqno;
23420Sstevel@tonic-gate
23430Sstevel@tonic-gate if (TRACEACTIONS)
23440Sstevel@tonic-gate trace_add_del("Add", rt);
23450Sstevel@tonic-gate
23460Sstevel@tonic-gate need_kern.tv_sec = now.tv_sec;
23470Sstevel@tonic-gate set_need_flash();
23480Sstevel@tonic-gate
23490Sstevel@tonic-gate if (NULL == rhead->rnh_addaddr(&rt->rt_dst_sock, &mask_sock, rhead,
23500Sstevel@tonic-gate rt->rt_nodes)) {
23510Sstevel@tonic-gate msglog("rnh_addaddr() failed for %s mask=%s",
23520Sstevel@tonic-gate naddr_ntoa(dst), naddr_ntoa(htonl(mask)));
23530Sstevel@tonic-gate free(rt);
23540Sstevel@tonic-gate }
23550Sstevel@tonic-gate
23560Sstevel@tonic-gate total_routes++;
23570Sstevel@tonic-gate }
23580Sstevel@tonic-gate
23590Sstevel@tonic-gate
23600Sstevel@tonic-gate /* notice a changed route */
23610Sstevel@tonic-gate void
rtchange(struct rt_entry * rt,uint16_t state,struct rt_spare * new,char * label)23620Sstevel@tonic-gate rtchange(struct rt_entry *rt,
23630Sstevel@tonic-gate uint16_t state, /* new state bits */
23640Sstevel@tonic-gate struct rt_spare *new,
23650Sstevel@tonic-gate char *label)
23660Sstevel@tonic-gate {
23670Sstevel@tonic-gate if (rt->rt_metric != new->rts_metric) {
23680Sstevel@tonic-gate /*
23690Sstevel@tonic-gate * Fix the kernel immediately if it seems the route
23700Sstevel@tonic-gate * has gone bad, since there may be a working route that
23710Sstevel@tonic-gate * aggregates this route.
23720Sstevel@tonic-gate */
23730Sstevel@tonic-gate if (new->rts_metric == HOPCNT_INFINITY) {
23740Sstevel@tonic-gate need_kern.tv_sec = now.tv_sec;
23750Sstevel@tonic-gate if (new->rts_time >= now.tv_sec - EXPIRE_TIME)
23760Sstevel@tonic-gate new->rts_time = now.tv_sec - EXPIRE_TIME;
23770Sstevel@tonic-gate }
23780Sstevel@tonic-gate rt->rt_seqno = update_seqno;
23790Sstevel@tonic-gate set_need_flash();
23800Sstevel@tonic-gate }
23810Sstevel@tonic-gate
23820Sstevel@tonic-gate if (rt->rt_gate != new->rts_gate) {
23830Sstevel@tonic-gate need_kern.tv_sec = now.tv_sec;
23840Sstevel@tonic-gate rt->rt_seqno = update_seqno;
23850Sstevel@tonic-gate set_need_flash();
23860Sstevel@tonic-gate }
23870Sstevel@tonic-gate
23880Sstevel@tonic-gate state |= (rt->rt_state & RS_SUBNET);
23890Sstevel@tonic-gate
23900Sstevel@tonic-gate /* Keep various things from deciding ageless routes are stale. */
23910Sstevel@tonic-gate if (!AGE_RT(state, rt->rt_spares[0].rts_origin, new->rts_ifp))
23920Sstevel@tonic-gate new->rts_time = now.tv_sec;
23930Sstevel@tonic-gate
23940Sstevel@tonic-gate if (TRACEACTIONS)
23950Sstevel@tonic-gate trace_change(rt, state, new,
23960Sstevel@tonic-gate label ? label : "Chg ");
23970Sstevel@tonic-gate
23980Sstevel@tonic-gate rt->rt_state = state;
23990Sstevel@tonic-gate /*
24000Sstevel@tonic-gate * If the interface state of the new primary route is good,
24010Sstevel@tonic-gate * turn off RS_BADIF flag
24020Sstevel@tonic-gate */
24030Sstevel@tonic-gate if ((rt->rt_state & RS_BADIF) &&
24040Sstevel@tonic-gate IS_IFF_UP(new->rts_ifp->int_if_flags) &&
24050Sstevel@tonic-gate !(new->rts_ifp->int_state & (IS_BROKE | IS_SICK)))
24060Sstevel@tonic-gate rt->rt_state &= ~(RS_BADIF);
24070Sstevel@tonic-gate
24080Sstevel@tonic-gate rt->rt_spares[0] = *new;
24090Sstevel@tonic-gate }
24100Sstevel@tonic-gate
24110Sstevel@tonic-gate
24120Sstevel@tonic-gate /* check for a better route among the spares */
24130Sstevel@tonic-gate static struct rt_spare *
rts_better(struct rt_entry * rt)24140Sstevel@tonic-gate rts_better(struct rt_entry *rt)
24150Sstevel@tonic-gate {
24160Sstevel@tonic-gate struct rt_spare *rts, *rts1;
24170Sstevel@tonic-gate int i;
24180Sstevel@tonic-gate
24190Sstevel@tonic-gate /* find the best alternative among the spares */
24200Sstevel@tonic-gate rts = rt->rt_spares+1;
24210Sstevel@tonic-gate for (i = rt->rt_num_spares, rts1 = rts+1; i > 2; i--, rts1++) {
24220Sstevel@tonic-gate if (BETTER_LINK(rt, rts1, rts))
24230Sstevel@tonic-gate rts = rts1;
24240Sstevel@tonic-gate }
24250Sstevel@tonic-gate
24260Sstevel@tonic-gate return (rts);
24270Sstevel@tonic-gate }
24280Sstevel@tonic-gate
24290Sstevel@tonic-gate
24300Sstevel@tonic-gate /* switch to a backup route */
24310Sstevel@tonic-gate void
rtswitch(struct rt_entry * rt,struct rt_spare * rts)24320Sstevel@tonic-gate rtswitch(struct rt_entry *rt,
24330Sstevel@tonic-gate struct rt_spare *rts)
24340Sstevel@tonic-gate {
24350Sstevel@tonic-gate struct rt_spare swap;
24360Sstevel@tonic-gate char label[10];
24370Sstevel@tonic-gate
24380Sstevel@tonic-gate /* Do not change permanent routes */
24390Sstevel@tonic-gate if (0 != (rt->rt_state & (RS_MHOME | RS_STATIC |
24400Sstevel@tonic-gate RS_NET_SYN | RS_IF)))
24410Sstevel@tonic-gate return;
24420Sstevel@tonic-gate
24430Sstevel@tonic-gate /* find the best alternative among the spares */
24440Sstevel@tonic-gate if (rts == NULL)
24450Sstevel@tonic-gate rts = rts_better(rt);
24460Sstevel@tonic-gate
24470Sstevel@tonic-gate /* Do not bother if it is not worthwhile. */
24480Sstevel@tonic-gate if (!BETTER_LINK(rt, rts, rt->rt_spares))
24490Sstevel@tonic-gate return;
24500Sstevel@tonic-gate
24510Sstevel@tonic-gate swap = rt->rt_spares[0];
24520Sstevel@tonic-gate (void) snprintf(label, sizeof (label), "Use #%d",
24530Sstevel@tonic-gate (int)(rts - rt->rt_spares));
24540Sstevel@tonic-gate rtchange(rt, rt->rt_state & ~(RS_NET_SYN), rts, label);
24550Sstevel@tonic-gate
24560Sstevel@tonic-gate if (swap.rts_metric == HOPCNT_INFINITY) {
24570Sstevel@tonic-gate *rts = rts_empty;
24580Sstevel@tonic-gate } else {
24590Sstevel@tonic-gate *rts = swap;
24600Sstevel@tonic-gate }
24610Sstevel@tonic-gate
24620Sstevel@tonic-gate }
24630Sstevel@tonic-gate
24640Sstevel@tonic-gate
24650Sstevel@tonic-gate void
rtdelete(struct rt_entry * rt)24660Sstevel@tonic-gate rtdelete(struct rt_entry *rt)
24670Sstevel@tonic-gate {
24680Sstevel@tonic-gate struct rt_entry *deleted_rt;
24690Sstevel@tonic-gate struct rt_spare *rts;
24700Sstevel@tonic-gate int i;
24710Sstevel@tonic-gate in_addr_t gate = rt->rt_gate; /* for debugging */
24720Sstevel@tonic-gate
24730Sstevel@tonic-gate if (TRACEACTIONS)
24740Sstevel@tonic-gate trace_add_del("Del", rt);
24750Sstevel@tonic-gate
24760Sstevel@tonic-gate for (i = 0; i < rt->rt_num_spares; i++) {
24770Sstevel@tonic-gate rts = &rt->rt_spares[i];
24780Sstevel@tonic-gate rts_delete(rt, rts);
24790Sstevel@tonic-gate }
24800Sstevel@tonic-gate
24810Sstevel@tonic-gate dst_sock.sin_addr.s_addr = rt->rt_dst;
24820Sstevel@tonic-gate mask_sock.sin_addr.s_addr = htonl(rt->rt_mask);
24830Sstevel@tonic-gate if (rt != (deleted_rt =
24840Sstevel@tonic-gate ((struct rt_entry *)rhead->rnh_deladdr(&dst_sock, &mask_sock,
24850Sstevel@tonic-gate rhead)))) {
24860Sstevel@tonic-gate msglog("rnh_deladdr(%s) failed; found rt 0x%lx",
24870Sstevel@tonic-gate rtname(rt->rt_dst, rt->rt_mask, gate), deleted_rt);
24880Sstevel@tonic-gate if (deleted_rt != NULL)
24890Sstevel@tonic-gate free(deleted_rt);
24900Sstevel@tonic-gate }
24910Sstevel@tonic-gate total_routes--;
24923725Ssowmini free(rt->rt_spares);
24930Sstevel@tonic-gate free(rt);
24940Sstevel@tonic-gate
24950Sstevel@tonic-gate if (dst_sock.sin_addr.s_addr == RIP_DEFAULT) {
24960Sstevel@tonic-gate /*
24970Sstevel@tonic-gate * we just deleted the default route. Trigger rdisc_sort
24980Sstevel@tonic-gate * so that we can recover from any rdisc information that
24990Sstevel@tonic-gate * is valid
25000Sstevel@tonic-gate */
25010Sstevel@tonic-gate rdisc_timer.tv_sec = 0;
25020Sstevel@tonic-gate }
25030Sstevel@tonic-gate }
25040Sstevel@tonic-gate
25050Sstevel@tonic-gate void
rts_delete(struct rt_entry * rt,struct rt_spare * rts)25060Sstevel@tonic-gate rts_delete(struct rt_entry *rt, struct rt_spare *rts)
25070Sstevel@tonic-gate {
25080Sstevel@tonic-gate struct khash *k;
25090Sstevel@tonic-gate
25100Sstevel@tonic-gate trace_upslot(rt, rts, &rts_empty);
25110Sstevel@tonic-gate k = kern_find(rt->rt_dst, rt->rt_mask,
25120Sstevel@tonic-gate rts->rts_gate, rts->rts_ifp, NULL);
25130Sstevel@tonic-gate if (k != NULL &&
25140Sstevel@tonic-gate !(k->k_state & KS_DEPRE_IF) &&
25150Sstevel@tonic-gate ((k->k_state & (KS_IF|KS_PASSIVE)) != KS_IF)) {
25160Sstevel@tonic-gate k->k_state |= KS_DELETE;
25170Sstevel@tonic-gate need_kern.tv_sec = now.tv_sec;
25180Sstevel@tonic-gate }
25190Sstevel@tonic-gate
25200Sstevel@tonic-gate *rts = rts_empty;
25210Sstevel@tonic-gate }
25220Sstevel@tonic-gate
25230Sstevel@tonic-gate /*
25240Sstevel@tonic-gate * Get rid of a bad route, and try to switch to a replacement.
25250Sstevel@tonic-gate * If the route has gone bad because of a bad interface,
25260Sstevel@tonic-gate * the information about the dead interface is available in badifp
25270Sstevel@tonic-gate * for the purpose of sanity checks, if_flags checks etc.
25280Sstevel@tonic-gate */
25290Sstevel@tonic-gate static void
rtbad(struct rt_entry * rt,struct interface * badifp)25300Sstevel@tonic-gate rtbad(struct rt_entry *rt, struct interface *badifp)
25310Sstevel@tonic-gate {
25320Sstevel@tonic-gate struct rt_spare new;
25330Sstevel@tonic-gate uint16_t rt_state;
25340Sstevel@tonic-gate
25350Sstevel@tonic-gate
25360Sstevel@tonic-gate if (badifp == NULL || (rt->rt_spares[0].rts_ifp == badifp)) {
25370Sstevel@tonic-gate /* Poison the route */
25380Sstevel@tonic-gate new = rt->rt_spares[0];
25390Sstevel@tonic-gate new.rts_metric = HOPCNT_INFINITY;
25400Sstevel@tonic-gate rt_state = rt->rt_state & ~(RS_IF | RS_LOCAL | RS_STATIC);
25410Sstevel@tonic-gate }
25420Sstevel@tonic-gate
25430Sstevel@tonic-gate if (badifp != NULL) {
25440Sstevel@tonic-gate /*
25450Sstevel@tonic-gate * Dont mark the rtentry bad unless the ifp for the primary
25460Sstevel@tonic-gate * route is the bad ifp
25470Sstevel@tonic-gate */
25480Sstevel@tonic-gate if (rt->rt_spares[0].rts_ifp != badifp)
25490Sstevel@tonic-gate return;
25500Sstevel@tonic-gate /*
25510Sstevel@tonic-gate * badifp has just gone bad. We want to keep this
25520Sstevel@tonic-gate * rt_entry around so that we tell our rip-neighbors
25530Sstevel@tonic-gate * about the bad route, but we can't do anything
25540Sstevel@tonic-gate * to the kernel itself, so mark it as RS_BADIF
25550Sstevel@tonic-gate */
25560Sstevel@tonic-gate trace_misc("rtbad:Setting RS_BADIF (%s)", badifp->int_name);
25570Sstevel@tonic-gate rt_state |= RS_BADIF;
25580Sstevel@tonic-gate new.rts_ifp = &dummy_ifp;
25590Sstevel@tonic-gate }
25600Sstevel@tonic-gate rtchange(rt, rt_state, &new, 0);
25610Sstevel@tonic-gate rtswitch(rt, 0);
25620Sstevel@tonic-gate }
25630Sstevel@tonic-gate
25640Sstevel@tonic-gate
25650Sstevel@tonic-gate /*
25660Sstevel@tonic-gate * Junk a RS_NET_SYN or RS_LOCAL route,
25670Sstevel@tonic-gate * unless it is needed by another interface.
25680Sstevel@tonic-gate */
25690Sstevel@tonic-gate void
rtbad_sub(struct rt_entry * rt,struct interface * badifp)25700Sstevel@tonic-gate rtbad_sub(struct rt_entry *rt, struct interface *badifp)
25710Sstevel@tonic-gate {
25720Sstevel@tonic-gate struct interface *ifp, *ifp1;
25730Sstevel@tonic-gate struct intnet *intnetp;
25740Sstevel@tonic-gate uint_t state;
25750Sstevel@tonic-gate
25760Sstevel@tonic-gate
25770Sstevel@tonic-gate ifp1 = NULL;
25780Sstevel@tonic-gate state = 0;
25790Sstevel@tonic-gate
25800Sstevel@tonic-gate if (rt->rt_state & RS_LOCAL) {
25810Sstevel@tonic-gate /*
25820Sstevel@tonic-gate * Is this the route through loopback for the interface?
25830Sstevel@tonic-gate * If so, see if it is used by any other interfaces, such
25840Sstevel@tonic-gate * as a point-to-point interface with the same local address.
25850Sstevel@tonic-gate */
25860Sstevel@tonic-gate for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
25870Sstevel@tonic-gate /* Retain it if another interface needs it. */
25880Sstevel@tonic-gate if (ifp->int_addr == rt->rt_ifp->int_addr) {
25890Sstevel@tonic-gate state |= RS_LOCAL;
25900Sstevel@tonic-gate ifp1 = ifp;
25910Sstevel@tonic-gate break;
25920Sstevel@tonic-gate }
25930Sstevel@tonic-gate }
25940Sstevel@tonic-gate
25950Sstevel@tonic-gate }
25960Sstevel@tonic-gate
25970Sstevel@tonic-gate if (!(state & RS_LOCAL)) {
25980Sstevel@tonic-gate /*
25990Sstevel@tonic-gate * Retain RIPv1 logical network route if there is another
26000Sstevel@tonic-gate * interface that justifies it.
26010Sstevel@tonic-gate */
26020Sstevel@tonic-gate if (rt->rt_state & RS_NET_SYN) {
26030Sstevel@tonic-gate for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
26040Sstevel@tonic-gate if ((ifp->int_state & IS_NEED_NET_SYN) &&
26050Sstevel@tonic-gate rt->rt_mask == ifp->int_std_mask &&
26060Sstevel@tonic-gate rt->rt_dst == ifp->int_std_addr) {
26070Sstevel@tonic-gate state |= RS_NET_SYN;
26080Sstevel@tonic-gate ifp1 = ifp;
26090Sstevel@tonic-gate break;
26100Sstevel@tonic-gate }
26110Sstevel@tonic-gate }
26120Sstevel@tonic-gate }
26130Sstevel@tonic-gate
26140Sstevel@tonic-gate /* or if there is an authority route that needs it. */
26150Sstevel@tonic-gate for (intnetp = intnets; intnetp != NULL;
26160Sstevel@tonic-gate intnetp = intnetp->intnet_next) {
26170Sstevel@tonic-gate if (intnetp->intnet_addr == rt->rt_dst &&
26180Sstevel@tonic-gate intnetp->intnet_mask == rt->rt_mask) {
26190Sstevel@tonic-gate state |= (RS_NET_SYN | RS_NET_INT);
26200Sstevel@tonic-gate break;
26210Sstevel@tonic-gate }
26220Sstevel@tonic-gate }
26230Sstevel@tonic-gate }
26240Sstevel@tonic-gate
26250Sstevel@tonic-gate if (ifp1 != NULL || (state & RS_NET_SYN)) {
26260Sstevel@tonic-gate struct rt_spare new = rt->rt_spares[0];
26270Sstevel@tonic-gate new.rts_ifp = ifp1;
26280Sstevel@tonic-gate rtchange(rt, ((rt->rt_state & ~(RS_NET_SYN|RS_LOCAL)) | state),
26290Sstevel@tonic-gate &new, 0);
26300Sstevel@tonic-gate } else {
26310Sstevel@tonic-gate rtbad(rt, badifp);
26320Sstevel@tonic-gate }
26330Sstevel@tonic-gate }
26340Sstevel@tonic-gate
26350Sstevel@tonic-gate /*
26360Sstevel@tonic-gate * Called while walking the table looking for sick interfaces
26370Sstevel@tonic-gate * or after a time change.
26380Sstevel@tonic-gate */
26390Sstevel@tonic-gate int
walk_bad(struct radix_node * rn,void * argp)26400Sstevel@tonic-gate walk_bad(struct radix_node *rn,
26410Sstevel@tonic-gate void *argp)
26420Sstevel@tonic-gate {
26430Sstevel@tonic-gate #define RT ((struct rt_entry *)rn)
26440Sstevel@tonic-gate struct rt_spare *rts;
26450Sstevel@tonic-gate int i, j = -1;
26460Sstevel@tonic-gate
26470Sstevel@tonic-gate /* fix any spare routes through the interface */
26480Sstevel@tonic-gate for (i = 1; i < RT->rt_num_spares; i++) {
26490Sstevel@tonic-gate rts = &((struct rt_entry *)rn)->rt_spares[i];
26500Sstevel@tonic-gate
26510Sstevel@tonic-gate if (rts->rts_metric < HOPCNT_INFINITY &&
26520Sstevel@tonic-gate (rts->rts_ifp == NULL ||
26530Sstevel@tonic-gate (rts->rts_ifp->int_state & IS_BROKE)))
26540Sstevel@tonic-gate rts_delete(RT, rts);
26550Sstevel@tonic-gate else {
26560Sstevel@tonic-gate if (rts->rts_origin != RO_NONE)
26570Sstevel@tonic-gate j = i;
26580Sstevel@tonic-gate }
26590Sstevel@tonic-gate }
26600Sstevel@tonic-gate
26610Sstevel@tonic-gate /*
26620Sstevel@tonic-gate * Deal with the main route
26630Sstevel@tonic-gate * finished if it has been handled before or if its interface is ok
26640Sstevel@tonic-gate */
26650Sstevel@tonic-gate if (RT->rt_ifp == NULL || !(RT->rt_ifp->int_state & IS_BROKE))
26660Sstevel@tonic-gate return (0);
26670Sstevel@tonic-gate
26680Sstevel@tonic-gate /* Bad routes for other than interfaces are easy. */
26690Sstevel@tonic-gate if (!(RT->rt_state & (RS_IF | RS_NET_SYN | RS_LOCAL))) {
2670552Ssowmini if (j > 0) {
2671552Ssowmini RT->rt_spares[0].rts_metric = HOPCNT_INFINITY;
26720Sstevel@tonic-gate rtswitch(RT, NULL);
2673552Ssowmini } else {
26740Sstevel@tonic-gate rtbad(RT, (struct interface *)argp);
2675552Ssowmini }
26760Sstevel@tonic-gate return (0);
26770Sstevel@tonic-gate }
26780Sstevel@tonic-gate
26790Sstevel@tonic-gate rtbad_sub(RT, (struct interface *)argp);
26800Sstevel@tonic-gate return (0);
26810Sstevel@tonic-gate #undef RT
26820Sstevel@tonic-gate }
26830Sstevel@tonic-gate
26840Sstevel@tonic-gate /*
26850Sstevel@tonic-gate * Called while walking the table to replace a duplicate interface
26860Sstevel@tonic-gate * with a backup.
26870Sstevel@tonic-gate */
26880Sstevel@tonic-gate int
walk_rewire(struct radix_node * rn,void * argp)26890Sstevel@tonic-gate walk_rewire(struct radix_node *rn, void *argp)
26900Sstevel@tonic-gate {
26910Sstevel@tonic-gate struct rt_entry *RT = (struct rt_entry *)rn;
26920Sstevel@tonic-gate struct rewire_data *wire = (struct rewire_data *)argp;
26930Sstevel@tonic-gate struct rt_spare *rts;
26940Sstevel@tonic-gate int i;
26950Sstevel@tonic-gate
26960Sstevel@tonic-gate /* fix any spare routes through the interface */
26970Sstevel@tonic-gate rts = RT->rt_spares;
26980Sstevel@tonic-gate for (i = RT->rt_num_spares; i > 0; i--, rts++) {
26990Sstevel@tonic-gate if (rts->rts_ifp == wire->if_old) {
27000Sstevel@tonic-gate rts->rts_ifp = wire->if_new;
27010Sstevel@tonic-gate if ((RT->rt_dst == RIP_DEFAULT) &&
27020Sstevel@tonic-gate (wire->if_old->int_state & IS_SUPPRESS_RDISC))
27030Sstevel@tonic-gate rdisc_suppress(rts->rts_ifp);
27040Sstevel@tonic-gate if ((rts->rts_metric += wire->metric_delta) >
27050Sstevel@tonic-gate HOPCNT_INFINITY)
27060Sstevel@tonic-gate rts->rts_metric = HOPCNT_INFINITY;
27070Sstevel@tonic-gate
27080Sstevel@tonic-gate /*
27090Sstevel@tonic-gate * If the main route is getting a worse metric,
27100Sstevel@tonic-gate * then it may be time to switch to a backup.
27110Sstevel@tonic-gate */
27120Sstevel@tonic-gate if (i == RT->rt_num_spares && wire->metric_delta > 0) {
27130Sstevel@tonic-gate rtswitch(RT, NULL);
27140Sstevel@tonic-gate }
27150Sstevel@tonic-gate }
27160Sstevel@tonic-gate }
27170Sstevel@tonic-gate
27180Sstevel@tonic-gate return (0);
27190Sstevel@tonic-gate }
27200Sstevel@tonic-gate
27210Sstevel@tonic-gate /* Check the age of an individual route. */
27220Sstevel@tonic-gate static int
walk_age(struct radix_node * rn,void * argp)27230Sstevel@tonic-gate walk_age(struct radix_node *rn, void *argp)
27240Sstevel@tonic-gate {
27250Sstevel@tonic-gate #define RT ((struct rt_entry *)rn)
27260Sstevel@tonic-gate struct interface *ifp;
27270Sstevel@tonic-gate struct rt_spare *rts;
27280Sstevel@tonic-gate int i;
27290Sstevel@tonic-gate in_addr_t age_bad_gate = *(in_addr_t *)argp;
27300Sstevel@tonic-gate
27310Sstevel@tonic-gate
27320Sstevel@tonic-gate /*
27330Sstevel@tonic-gate * age all of the spare routes, including the primary route
27340Sstevel@tonic-gate * currently in use
27350Sstevel@tonic-gate */
27360Sstevel@tonic-gate rts = RT->rt_spares;
27370Sstevel@tonic-gate for (i = RT->rt_num_spares; i != 0; i--, rts++) {
27380Sstevel@tonic-gate
27390Sstevel@tonic-gate ifp = rts->rts_ifp;
27400Sstevel@tonic-gate if (i == RT->rt_num_spares) {
27410Sstevel@tonic-gate if (!AGE_RT(RT->rt_state, rts->rts_origin, ifp)) {
27420Sstevel@tonic-gate /*
27430Sstevel@tonic-gate * Keep various things from deciding ageless
27440Sstevel@tonic-gate * routes are stale
27450Sstevel@tonic-gate */
27460Sstevel@tonic-gate rts->rts_time = now.tv_sec;
27470Sstevel@tonic-gate continue;
27480Sstevel@tonic-gate }
27490Sstevel@tonic-gate
27500Sstevel@tonic-gate /* forget RIP routes after RIP has been turned off. */
27510Sstevel@tonic-gate if (rip_sock < 0) {
27520Sstevel@tonic-gate rts->rts_time = now_stale + 1;
27530Sstevel@tonic-gate }
27540Sstevel@tonic-gate }
27550Sstevel@tonic-gate
27560Sstevel@tonic-gate /* age failing routes */
27570Sstevel@tonic-gate if (age_bad_gate == rts->rts_gate &&
27580Sstevel@tonic-gate rts->rts_time >= now_stale) {
27590Sstevel@tonic-gate rts->rts_time -= SUPPLY_INTERVAL;
27600Sstevel@tonic-gate }
27610Sstevel@tonic-gate
27620Sstevel@tonic-gate /* trash the spare routes when they go bad */
27630Sstevel@tonic-gate if (rts->rts_origin == RO_RIP &&
27640Sstevel@tonic-gate ((rip_sock < 0) ||
27650Sstevel@tonic-gate (rts->rts_metric < HOPCNT_INFINITY &&
27660Sstevel@tonic-gate now_garbage > rts->rts_time)) &&
27670Sstevel@tonic-gate i != RT->rt_num_spares) {
27680Sstevel@tonic-gate rts_delete(RT, rts);
27690Sstevel@tonic-gate }
27700Sstevel@tonic-gate }
27710Sstevel@tonic-gate
27720Sstevel@tonic-gate
27730Sstevel@tonic-gate /* finished if the active route is still fresh */
27740Sstevel@tonic-gate if (now_stale <= RT->rt_time)
27750Sstevel@tonic-gate return (0);
27760Sstevel@tonic-gate
27770Sstevel@tonic-gate /* try to switch to an alternative */
27780Sstevel@tonic-gate rtswitch(RT, NULL);
27790Sstevel@tonic-gate
27800Sstevel@tonic-gate /* Delete a dead route after it has been publically mourned. */
27810Sstevel@tonic-gate if (now_garbage > RT->rt_time) {
27820Sstevel@tonic-gate rtdelete(RT);
27830Sstevel@tonic-gate return (0);
27840Sstevel@tonic-gate }
27850Sstevel@tonic-gate
27860Sstevel@tonic-gate /* Start poisoning a bad route before deleting it. */
27870Sstevel@tonic-gate if (now.tv_sec - RT->rt_time > EXPIRE_TIME) {
27880Sstevel@tonic-gate struct rt_spare new = RT->rt_spares[0];
27890Sstevel@tonic-gate
27900Sstevel@tonic-gate new.rts_metric = HOPCNT_INFINITY;
27910Sstevel@tonic-gate rtchange(RT, RT->rt_state, &new, 0);
27920Sstevel@tonic-gate }
27930Sstevel@tonic-gate return (0);
27940Sstevel@tonic-gate }
27950Sstevel@tonic-gate
27960Sstevel@tonic-gate
27970Sstevel@tonic-gate /* Watch for dead routes and interfaces. */
27980Sstevel@tonic-gate void
age(in_addr_t bad_gate)27990Sstevel@tonic-gate age(in_addr_t bad_gate)
28000Sstevel@tonic-gate {
28010Sstevel@tonic-gate struct interface *ifp;
28020Sstevel@tonic-gate int need_query = 0;
28030Sstevel@tonic-gate
28040Sstevel@tonic-gate /*
28050Sstevel@tonic-gate * If not listening to RIP, there is no need to age the routes in
28060Sstevel@tonic-gate * the table.
28070Sstevel@tonic-gate */
28080Sstevel@tonic-gate age_timer.tv_sec = (now.tv_sec
28090Sstevel@tonic-gate + ((rip_sock < 0) ? NEVER : SUPPLY_INTERVAL));
28100Sstevel@tonic-gate
28110Sstevel@tonic-gate /*
28120Sstevel@tonic-gate * Check for dead IS_REMOTE interfaces by timing their
28130Sstevel@tonic-gate * transmissions.
28140Sstevel@tonic-gate */
28150Sstevel@tonic-gate for (ifp = ifnet; ifp; ifp = ifp->int_next) {
28160Sstevel@tonic-gate if (!(ifp->int_state & IS_REMOTE))
28170Sstevel@tonic-gate continue;
28180Sstevel@tonic-gate
28190Sstevel@tonic-gate /* ignore unreachable remote interfaces */
28200Sstevel@tonic-gate if (!check_remote(ifp))
28210Sstevel@tonic-gate continue;
28220Sstevel@tonic-gate
28230Sstevel@tonic-gate /* Restore remote interface that has become reachable */
28240Sstevel@tonic-gate if (ifp->int_state & IS_BROKE)
28250Sstevel@tonic-gate if_ok(ifp, "remote ", _B_FALSE);
28260Sstevel@tonic-gate
28270Sstevel@tonic-gate if (ifp->int_act_time != NEVER &&
28280Sstevel@tonic-gate now.tv_sec - ifp->int_act_time > EXPIRE_TIME) {
28290Sstevel@tonic-gate writelog(LOG_NOTICE,
28300Sstevel@tonic-gate "remote interface %s to %s timed out after"
28310Sstevel@tonic-gate " %ld:%ld",
28320Sstevel@tonic-gate ifp->int_name,
28330Sstevel@tonic-gate naddr_ntoa(ifp->int_dstaddr),
28340Sstevel@tonic-gate (now.tv_sec - ifp->int_act_time)/60,
28350Sstevel@tonic-gate (now.tv_sec - ifp->int_act_time)%60);
28360Sstevel@tonic-gate if_sick(ifp, _B_FALSE);
28370Sstevel@tonic-gate }
28380Sstevel@tonic-gate
28390Sstevel@tonic-gate /*
28400Sstevel@tonic-gate * If we have not heard from the other router
28410Sstevel@tonic-gate * recently, ask it.
28420Sstevel@tonic-gate */
28430Sstevel@tonic-gate if (now.tv_sec >= ifp->int_query_time) {
28440Sstevel@tonic-gate ifp->int_query_time = NEVER;
28450Sstevel@tonic-gate need_query = 1;
28460Sstevel@tonic-gate }
28470Sstevel@tonic-gate }
28480Sstevel@tonic-gate
28490Sstevel@tonic-gate /* Age routes. */
28500Sstevel@tonic-gate (void) rn_walktree(rhead, walk_age, &bad_gate);
28510Sstevel@tonic-gate
28520Sstevel@tonic-gate /*
28530Sstevel@tonic-gate * delete old redirected routes to keep the kernel table small
28540Sstevel@tonic-gate * and prevent blackholes
28550Sstevel@tonic-gate */
28560Sstevel@tonic-gate del_redirects(bad_gate, now.tv_sec-STALE_TIME);
28570Sstevel@tonic-gate
28580Sstevel@tonic-gate /* Update the kernel routing table. */
28590Sstevel@tonic-gate fix_kern();
28600Sstevel@tonic-gate
28610Sstevel@tonic-gate /* poke reticent remote gateways */
28620Sstevel@tonic-gate if (need_query)
28630Sstevel@tonic-gate rip_query();
28640Sstevel@tonic-gate }
28650Sstevel@tonic-gate
28660Sstevel@tonic-gate void
kern_dump(void)28670Sstevel@tonic-gate kern_dump(void)
28680Sstevel@tonic-gate {
28690Sstevel@tonic-gate int i;
28700Sstevel@tonic-gate struct khash *k;
28710Sstevel@tonic-gate
28720Sstevel@tonic-gate for (i = 0; i < KHASH_SIZE; i++) {
28730Sstevel@tonic-gate for (k = khash_bins[i]; k != NULL; k = k->k_next)
28740Sstevel@tonic-gate trace_khash(k);
28750Sstevel@tonic-gate }
28760Sstevel@tonic-gate }
28770Sstevel@tonic-gate
28780Sstevel@tonic-gate
28790Sstevel@tonic-gate static struct interface *
gwkludge_iflookup(in_addr_t dstaddr,in_addr_t addr,in_addr_t mask)28800Sstevel@tonic-gate gwkludge_iflookup(in_addr_t dstaddr, in_addr_t addr, in_addr_t mask)
28810Sstevel@tonic-gate {
28820Sstevel@tonic-gate uint32_t int_state;
28830Sstevel@tonic-gate struct interface *ifp;
28840Sstevel@tonic-gate
28850Sstevel@tonic-gate for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
28860Sstevel@tonic-gate int_state = ifp->int_state;
28870Sstevel@tonic-gate
28880Sstevel@tonic-gate if (!(int_state & IS_REMOTE))
28890Sstevel@tonic-gate continue;
28900Sstevel@tonic-gate
28910Sstevel@tonic-gate if (ifp->int_dstaddr == dstaddr && ifp->int_addr == addr &&
28920Sstevel@tonic-gate ifp->int_mask == mask)
28930Sstevel@tonic-gate return (ifp);
28940Sstevel@tonic-gate }
28950Sstevel@tonic-gate return (NULL);
28960Sstevel@tonic-gate }
28977738SRishi.Srivatsavai@Sun.COM
28987738SRishi.Srivatsavai@Sun.COM /*
28997738SRishi.Srivatsavai@Sun.COM * Lookup logical interface structure given the gateway address.
29007738SRishi.Srivatsavai@Sun.COM * Returns null if no interfaces match the given name.
29017738SRishi.Srivatsavai@Sun.COM */
29027738SRishi.Srivatsavai@Sun.COM static struct interface *
lifp_iflookup(in_addr_t addr,const char * name)29037738SRishi.Srivatsavai@Sun.COM lifp_iflookup(in_addr_t addr, const char *name)
29047738SRishi.Srivatsavai@Sun.COM {
29057738SRishi.Srivatsavai@Sun.COM struct physical_interface *phyi;
29067738SRishi.Srivatsavai@Sun.COM struct interface *ifp;
29077738SRishi.Srivatsavai@Sun.COM struct interface *best = NULL;
29087738SRishi.Srivatsavai@Sun.COM
29097738SRishi.Srivatsavai@Sun.COM if ((phyi = phys_byname(name)) == NULL)
29107738SRishi.Srivatsavai@Sun.COM return (NULL);
29117738SRishi.Srivatsavai@Sun.COM
29127738SRishi.Srivatsavai@Sun.COM for (ifp = phyi->phyi_interface; ifp != NULL;
29137738SRishi.Srivatsavai@Sun.COM ifp = ifp->int_ilist.hl_next) {
29147738SRishi.Srivatsavai@Sun.COM
29157738SRishi.Srivatsavai@Sun.COM #ifdef DEBUG_KERNEL_ROUTE_READ
29167738SRishi.Srivatsavai@Sun.COM (void) fprintf(stderr, " checking interface"
29177738SRishi.Srivatsavai@Sun.COM " %-4s %-4s %-15s-->%-15s \n",
29187738SRishi.Srivatsavai@Sun.COM phyi->phyi_name, ifp->int_name,
29197738SRishi.Srivatsavai@Sun.COM naddr_ntoa(ifp->int_addr),
29207738SRishi.Srivatsavai@Sun.COM addrname(((ifp->int_if_flags & IFF_POINTOPOINT) ?
29217738SRishi.Srivatsavai@Sun.COM ifp->int_dstaddr : htonl(ifp->int_net)),
29227738SRishi.Srivatsavai@Sun.COM ifp->int_mask, 1));
29237738SRishi.Srivatsavai@Sun.COM #endif
29247738SRishi.Srivatsavai@Sun.COM /* Exact match found */
29257738SRishi.Srivatsavai@Sun.COM if (addr_on_ifp(addr, ifp, &best))
29267738SRishi.Srivatsavai@Sun.COM return (ifp);
29277738SRishi.Srivatsavai@Sun.COM }
29287738SRishi.Srivatsavai@Sun.COM /* No exact match found but return any best match found */
29297738SRishi.Srivatsavai@Sun.COM return (best);
29307738SRishi.Srivatsavai@Sun.COM }
2931