Changeset View
Changeset View
Standalone View
Standalone View
sys/net/route/route_ctl.c
Show First 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | |||||
#include <net/route/nhop_var.h> | #include <net/route/nhop_var.h> | ||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#include <netinet6/scope6_var.h> | #include <netinet6/scope6_var.h> | ||||
#include <netinet6/in6_var.h> | #include <netinet6/in6_var.h> | ||||
#define DEBUG_MOD_NAME route_ctl | #define DEBUG_MOD_NAME route_ctl | ||||
#define DEBUG_MAX_LEVEL LOG_DEBUG | #define DEBUG_MAX_LEVEL LOG_DEBUG | ||||
#include <net/route/route_debug.h> | #include <net/route/route_debug.h> | ||||
_DECLARE_DEBUG(LOG_INFO); | _DECLARE_DEBUG(LOG_DEBUG); | ||||
/* | /* | ||||
* This file contains control plane routing tables functions. | * This file contains control plane routing tables functions. | ||||
* | * | ||||
* All functions assumes they are called in net epoch. | * All functions assumes they are called in net epoch. | ||||
*/ | */ | ||||
union sockaddr_union { | union sockaddr_union { | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | uint8_t mpath_entropy_key[MPATH_ENTROPY_KEY_LEN] = { | ||||
0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, | 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, | ||||
0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa, | 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa, | ||||
}; | }; | ||||
#endif | #endif | ||||
#if defined(INET) && defined(INET6) | #if defined(INET) && defined(INET6) | ||||
FEATURE(ipv4_rfc5549_support, "Route IPv4 packets via IPv6 nexthops"); | FEATURE(ipv4_rfc5549_support, "Route IPv4 packets via IPv6 nexthops"); | ||||
#define V_rib_route_ipv6_nexthop VNET(rib_route_ipv6_nexthop) | #define V_rib_route_ipv6_nexthop VNET(rib_route_ipv6_nexthop) | ||||
VNET_DEFINE(u_int, rib_route_ipv6_nexthop) = 1; | VNET_DEFINE_STATIC(u_int, rib_route_ipv6_nexthop) = 1; | ||||
SYSCTL_UINT(_net_route, OID_AUTO, ipv6_nexthop, CTLFLAG_RW | CTLFLAG_VNET, | SYSCTL_UINT(_net_route, OID_AUTO, ipv6_nexthop, CTLFLAG_RW | CTLFLAG_VNET, | ||||
&VNET_NAME(rib_route_ipv6_nexthop), 0, "Enable IPv4 route via IPv6 Next Hop address"); | &VNET_NAME(rib_route_ipv6_nexthop), 0, "Enable IPv4 route via IPv6 Next Hop address"); | ||||
#endif | #endif | ||||
/* Debug bits */ | /* Debug bits */ | ||||
SYSCTL_NODE(_net_route, OID_AUTO, debug, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); | SYSCTL_NODE(_net_route, OID_AUTO, debug, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); | ||||
static struct rib_head * | static struct rib_head * | ||||
get_rnh(uint32_t fibnum, const struct rt_addrinfo *info) | get_rnh(uint32_t fibnum, const struct rt_addrinfo *info) | ||||
{ | { | ||||
struct rib_head *rnh; | struct rib_head *rnh; | ||||
struct sockaddr *dst; | struct sockaddr *dst; | ||||
KASSERT((fibnum < rt_numfibs), ("rib_add_route: bad fibnum")); | KASSERT((fibnum < rt_numfibs), ("rib_add_route: bad fibnum")); | ||||
dst = info->rti_info[RTAX_DST]; | dst = info->rti_info[RTAX_DST]; | ||||
rnh = rt_tables_get_rnh(fibnum, dst->sa_family); | rnh = rt_tables_get_rnh(fibnum, dst->sa_family); | ||||
return (rnh); | return (rnh); | ||||
} | } | ||||
#if defined(INET) && defined(INET6) | #if defined(INET) && defined(INET6) | ||||
static bool | bool | ||||
rib_can_ipv6_nexthop_address(struct rib_head *rh) | rib_can_4o6_nhop(void) | ||||
{ | { | ||||
int result; | return (!!V_rib_route_ipv6_nexthop); | ||||
CURVNET_SET(rh->rib_vnet); | |||||
result = !!V_rib_route_ipv6_nexthop; | |||||
CURVNET_RESTORE(); | |||||
return (result); | |||||
} | } | ||||
#endif | #endif | ||||
#ifdef ROUTE_MPATH | #ifdef ROUTE_MPATH | ||||
static bool | static bool | ||||
rib_can_multipath(struct rib_head *rh) | rib_can_multipath(struct rib_head *rh) | ||||
{ | { | ||||
int result; | int result; | ||||
▲ Show 20 Lines • Show All 533 Lines • ▼ Show 20 Lines | rib_add_route(uint32_t fibnum, struct rt_addrinfo *info, | ||||
error = add_route_byinfo(rnh, info, rc); | error = add_route_byinfo(rnh, info, rc); | ||||
if (error == 0) | if (error == 0) | ||||
rib_notify(rnh, RIB_NOTIFY_DELAYED, rc); | rib_notify(rnh, RIB_NOTIFY_DELAYED, rc); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | |||||
* Checks if @dst and @gateway is valid combination. | |||||
* | |||||
* Returns true if is valid, false otherwise. | |||||
*/ | |||||
static bool | |||||
check_gateway(struct rib_head *rnh, struct sockaddr *dst, | |||||
struct sockaddr *gateway) | |||||
{ | |||||
if (dst->sa_family == gateway->sa_family) | |||||
return (true); | |||||
else if (gateway->sa_family == AF_UNSPEC) | |||||
return (true); | |||||
else if (gateway->sa_family == AF_LINK) | |||||
return (true); | |||||
#if defined(INET) && defined(INET6) | |||||
else if (dst->sa_family == AF_INET && gateway->sa_family == AF_INET6 && | |||||
rib_can_ipv6_nexthop_address(rnh)) | |||||
return (true); | |||||
#endif | |||||
else | |||||
return (false); | |||||
} | |||||
static int | static int | ||||
add_route_byinfo(struct rib_head *rnh, struct rt_addrinfo *info, | add_route_byinfo(struct rib_head *rnh, struct rt_addrinfo *info, | ||||
struct rib_cmd_info *rc) | struct rib_cmd_info *rc) | ||||
{ | { | ||||
struct route_nhop_data rnd_add; | struct route_nhop_data rnd_add; | ||||
struct nhop_object *nh; | struct nhop_object *nh; | ||||
struct rtentry *rt; | struct rtentry *rt; | ||||
struct sockaddr *dst, *gateway, *netmask; | struct sockaddr *dst, *gateway, *netmask; | ||||
int error; | int error; | ||||
dst = info->rti_info[RTAX_DST]; | dst = info->rti_info[RTAX_DST]; | ||||
gateway = info->rti_info[RTAX_GATEWAY]; | gateway = info->rti_info[RTAX_GATEWAY]; | ||||
netmask = info->rti_info[RTAX_NETMASK]; | netmask = info->rti_info[RTAX_NETMASK]; | ||||
if ((info->rti_flags & RTF_GATEWAY) && !gateway) { | if ((info->rti_flags & RTF_GATEWAY) && !gateway) { | ||||
FIB_RH_LOG(LOG_DEBUG, rnh, "error: RTF_GATEWAY set with empty gw"); | FIB_RH_LOG(LOG_DEBUG, rnh, "error: RTF_GATEWAY set with empty gw"); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
if (dst && gateway && !check_gateway(rnh, dst, gateway)) { | if (dst && gateway && !nhop_check_gateway(dst->sa_family, gateway->sa_family)) { | ||||
FIB_RH_LOG(LOG_DEBUG, rnh, | FIB_RH_LOG(LOG_DEBUG, rnh, | ||||
"error: invalid dst/gateway family combination (%d, %d)", | "error: invalid dst/gateway family combination (%d, %d)", | ||||
dst->sa_family, gateway->sa_family); | dst->sa_family, gateway->sa_family); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
if (dst->sa_len > sizeof(((struct rtentry *)NULL)->rt_dstb)) { | if (dst->sa_len > sizeof(((struct rtentry *)NULL)->rt_dstb)) { | ||||
FIB_RH_LOG(LOG_DEBUG, rnh, "error: dst->sa_len too large: %d", | FIB_RH_LOG(LOG_DEBUG, rnh, "error: dst->sa_len too large: %d", | ||||
▲ Show 20 Lines • Show All 406 Lines • ▼ Show 20 Lines | if (wn_new == NULL) { | ||||
nhop_free(nh_new); | nhop_free(nh_new); | ||||
return (EAGAIN); | return (EAGAIN); | ||||
} | } | ||||
memcpy(wn_new, wn, num_nhops * sizeof(struct weightened_nhop)); | memcpy(wn_new, wn, num_nhops * sizeof(struct weightened_nhop)); | ||||
wn_new[found_idx].nh = nh_new; | wn_new[found_idx].nh = nh_new; | ||||
wn_new[found_idx].weight = get_info_weight(info, wn[found_idx].weight); | wn_new[found_idx].weight = get_info_weight(info, wn[found_idx].weight); | ||||
error = nhgrp_get_group(rnh, wn_new, num_nhops, &rnd_new.rnd_nhgrp); | error = nhgrp_get_group(rnh, wn_new, num_nhops, 0, &rnd_new.rnd_nhgrp); | ||||
nhop_free(nh_new); | nhop_free(nh_new); | ||||
free(wn_new, M_TEMP); | free(wn_new, M_TEMP); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
error = change_route_conditional(rnh, rt, rnd_orig, &rnd_new, rc); | error = change_route_conditional(rnh, rt, rnd_orig, &rnd_new, rc); | ||||
▲ Show 20 Lines • Show All 394 Lines • ▼ Show 20 Lines | case AF_INET: | ||||
return ("inet"); | return ("inet"); | ||||
case AF_INET6: | case AF_INET6: | ||||
return ("inet6"); | return ("inet6"); | ||||
case AF_LINK: | case AF_LINK: | ||||
return ("link"); | return ("link"); | ||||
} | } | ||||
return ("unknown"); | return ("unknown"); | ||||
} | } | ||||
CK_STAILQ_HEAD(rib_event_bridge_head, rib_event_bridge); | |||||
static struct rib_event_bridge_head bridge_head; | |||||
glebius: Why not static? | |||||
struct mtx bridge_lock; | |||||
static void | |||||
rib_bridge_init(void) | |||||
{ | |||||
CK_STAILQ_INIT(&bridge_head); | |||||
mtx_init(&bridge_lock, "rib_event_bridge_lock", NULL, MTX_DEF); | |||||
} | |||||
Done Inline ActionsBoth tailq head and mutex can be initialized with standard initializer macros. glebius: Both tailq head and mutex can be initialized with standard initializer macros. | |||||
SYSINIT(rib_bridge_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_SECOND, rib_bridge_init, NULL); | |||||
void | |||||
rib_bridge_generic_event(int provider_id, uint32_t event_type, uint32_t val1, | |||||
void *ptr1, void *ptr2) | |||||
{ | |||||
struct rib_event_bridge *reb; | |||||
NET_EPOCH_ASSERT(); | |||||
CK_STAILQ_FOREACH(reb, &bridge_head, reb_link) { | |||||
RT_LOG(LOG_DEBUG3, "HERE reb %p %d", reb, reb->reb_provider_id); | |||||
if (reb->reb_provider_id != provider_id) | |||||
reb->reb_cb(event_type, val1, ptr1, ptr2, reb->reb_cb_arg); | |||||
} | |||||
} | |||||
void | |||||
rib_bridge_rt_event(int provider_id, uint32_t fibnum, struct rt_addrinfo *info, | |||||
struct rib_cmd_info *rc) | |||||
{ | |||||
#if DEBUG_MAX_LEVEL >= LOG_DEBUG2 | |||||
char rtbuf[INET6_ADDRSTRLEN + 5]; | |||||
FIB_LOG(LOG_DEBUG3, fibnum, rt_get_family(rc->rc_rt), "received cmd %s for %s", | |||||
rib_print_cmd(rc->rc_cmd), rt_print_buf(rc->rc_rt, rtbuf, sizeof(rtbuf))); | |||||
#endif | |||||
rib_bridge_generic_event(provider_id, NLBR_EVENT_ROUTE, fibnum, info, rc); | |||||
} | |||||
void | |||||
rib_bridge_link(struct rib_event_bridge *reb) | |||||
{ | |||||
mtx_lock(&bridge_lock); | |||||
CK_STAILQ_INSERT_HEAD(&bridge_head, reb, reb_link); | |||||
mtx_unlock(&bridge_lock); | |||||
RT_LOG(LOG_DEBUG, "link %p", reb); | |||||
} | |||||
void | |||||
rib_bridge_unlink(struct rib_event_bridge *reb) | |||||
{ | |||||
mtx_lock(&bridge_lock); | |||||
CK_STAILQ_REMOVE(&bridge_head, reb, rib_event_bridge, reb_link); | |||||
mtx_unlock(&bridge_lock); | |||||
RT_LOG(LOG_DEBUG, "unlink %p", reb); | |||||
} | |||||
Why not static?