Split rt_newaddrmsg_fib() into two different functions.
Adding/deleting interface addresses involves access to 3 different subsystems, int different parts of code. Each call can fail, so reporting successful operation by rtsock in the middle of the process error-prone. Further split routing notification API and actual rtsock calls via creating public-available rt_addrmsg() / rt_routemsg() functions with "private" rtsock_* backend. MFC after: 2 weeks
This commit is contained in:
parent
977929e179
commit
4cbac30b29
108
sys/net/route.c
108
sys/net/route.c
@ -37,6 +37,7 @@
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
#include "opt_route.h"
|
||||
#include "opt_sctp.h"
|
||||
#include "opt_mrouting.h"
|
||||
#include "opt_mpath.h"
|
||||
|
||||
@ -52,6 +53,7 @@
|
||||
#include <sys/proc.h>
|
||||
#include <sys/domain.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/kdb.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_var.h>
|
||||
@ -86,6 +88,13 @@
|
||||
#define RT_NUMFIBS 1
|
||||
#endif
|
||||
|
||||
#if defined(INET) || defined(INET6)
|
||||
#ifdef SCTP
|
||||
extern void sctp_addr_change(struct ifaddr *ifa, int cmd);
|
||||
#endif /* SCTP */
|
||||
#endif
|
||||
|
||||
|
||||
/* This is read-only.. */
|
||||
u_int rt_numfibs = RT_NUMFIBS;
|
||||
SYSCTL_UINT(_net, OID_AUTO, fibs, CTLFLAG_RD, &rt_numfibs, 0, "");
|
||||
@ -118,7 +127,8 @@ VNET_DEFINE(int, rttrash); /* routes not in table but not freed */
|
||||
|
||||
|
||||
/* compare two sockaddr structures */
|
||||
#define sa_equal(a1, a2) (bcmp((a1), (a2), (a1)->sa_len) == 0)
|
||||
#define sa_equal(a1, a2) (((a1)->sa_len == (a2)->sa_len) && \
|
||||
(bcmp((a1), (a2), (a1)->sa_len) == 0))
|
||||
|
||||
/*
|
||||
* Convert a 'struct radix_node *' to a 'struct rtentry *'.
|
||||
@ -1731,3 +1741,99 @@ rtinit(struct ifaddr *ifa, int cmd, int flags)
|
||||
}
|
||||
return (rtinit1(ifa, cmd, flags, fib));
|
||||
}
|
||||
|
||||
/*
|
||||
* Announce interface address arrival/withdraw
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
int
|
||||
rt_addrmsg(int cmd, struct ifaddr *ifa, int fibnum)
|
||||
{
|
||||
|
||||
KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE,
|
||||
("unexpected cmd %u", cmd));
|
||||
|
||||
if (fibnum != RT_ALL_FIBS) {
|
||||
KASSERT(fibnum >= 0 && fibnum < rt_numfibs, ("%s: "
|
||||
"fibnum out of range 0 <= %d < %d", __func__,
|
||||
fibnum, rt_numfibs));
|
||||
}
|
||||
|
||||
return (rtsock_addrmsg(cmd, ifa, fibnum));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Announce route addition/removal
|
||||
* Users of this function MUST validate input data BEFORE calling.
|
||||
* However we have to be able to handle invalid data:
|
||||
* if some userland app sends us "invalid" route message (invalid mask,
|
||||
* no dst, wrokg address families, etc...) we need to pass it back
|
||||
* to app (and any other rtsock consumers) with rtm_errno field set to
|
||||
* non-zero value.
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
int
|
||||
rt_routemsg(int cmd, struct ifnet *ifp, int error, struct rtentry *rt,
|
||||
int fibnum)
|
||||
{
|
||||
|
||||
KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE,
|
||||
("unexpected cmd %u", cmd));
|
||||
|
||||
if (fibnum != RT_ALL_FIBS) {
|
||||
KASSERT(fibnum >= 0 && fibnum < rt_numfibs, ("%s: "
|
||||
"fibnum out of range 0 <= %d < %d", __func__,
|
||||
fibnum, rt_numfibs));
|
||||
}
|
||||
|
||||
KASSERT(rt_key(rt) != NULL, (":%s: rt_key must be supplied", __func__));
|
||||
|
||||
return (rtsock_routemsg(cmd, ifp, error, rt, fibnum));
|
||||
}
|
||||
|
||||
void
|
||||
rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt)
|
||||
{
|
||||
|
||||
rt_newaddrmsg_fib(cmd, ifa, error, rt, RT_ALL_FIBS);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called to generate messages from the routing socket
|
||||
* indicating a network interface has had addresses associated with it.
|
||||
*/
|
||||
void
|
||||
rt_newaddrmsg_fib(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt,
|
||||
int fibnum)
|
||||
{
|
||||
|
||||
KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE,
|
||||
("unexpected cmd %u", cmd));
|
||||
if (fibnum != RT_ALL_FIBS) {
|
||||
KASSERT(fibnum >= 0 && fibnum < rt_numfibs, ("%s: "
|
||||
"fibnum out of range 0 <= %d < %d", __func__,
|
||||
fibnum, rt_numfibs));
|
||||
}
|
||||
|
||||
#if defined(INET) || defined(INET6)
|
||||
#ifdef SCTP
|
||||
/*
|
||||
* notify the SCTP stack
|
||||
* this will only get called when an address is added/deleted
|
||||
* XXX pass the ifaddr struct instead if ifa->ifa_addr...
|
||||
*/
|
||||
sctp_addr_change(ifa, cmd);
|
||||
#endif /* SCTP */
|
||||
#endif
|
||||
if (cmd == RTM_ADD) {
|
||||
rt_addrmsg(cmd, ifa, fibnum);
|
||||
if (rt != NULL)
|
||||
rt_routemsg(cmd, ifa->ifa_ifp, error, rt, fibnum);
|
||||
} else {
|
||||
if (rt != NULL)
|
||||
rt_routemsg(cmd, ifa->ifa_ifp, error, rt, fibnum);
|
||||
rt_addrmsg(cmd, ifa, fibnum);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -369,10 +369,15 @@ void rt_missmsg(int, struct rt_addrinfo *, int, int);
|
||||
void rt_missmsg_fib(int, struct rt_addrinfo *, int, int, int);
|
||||
void rt_newaddrmsg(int, struct ifaddr *, int, struct rtentry *);
|
||||
void rt_newaddrmsg_fib(int, struct ifaddr *, int, struct rtentry *, int);
|
||||
int rt_addrmsg(int, struct ifaddr *, int);
|
||||
int rt_routemsg(int, struct ifnet *ifp, int, struct rtentry *, int);
|
||||
void rt_newmaddrmsg(int, struct ifmultiaddr *);
|
||||
int rt_setgate(struct rtentry *, struct sockaddr *, struct sockaddr *);
|
||||
void rt_maskedcopy(struct sockaddr *, struct sockaddr *, struct sockaddr *);
|
||||
|
||||
int rtsock_addrmsg(int, struct ifaddr *, int);
|
||||
int rtsock_routemsg(int, struct ifnet *ifp, int, struct rtentry *, int);
|
||||
|
||||
/*
|
||||
* Note the following locking behavior:
|
||||
*
|
||||
|
157
sys/net/rtsock.c
157
sys/net/rtsock.c
@ -30,7 +30,6 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include "opt_compat.h"
|
||||
#include "opt_sctp.h"
|
||||
#include "opt_mpath.h"
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
@ -70,12 +69,6 @@
|
||||
#include <netinet6/scope6_var.h>
|
||||
#endif
|
||||
|
||||
#if defined(INET) || defined(INET6)
|
||||
#ifdef SCTP
|
||||
extern void sctp_addr_change(struct ifaddr *ifa, int cmd);
|
||||
#endif /* SCTP */
|
||||
#endif
|
||||
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
#include <sys/mount.h>
|
||||
#include <compat/freebsd32/freebsd32.h>
|
||||
@ -1334,90 +1327,94 @@ rt_ifmsg(struct ifnet *ifp)
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called to generate messages from the routing socket
|
||||
* indicating a network interface has had addresses associated with it.
|
||||
* if we ever reverse the logic and replace messages TO the routing
|
||||
* socket indicate a request to configure interfaces, then it will
|
||||
* be unnecessary as the routing socket will automatically generate
|
||||
* copies of it.
|
||||
* Announce interface address arrival/withdraw.
|
||||
* Please do not call directly, use rt_addrmsg().
|
||||
* Assume input data to be valid.
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
void
|
||||
rt_newaddrmsg_fib(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt,
|
||||
int
|
||||
rtsock_addrmsg(int cmd, struct ifaddr *ifa, int fibnum)
|
||||
{
|
||||
struct rt_addrinfo info;
|
||||
struct sockaddr *sa;
|
||||
int ncmd;
|
||||
struct mbuf *m;
|
||||
struct ifa_msghdr *ifam;
|
||||
struct ifnet *ifp = ifa->ifa_ifp;
|
||||
|
||||
if (route_cb.any_count == 0)
|
||||
return (0);
|
||||
|
||||
ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR;
|
||||
|
||||
bzero((caddr_t)&info, sizeof(info));
|
||||
info.rti_info[RTAX_IFA] = sa = ifa->ifa_addr;
|
||||
info.rti_info[RTAX_IFP] = ifp->if_addr->ifa_addr;
|
||||
info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
|
||||
info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr;
|
||||
if ((m = rt_msg1(ncmd, &info)) == NULL)
|
||||
return (ENOBUFS);
|
||||
ifam = mtod(m, struct ifa_msghdr *);
|
||||
ifam->ifam_index = ifp->if_index;
|
||||
ifam->ifam_metric = ifa->ifa_metric;
|
||||
ifam->ifam_flags = ifa->ifa_flags;
|
||||
ifam->ifam_addrs = info.rti_addrs;
|
||||
|
||||
if (fibnum != RT_ALL_FIBS) {
|
||||
M_SETFIB(m, fibnum);
|
||||
m->m_flags |= RTS_FILTER_FIB;
|
||||
}
|
||||
|
||||
rt_dispatch(m, sa ? sa->sa_family : AF_UNSPEC);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Announce route addition/removal.
|
||||
* Please do not call directly, use rt_routemsg().
|
||||
* Note that @rt data MAY be inconsistent/invalid:
|
||||
* if some userland app sends us "invalid" route message (invalid mask,
|
||||
* no dst, wrong address families, etc...) we need to pass it back
|
||||
* to app (and any other rtsock consumers) with rtm_errno field set to
|
||||
* non-zero value.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
int
|
||||
rtsock_routemsg(int cmd, struct ifnet *ifp, int error, struct rtentry *rt,
|
||||
int fibnum)
|
||||
{
|
||||
struct rt_addrinfo info;
|
||||
struct sockaddr *sa = NULL;
|
||||
int pass;
|
||||
struct mbuf *m = NULL;
|
||||
struct ifnet *ifp = ifa->ifa_ifp;
|
||||
struct sockaddr *sa;
|
||||
struct mbuf *m;
|
||||
struct rt_msghdr *rtm;
|
||||
|
||||
KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE,
|
||||
("unexpected cmd %u", cmd));
|
||||
#if defined(INET) || defined(INET6)
|
||||
#ifdef SCTP
|
||||
/*
|
||||
* notify the SCTP stack
|
||||
* this will only get called when an address is added/deleted
|
||||
* XXX pass the ifaddr struct instead if ifa->ifa_addr...
|
||||
*/
|
||||
sctp_addr_change(ifa, cmd);
|
||||
#endif /* SCTP */
|
||||
#endif
|
||||
if (route_cb.any_count == 0)
|
||||
return;
|
||||
for (pass = 1; pass < 3; pass++) {
|
||||
bzero((caddr_t)&info, sizeof(info));
|
||||
if ((cmd == RTM_ADD && pass == 1) ||
|
||||
(cmd == RTM_DELETE && pass == 2)) {
|
||||
struct ifa_msghdr *ifam;
|
||||
int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR;
|
||||
return (0);
|
||||
|
||||
info.rti_info[RTAX_IFA] = sa = ifa->ifa_addr;
|
||||
info.rti_info[RTAX_IFP] = ifp->if_addr->ifa_addr;
|
||||
info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
|
||||
info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr;
|
||||
if ((m = rt_msg1(ncmd, &info)) == NULL)
|
||||
continue;
|
||||
ifam = mtod(m, struct ifa_msghdr *);
|
||||
ifam->ifam_index = ifp->if_index;
|
||||
ifam->ifam_metric = ifa->ifa_metric;
|
||||
ifam->ifam_flags = ifa->ifa_flags;
|
||||
ifam->ifam_addrs = info.rti_addrs;
|
||||
}
|
||||
if ((cmd == RTM_ADD && pass == 2) ||
|
||||
(cmd == RTM_DELETE && pass == 1)) {
|
||||
struct rt_msghdr *rtm;
|
||||
bzero((caddr_t)&info, sizeof(info));
|
||||
info.rti_info[RTAX_NETMASK] = rt_mask(rt);
|
||||
info.rti_info[RTAX_DST] = sa = rt_key(rt);
|
||||
info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
|
||||
if ((m = rt_msg1(cmd, &info)) == NULL)
|
||||
return (ENOBUFS);
|
||||
rtm = mtod(m, struct rt_msghdr *);
|
||||
rtm->rtm_index = ifp->if_index;
|
||||
rtm->rtm_flags |= rt->rt_flags;
|
||||
rtm->rtm_errno = error;
|
||||
rtm->rtm_addrs = info.rti_addrs;
|
||||
|
||||
if (rt == NULL)
|
||||
continue;
|
||||
info.rti_info[RTAX_NETMASK] = rt_mask(rt);
|
||||
info.rti_info[RTAX_DST] = sa = rt_key(rt);
|
||||
info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
|
||||
if ((m = rt_msg1(cmd, &info)) == NULL)
|
||||
continue;
|
||||
rtm = mtod(m, struct rt_msghdr *);
|
||||
rtm->rtm_index = ifp->if_index;
|
||||
rtm->rtm_flags |= rt->rt_flags;
|
||||
rtm->rtm_errno = error;
|
||||
rtm->rtm_addrs = info.rti_addrs;
|
||||
}
|
||||
if (fibnum != RT_ALL_FIBS) {
|
||||
KASSERT(fibnum >= 0 && fibnum < rt_numfibs, ("%s: "
|
||||
"fibnum out of range 0 <= %d < %d", __func__,
|
||||
fibnum, rt_numfibs));
|
||||
M_SETFIB(m, fibnum);
|
||||
m->m_flags |= RTS_FILTER_FIB;
|
||||
}
|
||||
rt_dispatch(m, sa ? sa->sa_family : AF_UNSPEC);
|
||||
if (fibnum != RT_ALL_FIBS) {
|
||||
M_SETFIB(m, fibnum);
|
||||
m->m_flags |= RTS_FILTER_FIB;
|
||||
}
|
||||
|
||||
rt_dispatch(m, sa ? sa->sa_family : AF_UNSPEC);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt)
|
||||
{
|
||||
|
||||
rt_newaddrmsg_fib(cmd, ifa, error, rt, RT_ALL_FIBS);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the analogue to the rt_newaddrmsg which performs the same
|
||||
|
Loading…
x
Reference in New Issue
Block a user