*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
|
|
|
/* $NetBSD: route.h,v 1.71 2008/11/07 00:20:13 dyoung Exp $ */
|
1994-06-29 10:29:24 +04:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
1994-05-11 13:26:46 +04:00
|
|
|
* Copyright (c) 1980, 1986, 1993
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
1993-03-21 12:45:37 +03:00
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
2003-08-07 20:26:28 +04:00
|
|
|
* 3. Neither the name of the University nor the names of its contributors
|
1993-03-21 12:45:37 +03:00
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
1997-04-03 01:17:28 +04:00
|
|
|
* @(#)route.h 8.5 (Berkeley) 2/8/95
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
|
|
|
|
1997-04-03 01:17:28 +04:00
|
|
|
#ifndef _NET_ROUTE_H_
|
|
|
|
#define _NET_ROUTE_H_
|
1998-04-29 21:49:58 +04:00
|
|
|
|
|
|
|
#include <sys/queue.h>
|
1998-05-03 01:19:03 +04:00
|
|
|
#include <sys/socket.h>
|
2006-11-13 08:13:38 +03:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <net/if.h>
|
1998-04-29 21:49:58 +04:00
|
|
|
|
2008-02-11 07:47:21 +03:00
|
|
|
#if !(defined(_KERNEL) || defined(_STANDALONE))
|
2008-01-21 23:25:33 +03:00
|
|
|
#include <stdbool.h>
|
|
|
|
#endif
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Kernel resident routing tables.
|
2005-02-27 01:45:09 +03:00
|
|
|
*
|
1993-03-21 12:45:37 +03:00
|
|
|
* The routing tables are initialized when interface addresses
|
|
|
|
* are set by making entries for all directly connected interfaces.
|
|
|
|
*/
|
|
|
|
|
2008-01-21 23:25:33 +03:00
|
|
|
/*
|
|
|
|
* A route consists of a destination address and a reference
|
|
|
|
* to a routing entry. These are often held by protocols
|
|
|
|
* in their control blocks, e.g. inpcb.
|
|
|
|
*/
|
|
|
|
struct route {
|
|
|
|
struct rtentry *_ro_rt;
|
|
|
|
struct sockaddr *ro_sa;
|
|
|
|
LIST_ENTRY(route) ro_rtcache_next;
|
|
|
|
bool ro_invalid;
|
|
|
|
};
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* These numbers are used by reliable protocols for determining
|
|
|
|
* retransmission behavior and are included in the routing structure.
|
|
|
|
*/
|
|
|
|
struct rt_metrics {
|
|
|
|
u_long rmx_locks; /* Kernel must leave these values alone */
|
|
|
|
u_long rmx_mtu; /* MTU for this path */
|
|
|
|
u_long rmx_hopcount; /* max hops expected */
|
|
|
|
u_long rmx_expire; /* lifetime for route, e.g. redirect */
|
2003-01-18 15:02:40 +03:00
|
|
|
u_long rmx_recvpipe; /* inbound delay-bandwidth product */
|
|
|
|
u_long rmx_sendpipe; /* outbound delay-bandwidth product */
|
1993-03-21 12:45:37 +03:00
|
|
|
u_long rmx_ssthresh; /* outbound gateway buffer limit */
|
|
|
|
u_long rmx_rtt; /* estimated round trip time */
|
|
|
|
u_long rmx_rttvar; /* estimated rtt variance */
|
1994-05-11 13:26:46 +04:00
|
|
|
u_long rmx_pksent; /* packets sent using this route */
|
1993-03-21 12:45:37 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* rmx_rtt and rmx_rttvar are stored as microseconds;
|
|
|
|
* RTTTOPRHZ(rtt) converts to a value suitable for use
|
|
|
|
* by a protocol slowtimo counter.
|
|
|
|
*/
|
|
|
|
#define RTM_RTTUNIT 1000000 /* units for rtt, rttvar, as units per sec */
|
|
|
|
#define RTTTOPRHZ(r) ((r) / (RTM_RTTUNIT / PR_SLOWHZ))
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We distinguish between routes to hosts and routes to networks,
|
|
|
|
* preferring the former if available. For each route we infer
|
|
|
|
* the interface to use from the gateway address supplied when
|
|
|
|
* the route was entered. Routes that forward packets through
|
|
|
|
* gateways are marked so that the output routines know to address the
|
|
|
|
* gateway rather than the ultimate destination.
|
|
|
|
*/
|
|
|
|
#ifndef RNF_NORMAL
|
1994-05-11 13:26:46 +04:00
|
|
|
#include <net/radix.h>
|
1993-03-21 12:45:37 +03:00
|
|
|
#endif
|
|
|
|
struct rtentry {
|
|
|
|
struct radix_node rt_nodes[2]; /* tree glue, and other values */
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
#define rt_mask(r) ((const struct sockaddr *)((r)->rt_nodes->rn_mask))
|
1993-03-21 12:45:37 +03:00
|
|
|
struct sockaddr *rt_gateway; /* value */
|
2000-05-04 21:33:03 +04:00
|
|
|
int rt_flags; /* up/down?, host/net */
|
|
|
|
int rt_refcnt; /* # held references */
|
1993-03-21 12:45:37 +03:00
|
|
|
u_long rt_use; /* raw # packets forwarded */
|
|
|
|
struct ifnet *rt_ifp; /* the answer: interface to use */
|
|
|
|
struct ifaddr *rt_ifa; /* the answer: interface to use */
|
2006-11-13 08:13:38 +03:00
|
|
|
uint32_t rt_ifa_seqno;
|
2007-03-04 08:59:00 +03:00
|
|
|
void * rt_llinfo; /* pointer to link level info cache */
|
1993-03-21 12:45:37 +03:00
|
|
|
struct rt_metrics rt_rmx; /* metrics used by rx'ing protocols */
|
1994-05-11 13:26:46 +04:00
|
|
|
struct rtentry *rt_gwroute; /* implied entry for gatewayed routes */
|
1998-04-29 07:41:49 +04:00
|
|
|
LIST_HEAD(, rttimer) rt_timer; /* queue of timeouts for misc funcs */
|
2001-01-27 13:39:33 +03:00
|
|
|
struct rtentry *rt_parent; /* parent of cloned route */
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
struct sockaddr *_rt_key;
|
1993-03-21 12:45:37 +03:00
|
|
|
};
|
|
|
|
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
static inline const struct sockaddr *
|
|
|
|
rt_getkey(const struct rtentry *rt)
|
|
|
|
{
|
|
|
|
return rt->_rt_key;
|
|
|
|
}
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Following structure necessary for 4.3 compatibility;
|
|
|
|
* We should eventually move it to a compat file.
|
|
|
|
*/
|
|
|
|
struct ortentry {
|
2008-02-20 20:05:52 +03:00
|
|
|
uint32_t rt_hash; /* to speed lookups */
|
1997-04-03 01:17:28 +04:00
|
|
|
struct sockaddr rt_dst; /* key */
|
|
|
|
struct sockaddr rt_gateway; /* value */
|
|
|
|
int16_t rt_flags; /* up/down?, host/net */
|
|
|
|
int16_t rt_refcnt; /* # held references */
|
2008-02-20 20:05:52 +03:00
|
|
|
uint32_t rt_use; /* raw # packets forwarded */
|
1997-04-03 01:17:28 +04:00
|
|
|
struct ifnet *rt_ifp; /* the answer: interface to use */
|
1993-03-21 12:45:37 +03:00
|
|
|
};
|
|
|
|
|
1994-05-11 13:26:46 +04:00
|
|
|
#define RTF_UP 0x1 /* route usable */
|
1993-03-21 12:45:37 +03:00
|
|
|
#define RTF_GATEWAY 0x2 /* destination is a gateway */
|
|
|
|
#define RTF_HOST 0x4 /* host entry (net otherwise) */
|
|
|
|
#define RTF_REJECT 0x8 /* host or net unreachable */
|
|
|
|
#define RTF_DYNAMIC 0x10 /* created dynamically (by redirect) */
|
|
|
|
#define RTF_MODIFIED 0x20 /* modified dynamically (by redirect) */
|
|
|
|
#define RTF_DONE 0x40 /* message confirmed */
|
|
|
|
#define RTF_MASK 0x80 /* subnet mask present */
|
|
|
|
#define RTF_CLONING 0x100 /* generate new routes on use */
|
|
|
|
#define RTF_XRESOLVE 0x200 /* external daemon resolves name */
|
|
|
|
#define RTF_LLINFO 0x400 /* generated by ARP or ESIS */
|
1994-05-11 13:26:46 +04:00
|
|
|
#define RTF_STATIC 0x800 /* manually added */
|
|
|
|
#define RTF_BLACKHOLE 0x1000 /* just discard pkts (during updates) */
|
2001-01-27 07:49:31 +03:00
|
|
|
#define RTF_CLONED 0x2000 /* this is a cloned route */
|
1993-03-21 12:45:37 +03:00
|
|
|
#define RTF_PROTO2 0x4000 /* protocol specific routing flag */
|
|
|
|
#define RTF_PROTO1 0x8000 /* protocol specific routing flag */
|
2006-11-13 08:13:38 +03:00
|
|
|
#define RTF_SRC 0x10000 /* route has fixed source address */
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Routing statistics.
|
|
|
|
*/
|
|
|
|
struct rtstat {
|
2001-02-21 08:45:11 +03:00
|
|
|
u_quad_t rts_badredirect; /* bogus redirect calls */
|
|
|
|
u_quad_t rts_dynamic; /* routes created by redirects */
|
2001-03-08 06:22:28 +03:00
|
|
|
u_quad_t rts_newgateway; /* routes modified by redirects */
|
2001-02-21 08:45:11 +03:00
|
|
|
u_quad_t rts_unreach; /* lookups which failed */
|
|
|
|
u_quad_t rts_wildcard; /* lookups satisfied by a wildcard */
|
1993-03-21 12:45:37 +03:00
|
|
|
};
|
|
|
|
/*
|
|
|
|
* Structures for routing messages.
|
|
|
|
*/
|
|
|
|
struct rt_msghdr {
|
|
|
|
u_short rtm_msglen; /* to skip over non-understood messages */
|
1994-05-11 13:26:46 +04:00
|
|
|
u_char rtm_version; /* future binary compatibility */
|
1993-03-21 12:45:37 +03:00
|
|
|
u_char rtm_type; /* message type */
|
|
|
|
u_short rtm_index; /* index for associated ifp */
|
1994-05-11 13:26:46 +04:00
|
|
|
int rtm_flags; /* flags, incl. kern & message, e.g. DONE */
|
1993-03-21 12:45:37 +03:00
|
|
|
int rtm_addrs; /* bitmask identifying sockaddrs in msg */
|
1994-05-11 13:26:46 +04:00
|
|
|
pid_t rtm_pid; /* identify sender */
|
1993-03-21 12:45:37 +03:00
|
|
|
int rtm_seq; /* for sender to identify action */
|
|
|
|
int rtm_errno; /* why failed */
|
|
|
|
int rtm_use; /* from rtentry */
|
|
|
|
u_long rtm_inits; /* which metrics we are initializing */
|
|
|
|
struct rt_metrics rtm_rmx; /* metrics themselves */
|
|
|
|
};
|
|
|
|
|
1994-05-11 13:26:46 +04:00
|
|
|
#define RTM_VERSION 3 /* Up the ante and ignore older versions */
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
#define RTM_ADD 0x1 /* Add Route */
|
|
|
|
#define RTM_DELETE 0x2 /* Delete Route */
|
|
|
|
#define RTM_CHANGE 0x3 /* Change Metrics or flags */
|
|
|
|
#define RTM_GET 0x4 /* Report Metrics */
|
|
|
|
#define RTM_LOSING 0x5 /* Kernel Suspects Partitioning */
|
|
|
|
#define RTM_REDIRECT 0x6 /* Told to use different route */
|
|
|
|
#define RTM_MISS 0x7 /* Lookup failed on this address */
|
|
|
|
#define RTM_LOCK 0x8 /* fix specified metrics */
|
|
|
|
#define RTM_OLDADD 0x9 /* caused by SIOCADDRT */
|
|
|
|
#define RTM_OLDDEL 0xa /* caused by SIOCDELRT */
|
|
|
|
#define RTM_RESOLVE 0xb /* req to resolve dst to LL addr */
|
1994-05-11 13:26:46 +04:00
|
|
|
#define RTM_NEWADDR 0xc /* address being added to iface */
|
|
|
|
#define RTM_DELADDR 0xd /* address being removed from iface */
|
1999-11-19 13:41:41 +03:00
|
|
|
#define RTM_OIFINFO 0xe /* Old (pre-1.5) RTM_IFINFO message */
|
2000-03-06 23:49:00 +03:00
|
|
|
#define RTM_IFINFO 0xf /* iface/link going up/down etc. */
|
|
|
|
#define RTM_IFANNOUNCE 0x10 /* iface arrival/departure */
|
2005-06-22 10:14:51 +04:00
|
|
|
#define RTM_IEEE80211 0x11 /* IEEE80211 wireless event */
|
2007-08-27 04:34:01 +04:00
|
|
|
#define RTM_SETGATE 0x12 /* set prototype gateway for clones
|
|
|
|
* (see example in arp_rtrequest).
|
|
|
|
*/
|
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
|
|
|
#define RTM_LLINFO_UPD 0x13 /* indication to ARP/NDP/etc. that link-layer
|
|
|
|
* address has changed
|
|
|
|
*/
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
#define RTV_MTU 0x1 /* init or lock _mtu */
|
|
|
|
#define RTV_HOPCOUNT 0x2 /* init or lock _hopcount */
|
2001-03-08 06:22:28 +03:00
|
|
|
#define RTV_EXPIRE 0x4 /* init or lock _expire */
|
1993-03-21 12:45:37 +03:00
|
|
|
#define RTV_RPIPE 0x8 /* init or lock _recvpipe */
|
|
|
|
#define RTV_SPIPE 0x10 /* init or lock _sendpipe */
|
|
|
|
#define RTV_SSTHRESH 0x20 /* init or lock _ssthresh */
|
|
|
|
#define RTV_RTT 0x40 /* init or lock _rtt */
|
|
|
|
#define RTV_RTTVAR 0x80 /* init or lock _rttvar */
|
|
|
|
|
1994-05-11 13:26:46 +04:00
|
|
|
/*
|
|
|
|
* Bitmask values for rtm_addr.
|
|
|
|
*/
|
1993-03-21 12:45:37 +03:00
|
|
|
#define RTA_DST 0x1 /* destination sockaddr present */
|
|
|
|
#define RTA_GATEWAY 0x2 /* gateway sockaddr present */
|
|
|
|
#define RTA_NETMASK 0x4 /* netmask sockaddr present */
|
|
|
|
#define RTA_GENMASK 0x8 /* cloning mask sockaddr present */
|
|
|
|
#define RTA_IFP 0x10 /* interface name sockaddr present */
|
|
|
|
#define RTA_IFA 0x20 /* interface addr sockaddr present */
|
|
|
|
#define RTA_AUTHOR 0x40 /* sockaddr for author of redirect */
|
1994-05-11 13:26:46 +04:00
|
|
|
#define RTA_BRD 0x80 /* for NEWADDR, broadcast or p-p dest addr */
|
1993-03-21 12:45:37 +03:00
|
|
|
|
1994-05-11 13:26:46 +04:00
|
|
|
/*
|
|
|
|
* Index offsets for sockaddr array for alternate internal encoding.
|
|
|
|
*/
|
|
|
|
#define RTAX_DST 0 /* destination sockaddr present */
|
|
|
|
#define RTAX_GATEWAY 1 /* gateway sockaddr present */
|
|
|
|
#define RTAX_NETMASK 2 /* netmask sockaddr present */
|
|
|
|
#define RTAX_GENMASK 3 /* cloning mask sockaddr present */
|
|
|
|
#define RTAX_IFP 4 /* interface name sockaddr present */
|
|
|
|
#define RTAX_IFA 5 /* interface addr sockaddr present */
|
|
|
|
#define RTAX_AUTHOR 6 /* sockaddr for author of redirect */
|
|
|
|
#define RTAX_BRD 7 /* for NEWADDR, broadcast or p-p dest addr */
|
|
|
|
#define RTAX_MAX 8 /* size of array to allocate */
|
|
|
|
|
|
|
|
struct rt_addrinfo {
|
|
|
|
int rti_addrs;
|
2004-04-21 08:17:28 +04:00
|
|
|
const struct sockaddr *rti_info[RTAX_MAX];
|
2001-01-17 07:05:41 +03:00
|
|
|
int rti_flags;
|
|
|
|
struct ifaddr *rti_ifa;
|
|
|
|
struct ifnet *rti_ifp;
|
|
|
|
struct rt_msghdr *rti_rtm;
|
1994-05-11 13:26:46 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
struct route_cb {
|
|
|
|
int ip_count;
|
1999-07-01 12:12:45 +04:00
|
|
|
int ip6_count;
|
1998-12-10 18:52:39 +03:00
|
|
|
int ipx_count;
|
1994-05-11 13:26:46 +04:00
|
|
|
int ns_count;
|
|
|
|
int iso_count;
|
|
|
|
int any_count;
|
|
|
|
};
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2005-02-27 01:45:09 +03:00
|
|
|
/*
|
1998-04-29 07:41:49 +04:00
|
|
|
* This structure, and the prototypes for the rt_timer_{init,remove_all,
|
|
|
|
* add,timer} functions all used with the kind permission of BSDI.
|
|
|
|
* These allow functions to be called for routes at specific times.
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct rttimer {
|
1998-12-27 21:27:48 +03:00
|
|
|
TAILQ_ENTRY(rttimer) rtt_next; /* entry on timer queue */
|
|
|
|
LIST_ENTRY(rttimer) rtt_link; /* multiple timers per rtentry */
|
2004-04-22 01:03:43 +04:00
|
|
|
struct rttimer_queue *rtt_queue; /* back pointer to queue */
|
|
|
|
struct rtentry *rtt_rt; /* Back pointer to the route */
|
|
|
|
void (*rtt_func)(struct rtentry *, struct rttimer *);
|
|
|
|
time_t rtt_time; /* When this timer was registered */
|
1998-04-29 07:41:49 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
struct rttimer_queue {
|
|
|
|
long rtq_timeout;
|
2000-12-09 04:29:45 +03:00
|
|
|
unsigned long rtq_count;
|
1998-12-27 21:27:48 +03:00
|
|
|
TAILQ_HEAD(, rttimer) rtq_head;
|
1998-04-29 07:41:49 +04:00
|
|
|
LIST_ENTRY(rttimer_queue) rtq_link;
|
1998-12-27 21:27:48 +03:00
|
|
|
};
|
1998-04-29 07:41:49 +04:00
|
|
|
|
|
|
|
|
1995-03-27 00:23:52 +04:00
|
|
|
#ifdef _KERNEL
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
#if 0
|
|
|
|
#define RT_DPRINTF(__fmt, ...) do { } while (/*CONSTCOND*/0)
|
|
|
|
#else
|
|
|
|
#define RT_DPRINTF(__fmt, ...) /* do nothing */
|
|
|
|
#endif
|
|
|
|
|
2007-06-09 07:07:21 +04:00
|
|
|
struct rtwalk {
|
|
|
|
int (*rw_f)(struct rtentry *, void *);
|
|
|
|
void *rw_v;
|
|
|
|
};
|
2002-05-13 00:40:11 +04:00
|
|
|
extern struct route_cb route_cb;
|
|
|
|
extern struct rtstat rtstat;
|
|
|
|
extern struct radix_node_head *rt_tables[AF_MAX+1];
|
1994-05-11 13:26:46 +04:00
|
|
|
|
1997-04-03 01:17:28 +04:00
|
|
|
struct socket;
|
2008-01-21 12:11:24 +03:00
|
|
|
struct dom_rtlist;
|
1997-04-03 01:17:28 +04:00
|
|
|
|
2004-04-22 01:03:43 +04:00
|
|
|
void route_init(void);
|
|
|
|
int route_output(struct mbuf *, ...);
|
|
|
|
int route_usrreq(struct socket *,
|
2005-12-11 15:16:03 +03:00
|
|
|
int, struct mbuf *, struct mbuf *, struct mbuf *, struct lwp *);
|
2008-03-26 17:53:14 +03:00
|
|
|
void rt_init(void);
|
2004-04-22 01:03:43 +04:00
|
|
|
void rt_ifannouncemsg(struct ifnet *, int);
|
2005-06-22 10:14:51 +04:00
|
|
|
void rt_ieee80211msg(struct ifnet *, int, void *, size_t);
|
2004-04-22 01:03:43 +04:00
|
|
|
void rt_ifmsg(struct ifnet *);
|
|
|
|
void rt_maskedcopy(const struct sockaddr *,
|
|
|
|
struct sockaddr *, const struct sockaddr *);
|
|
|
|
void rt_missmsg(int, struct rt_addrinfo *, int, int);
|
|
|
|
void rt_newaddrmsg(int, struct ifaddr *, int, struct rtentry *);
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
int rt_setgate(struct rtentry *, const struct sockaddr *);
|
2004-04-22 01:03:43 +04:00
|
|
|
void rt_setmetrics(u_long, const struct rt_metrics *, struct rt_metrics *);
|
|
|
|
int rt_timer_add(struct rtentry *,
|
1998-04-29 07:41:49 +04:00
|
|
|
void(*)(struct rtentry *, struct rttimer *),
|
2004-04-22 01:03:43 +04:00
|
|
|
struct rttimer_queue *);
|
|
|
|
void rt_timer_init(void);
|
1998-04-29 07:41:49 +04:00
|
|
|
struct rttimer_queue *
|
2004-04-22 01:03:43 +04:00
|
|
|
rt_timer_queue_create(u_int);
|
|
|
|
void rt_timer_queue_change(struct rttimer_queue *, long);
|
|
|
|
void rt_timer_queue_remove_all(struct rttimer_queue *, int);
|
|
|
|
void rt_timer_queue_destroy(struct rttimer_queue *, int);
|
|
|
|
void rt_timer_remove_all(struct rtentry *, int);
|
|
|
|
unsigned long rt_timer_count(struct rttimer_queue *);
|
|
|
|
void rt_timer_timer(void *);
|
|
|
|
void rtable_init(void **);
|
Here are various changes designed to protect against bad IPv4
routing caused by stale route caches (struct route). Route caches
are sprinkled throughout PCBs, the IP fast-forwarding table, and
IP tunnel interfaces (gre, gif, stf).
Stale IPv6 and ISO route caches will be treated by separate patches.
Thank you to Christoph Badura for suggesting the general approach
to invalidating route caches that I take here.
Here are the details:
Add hooks to struct domain for tracking and for invalidating each
domain's route caches: dom_rtcache, dom_rtflush, and dom_rtflushall.
Introduce helper subroutines, rtflush(ro) for invalidating a route
cache, rtflushall(family) for invalidating all route caches in a
routing domain, and rtcache(ro) for notifying the domain of a new
cached route.
Chain together all IPv4 route caches where ro_rt != NULL. Provide
in_rtcache() for adding a route to the chain. Provide in_rtflush()
and in_rtflushall() for invalidating IPv4 route caches. In
in_rtflush(), set ro_rt to NULL, and remove the route from the
chain. In in_rtflushall(), walk the chain and remove every route
cache.
In rtrequest1(), call rtflushall() to invalidate route caches when
a route is added.
In gif(4), discard the workaround for stale caches that involves
expiring them every so often.
Replace the pattern 'RTFREE(ro->ro_rt); ro->ro_rt = NULL;' with a
call to rtflush(ro).
Update ipflow_fastforward() and all other users of route caches so
that they expect a cached route, ro->ro_rt, to turn to NULL.
Take care when moving a 'struct route' to rtflush() the source and
to rtcache() the destination.
In domain initializers, use .dom_xxx tags.
KNF here and there.
2006-12-09 08:33:04 +03:00
|
|
|
void rtcache(struct route *);
|
|
|
|
void rtflushall(int);
|
1994-05-11 13:26:46 +04:00
|
|
|
struct rtentry *
|
2004-04-22 01:03:43 +04:00
|
|
|
rtalloc1(const struct sockaddr *, int);
|
|
|
|
void rtfree(struct rtentry *);
|
|
|
|
int rt_getifa(struct rt_addrinfo *);
|
|
|
|
int rtinit(struct ifaddr *, int, int);
|
2007-03-04 08:59:00 +03:00
|
|
|
int rtioctl(u_long, void *, struct lwp *);
|
2004-04-22 01:03:43 +04:00
|
|
|
void rtredirect(const struct sockaddr *, const struct sockaddr *,
|
2004-04-21 08:17:28 +04:00
|
|
|
const struct sockaddr *, int, const struct sockaddr *,
|
2004-04-22 01:03:43 +04:00
|
|
|
struct rtentry **);
|
|
|
|
int rtrequest(int, const struct sockaddr *,
|
2004-04-21 08:17:28 +04:00
|
|
|
const struct sockaddr *, const struct sockaddr *, int,
|
2004-04-22 01:03:43 +04:00
|
|
|
struct rtentry **);
|
|
|
|
int rtrequest1(int, struct rt_addrinfo *, struct rtentry **);
|
2006-11-13 08:13:38 +03:00
|
|
|
|
2006-12-16 00:18:52 +03:00
|
|
|
struct ifaddr *rt_get_ifa(struct rtentry *);
|
|
|
|
void rt_replace_ifa(struct rtentry *, struct ifaddr *);
|
|
|
|
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
static inline void
|
|
|
|
rt_destroy(struct rtentry *rt)
|
|
|
|
{
|
|
|
|
if (rt->_rt_key != NULL)
|
|
|
|
sockaddr_free(rt->_rt_key);
|
|
|
|
if (rt->rt_gateway != NULL)
|
|
|
|
sockaddr_free(rt->rt_gateway);
|
|
|
|
rt->_rt_key = rt->rt_gateway = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline const struct sockaddr *
|
|
|
|
rt_setkey(struct rtentry *rt, const struct sockaddr *key, int flags)
|
|
|
|
{
|
|
|
|
if (rt->_rt_key == key)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (rt->_rt_key != NULL)
|
|
|
|
sockaddr_free(rt->_rt_key);
|
|
|
|
rt->_rt_key = sockaddr_dup(key, flags);
|
|
|
|
out:
|
|
|
|
KASSERT(rt->_rt_key != NULL);
|
|
|
|
rt->rt_nodes->rn_key = (const char *)rt->_rt_key;
|
|
|
|
return rt->_rt_key;
|
|
|
|
}
|
|
|
|
|
2006-12-16 00:18:52 +03:00
|
|
|
struct rtentry *rtfindparent(struct radix_node_head *, struct route *);
|
|
|
|
|
2008-01-10 11:03:22 +03:00
|
|
|
struct rtentry *rtcache_init(struct route *);
|
|
|
|
struct rtentry *rtcache_init_noclone(struct route *);
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
void rtcache_copy(struct route *, const struct route *);
|
2008-01-21 12:11:24 +03:00
|
|
|
void rtcache_invalidate(struct dom_rtlist *);
|
2007-01-05 19:40:08 +03:00
|
|
|
|
2007-05-06 06:17:54 +04:00
|
|
|
struct rtentry *rtcache_lookup2(struct route *, const struct sockaddr *, int,
|
|
|
|
int *);
|
2007-04-22 17:05:21 +04:00
|
|
|
void rtcache_clear(struct route *);
|
2008-01-10 11:03:22 +03:00
|
|
|
struct rtentry *rtcache_update(struct route *, int);
|
2006-12-16 00:18:52 +03:00
|
|
|
void rtcache_free(struct route *);
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
int rtcache_setdst(struct route *, const struct sockaddr *);
|
2006-12-16 00:18:52 +03:00
|
|
|
|
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
|
|
|
static inline void
|
|
|
|
rtcache_invariants(const struct route *ro)
|
|
|
|
{
|
|
|
|
KASSERT(ro->ro_sa != NULL || ro->_ro_rt == NULL);
|
|
|
|
KASSERT(!ro->ro_invalid || ro->_ro_rt != NULL);
|
|
|
|
}
|
|
|
|
|
2007-05-06 06:17:54 +04:00
|
|
|
static inline struct rtentry *
|
|
|
|
rtcache_lookup1(struct route *ro, const struct sockaddr *dst, int clone)
|
|
|
|
{
|
|
|
|
int hit;
|
|
|
|
|
|
|
|
return rtcache_lookup2(ro, dst, clone, &hit);
|
|
|
|
}
|
|
|
|
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
static inline struct rtentry *
|
|
|
|
rtcache_lookup_noclone(struct route *ro, const struct sockaddr *dst)
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
{
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
return rtcache_lookup1(ro, dst, 0);
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
}
|
|
|
|
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
static inline struct rtentry *
|
|
|
|
rtcache_lookup(struct route *ro, const struct sockaddr *dst)
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
{
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
return rtcache_lookup1(ro, dst, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline const struct sockaddr *
|
|
|
|
rtcache_getdst(const struct route *ro)
|
|
|
|
{
|
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
|
|
|
rtcache_invariants(ro);
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
return ro->ro_sa;
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
}
|
|
|
|
|
2008-01-11 04:38:45 +03:00
|
|
|
/* If the cache is not empty, and the cached route is still present
|
|
|
|
* in the routing table, return the cached route. Otherwise, return
|
|
|
|
* NULL.
|
2007-05-06 06:17:54 +04:00
|
|
|
*/
|
2008-01-05 02:26:44 +03:00
|
|
|
static inline struct rtentry *
|
|
|
|
rtcache_validate(const struct route *ro)
|
2007-05-06 06:17:54 +04:00
|
|
|
{
|
2008-01-05 02:26:44 +03:00
|
|
|
struct rtentry *rt = ro->_ro_rt;
|
|
|
|
|
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
|
|
|
rtcache_invariants(ro);
|
|
|
|
|
2008-01-21 12:11:24 +03:00
|
|
|
if (ro->ro_invalid)
|
|
|
|
return NULL;
|
|
|
|
|
2008-01-05 02:26:44 +03:00
|
|
|
if (rt != NULL && (rt->rt_flags & RTF_UP) != 0 && rt->rt_ifp != NULL)
|
|
|
|
return rt;
|
|
|
|
return NULL;
|
|
|
|
|
2007-05-06 06:17:54 +04:00
|
|
|
}
|
|
|
|
|
Here are various changes designed to protect against bad IPv4
routing caused by stale route caches (struct route). Route caches
are sprinkled throughout PCBs, the IP fast-forwarding table, and
IP tunnel interfaces (gre, gif, stf).
Stale IPv6 and ISO route caches will be treated by separate patches.
Thank you to Christoph Badura for suggesting the general approach
to invalidating route caches that I take here.
Here are the details:
Add hooks to struct domain for tracking and for invalidating each
domain's route caches: dom_rtcache, dom_rtflush, and dom_rtflushall.
Introduce helper subroutines, rtflush(ro) for invalidating a route
cache, rtflushall(family) for invalidating all route caches in a
routing domain, and rtcache(ro) for notifying the domain of a new
cached route.
Chain together all IPv4 route caches where ro_rt != NULL. Provide
in_rtcache() for adding a route to the chain. Provide in_rtflush()
and in_rtflushall() for invalidating IPv4 route caches. In
in_rtflush(), set ro_rt to NULL, and remove the route from the
chain. In in_rtflushall(), walk the chain and remove every route
cache.
In rtrequest1(), call rtflushall() to invalidate route caches when
a route is added.
In gif(4), discard the workaround for stale caches that involves
expiring them every so often.
Replace the pattern 'RTFREE(ro->ro_rt); ro->ro_rt = NULL;' with a
call to rtflush(ro).
Update ipflow_fastforward() and all other users of route caches so
that they expect a cached route, ro->ro_rt, to turn to NULL.
Take care when moving a 'struct route' to rtflush() the source and
to rtcache() the destination.
In domain initializers, use .dom_xxx tags.
KNF here and there.
2006-12-09 08:33:04 +03:00
|
|
|
static inline void
|
|
|
|
RTFREE(struct rtentry *rt)
|
|
|
|
{
|
|
|
|
if (rt->rt_refcnt <= 1)
|
|
|
|
rtfree(rt);
|
|
|
|
else
|
|
|
|
rt->rt_refcnt--;
|
|
|
|
}
|
|
|
|
|
2007-06-09 07:07:21 +04:00
|
|
|
int
|
|
|
|
rt_walktree(sa_family_t, int (*)(struct rtentry *, void *), void *);
|
|
|
|
|
1995-03-27 00:23:52 +04:00
|
|
|
#endif /* _KERNEL */
|
2005-12-11 02:21:38 +03:00
|
|
|
#endif /* !_NET_ROUTE_H_ */
|