Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/in.c
Show First 20 Lines • Show All 815 Lines • ▼ Show 20 Lines | in_match_ifaddr(const struct rtentry *rt, const struct nhop_object *nh, void *arg) | ||||
if (nh->nh_ifa == (struct ifaddr *)arg) | if (nh->nh_ifa == (struct ifaddr *)arg) | ||||
return (1); | return (1); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
in_handle_prefix_route(uint32_t fibnum, int cmd, | in_handle_prefix_route(uint32_t fibnum, int cmd, struct sockaddr *dst, | ||||
struct sockaddr_in *dst, struct sockaddr_in *netmask, struct ifaddr *ifa, | int plen, struct ifaddr *ifa, struct ifnet *ifp) | ||||
struct ifnet *ifp) | |||||
{ | { | ||||
int error = 0; | |||||
NET_EPOCH_ASSERT(); | NET_EPOCH_ASSERT(); | ||||
/* Prepare gateway */ | if (cmd == RTM_DELETE) { | ||||
struct sockaddr_dl_short sdl = { | error = rib_del_kernel_px(fibnum, dst, plen, in_match_ifaddr, ifa, | ||||
.sdl_family = AF_LINK, | RTM_F_FORCE); | ||||
.sdl_len = sizeof(struct sockaddr_dl_short), | } else { | ||||
.sdl_type = ifa->ifa_ifp->if_type, | struct nhop_object *nh = nhop_alloc(fibnum, dst->sa_family); | ||||
.sdl_index = ifa->ifa_ifp->if_index, | struct route_nhop_data rnd = { .rnd_weight = RT_DEFAULT_WEIGHT }; | ||||
}; | |||||
struct rt_addrinfo info = { | if (nh == NULL) | ||||
.rti_ifa = ifa, | return (ENOMEM); | ||||
.rti_ifp = ifp, | nhop_set_direct_gw(nh, ifa->ifa_ifp); | ||||
.rti_flags = RTF_PINNED | ((netmask != NULL) ? 0 : RTF_HOST), | nhop_set_transmit_ifp(nh, ifp); | ||||
.rti_info = { | nhop_set_src(nh, ifa); | ||||
[RTAX_DST] = (struct sockaddr *)dst, | nhop_set_pinned(nh, true); | ||||
[RTAX_NETMASK] = (struct sockaddr *)netmask, | nhop_set_pxtype_flag(nh, plen == 32 ? NHF_HOST : 0); | ||||
[RTAX_GATEWAY] = (struct sockaddr *)&sdl, | rnd.rnd_nhop = nhop_get_nhop(nh, &error); | ||||
}, | if (error != 0) | ||||
/* Ensure we delete the prefix IFF prefix ifa matches */ | return (error); | ||||
.rti_filter = in_match_ifaddr, | int op_flags = RTM_F_CREATE | RTM_F_REPLACE | RTM_F_FORCE; | ||||
.rti_filterdata = ifa, | error = rib_add_kernel_px(fibnum, dst, plen, &rnd, op_flags); | ||||
}; | |||||
return (rib_handle_ifaddr_info(fibnum, cmd, &info)); | |||||
} | } | ||||
return (error); | |||||
} | |||||
/* | /* | ||||
* Routing table interaction with interface addresses. | * Routing table interaction with interface addresses. | ||||
* | * | ||||
* In general, two types of routes needs to be installed: | * In general, two types of routes needs to be installed: | ||||
* a) "interface" or "prefix" route, telling user that the addresses | * a) "interface" or "prefix" route, telling user that the addresses | ||||
* behind the ifa prefix are reached directly. | * behind the ifa prefix are reached directly. | ||||
* b) "loopback" route installed for the ifa address, telling user that | * b) "loopback" route installed for the ifa address, telling user that | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | |||||
* Adds or delete interface "prefix" route corresponding to @ifa. | * Adds or delete interface "prefix" route corresponding to @ifa. | ||||
* Returns 0 on success or errno. | * Returns 0 on success or errno. | ||||
*/ | */ | ||||
static int | static int | ||||
in_handle_ifaddr_route(int cmd, struct in_ifaddr *ia) | in_handle_ifaddr_route(int cmd, struct in_ifaddr *ia) | ||||
{ | { | ||||
struct ifaddr *ifa = &ia->ia_ifa; | struct ifaddr *ifa = &ia->ia_ifa; | ||||
struct in_addr daddr, maddr; | struct in_addr daddr, maddr; | ||||
struct sockaddr_in *pmask; | |||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
int error; | int error; | ||||
ia_getrtprefix(ia, &daddr, &maddr); | ia_getrtprefix(ia, &daddr, &maddr); | ||||
struct sockaddr_in mask = { | int plen = bitcount32(maddr.s_addr); | ||||
.sin_family = AF_INET, | |||||
.sin_len = sizeof(struct sockaddr_in), | |||||
.sin_addr = maddr, | |||||
}; | |||||
pmask = (maddr.s_addr != INADDR_BROADCAST) ? &mask : NULL; | |||||
struct sockaddr_in dst = { | struct sockaddr_in dst = { | ||||
.sin_family = AF_INET, | .sin_family = AF_INET, | ||||
.sin_len = sizeof(struct sockaddr_in), | .sin_len = sizeof(struct sockaddr_in), | ||||
.sin_addr.s_addr = daddr.s_addr & maddr.s_addr, | .sin_addr.s_addr = daddr.s_addr & maddr.s_addr, | ||||
}; | }; | ||||
struct ifnet *ifp = ia->ia_ifp; | struct ifnet *ifp = ia->ia_ifp; | ||||
if ((maddr.s_addr == INADDR_BROADCAST) && | if ((maddr.s_addr == INADDR_BROADCAST) && | ||||
(!(ia->ia_ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)))) { | (!(ia->ia_ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)))) { | ||||
/* Case 2: host route on broadcast interface */ | /* Case 2: host route on broadcast interface */ | ||||
ifp = V_loif; | ifp = V_loif; | ||||
} | } | ||||
uint32_t fibnum = ifa->ifa_ifp->if_fib; | uint32_t fibnum = ifa->ifa_ifp->if_fib; | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
error = in_handle_prefix_route(fibnum, cmd, &dst, pmask, ifa, ifp); | error = in_handle_prefix_route(fibnum, cmd, (struct sockaddr *)&dst, | ||||
plen, ifa, ifp); | |||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Check if we have a route for the given prefix already. | * Check if we have a route for the given prefix already. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 852 Lines • Show Last 20 Lines |