Use hash table for session tracking
This commit is contained in:
parent
5ba34bdfae
commit
eb18db8184
24
src/addr.c
24
src/addr.c
@ -116,14 +116,24 @@ void nd_addr_combine(const nd_addr_t *first, const nd_addr_t *second, unsigned p
|
||||
}
|
||||
}
|
||||
|
||||
static int ndL_count_bits(uint32_t n)
|
||||
uint32_t nd_addr_hash(const nd_addr_t *addr)
|
||||
{
|
||||
n = (n & 0x55555555) + ((n >> 1) & 0x55555555);
|
||||
n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
|
||||
n = (n & 0x0f0f0f0f) + ((n >> 4) & 0x0f0f0f0f);
|
||||
n = (n & 0x00ff00ff) + ((n >> 8) & 0x00ff00ff);
|
||||
n = (n & 0x0000ffff) + ((n >> 16) & 0x0000ffff);
|
||||
return n;
|
||||
uint32_t hash = 7;
|
||||
hash = 31 * hash + addr->u32[0];
|
||||
hash = 31 * hash + addr->u32[1];
|
||||
hash = 31 * hash + addr->u32[2];
|
||||
hash = 31 * hash + addr->u32[3];
|
||||
return hash;
|
||||
}
|
||||
|
||||
static int ndL_count_bits(uint32_t value)
|
||||
{
|
||||
value = (value & 0x55555555) + ((value >> 1) & 0x55555555);
|
||||
value = (value & 0x33333333) + ((value >> 2) & 0x33333333);
|
||||
value = (value & 0x0f0f0f0f) + ((value >> 4) & 0x0f0f0f0f);
|
||||
value = (value & 0x00ff00ff) + ((value >> 8) & 0x00ff00ff);
|
||||
value = (value & 0x0000ffff) + ((value >> 16) & 0x0000ffff);
|
||||
return value;
|
||||
}
|
||||
|
||||
int nd_mask_to_pflen(const nd_addr_t *netmask)
|
||||
|
11
src/iface.c
11
src/iface.c
@ -108,9 +108,9 @@ static void ndL_handle_na(nd_iface_t *iface, struct icmp6_hdr *ih, size_t len)
|
||||
|
||||
struct nd_neighbor_advert *na = (struct nd_neighbor_advert *)ih;
|
||||
|
||||
nd_session_t *session;
|
||||
ND_LL_SEARCH(iface->sessions, session, next_in_iface,
|
||||
nd_addr_eq(&session->real_tgt, (nd_addr_t *)&na->nd_na_target));
|
||||
nd_log_trace("Handle NA tgt=%s", nd_ntoa((nd_addr_t *)&na->nd_na_target));
|
||||
|
||||
nd_session_t *session = nd_session_find_r((nd_addr_t *)&na->nd_na_target, iface);
|
||||
|
||||
if (!session) {
|
||||
return;
|
||||
@ -517,8 +517,6 @@ nd_iface_t *nd_iface_open(const char *name, unsigned index)
|
||||
*iface = (nd_iface_t){
|
||||
.index = index,
|
||||
.refcount = 1,
|
||||
.old_allmulti = -1,
|
||||
.old_promisc = -1,
|
||||
.lladdr = *lladdr,
|
||||
};
|
||||
|
||||
@ -609,12 +607,13 @@ ssize_t nd_iface_send_na(nd_iface_t *iface, const nd_addr_t *dst, const nd_lladd
|
||||
.ip.ip6_dst = *(struct in6_addr *)dst,
|
||||
.na.nd_na_type = ND_NEIGHBOR_ADVERT,
|
||||
.na.nd_na_target = *(struct in6_addr *)tgt,
|
||||
.na.nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE,
|
||||
.opt.nd_opt_type = ND_OPT_TARGET_LINKADDR,
|
||||
.opt.nd_opt_len = 1,
|
||||
.lladdr = *(struct ether_addr *)tgt_ll,
|
||||
};
|
||||
|
||||
if (nd_addr_is_multicast(dst)) {
|
||||
if (!nd_addr_is_multicast(dst)) {
|
||||
msg.na.nd_na_flags_reserved |= ND_NA_FLAG_SOLICITED;
|
||||
}
|
||||
|
||||
|
11
src/ndppd.c
11
src/ndppd.c
@ -261,7 +261,9 @@ int main(int argc, char *argv[])
|
||||
nd_rt_query_routes();
|
||||
bool querying_routes = true;
|
||||
|
||||
while (1) {
|
||||
long last_session_update = 0;
|
||||
|
||||
for(;;) {
|
||||
if (nd_current_time >= nd_rt_dump_timeout) {
|
||||
nd_rt_dump_timeout = 0;
|
||||
}
|
||||
@ -272,13 +274,16 @@ int main(int argc, char *argv[])
|
||||
nd_rt_query_addresses();
|
||||
}
|
||||
|
||||
if (nd_current_time - last_session_update > 100) {
|
||||
nd_session_update_all();
|
||||
last_session_update = nd_current_time;
|
||||
}
|
||||
|
||||
if (!nd_io_poll()) {
|
||||
/* TODO: Error */
|
||||
break;
|
||||
}
|
||||
|
||||
nd_proxy_update_all();
|
||||
|
||||
gettimeofday(&t1, 0);
|
||||
nd_current_time = t1.tv_sec * 1000 + t1.tv_usec / 1000;
|
||||
}
|
||||
|
17
src/ndppd.h
17
src/ndppd.h
@ -96,16 +96,15 @@ struct nd_proxy {
|
||||
|
||||
nd_iface_t *iface;
|
||||
nd_rule_t *rules;
|
||||
nd_session_t *sessions;
|
||||
bool router;
|
||||
};
|
||||
|
||||
struct nd_session {
|
||||
nd_session_t *next_in_proxy;
|
||||
nd_session_t *next_in_iface;
|
||||
nd_session_t *next;
|
||||
nd_session_t *next_r;
|
||||
nd_rule_t *rule;
|
||||
nd_addr_t tgt;
|
||||
nd_addr_t real_tgt;
|
||||
nd_addr_t tgt_r;
|
||||
int ons_count; /* Number of outgoing NS messages. */
|
||||
long ons_time; /* Last time we sent a NS message. */
|
||||
long ins_time; /* Last time this session was the target of an incoming NS. */
|
||||
@ -143,11 +142,7 @@ struct nd_iface {
|
||||
|
||||
uint index;
|
||||
|
||||
int old_allmulti;
|
||||
int old_promisc;
|
||||
|
||||
nd_proxy_t *proxy;
|
||||
nd_session_t *sessions; // All sessions expecting NA messages to arrive here.
|
||||
|
||||
#ifndef __linux__
|
||||
nd_io_t *bpf_io;
|
||||
@ -271,6 +266,8 @@ void nd_addr_combine(const nd_addr_t *first, const nd_addr_t *second, unsigned p
|
||||
|
||||
bool nd_addr_is_unspecified(const nd_addr_t *addr);
|
||||
|
||||
uint32_t nd_addr_hash(const nd_addr_t *addr);
|
||||
|
||||
/*! Returns the string representation of link-layer address <tt>addr</tt>.
|
||||
*
|
||||
* @note This function returns a pointer to static data. It uses three different static arrays
|
||||
@ -288,7 +285,6 @@ nd_proxy_t *nd_proxy_create(const char *ifname);
|
||||
void nd_proxy_handle_ns(nd_proxy_t *proxy, const nd_addr_t *src, const nd_addr_t *dst, const nd_addr_t *tgt,
|
||||
const nd_lladdr_t *src_ll);
|
||||
bool nd_proxy_startup();
|
||||
void nd_proxy_update_all();
|
||||
|
||||
/*
|
||||
* session.c
|
||||
@ -298,6 +294,9 @@ nd_session_t *nd_session_create(nd_rule_t *rule, const nd_addr_t *tgt);
|
||||
void nd_session_update(nd_session_t *session);
|
||||
void nd_session_handle_ns(nd_session_t *session, const nd_addr_t *src, const nd_lladdr_t *src_ll);
|
||||
void nd_session_handle_na(nd_session_t *session);
|
||||
nd_session_t *nd_session_find(const nd_addr_t *tgt, const nd_proxy_t *proxy);
|
||||
nd_session_t *nd_session_find_r(const nd_addr_t *tgt, const nd_iface_t *iface);
|
||||
void nd_session_update_all();
|
||||
|
||||
/*
|
||||
* rule.c
|
||||
|
41
src/proxy.c
41
src/proxy.c
@ -56,42 +56,23 @@ void nd_proxy_handle_ns(nd_proxy_t *proxy, const nd_addr_t *src, const nd_addr_t
|
||||
{
|
||||
(void)dst;
|
||||
|
||||
if (nd_addr_is_unspecified(src)) {
|
||||
nd_log_trace("Handle NS src=(unspecified), dst=%s, tgt=%s", nd_ntoa(dst), nd_ntoa(tgt));
|
||||
} else {
|
||||
nd_log_trace("Handle NS src=%s [%s], dst=%s, tgt=%s", //
|
||||
nd_ntoa(src), nd_ll_ntoa(src_ll), nd_ntoa(dst), nd_ntoa(tgt));
|
||||
}
|
||||
nd_log_trace("Handle NS src=%s [%s], dst=%s, tgt=%s", //
|
||||
nd_ntoa(src), nd_ll_ntoa(src_ll), nd_ntoa(dst), nd_ntoa(tgt));
|
||||
|
||||
nd_session_t *session;
|
||||
nd_session_t *session = nd_session_find(tgt, proxy);
|
||||
|
||||
ND_LL_FOREACH_NODEF (proxy->sessions, session, next_in_proxy) {
|
||||
if (nd_addr_eq(&session->tgt, tgt)) {
|
||||
nd_session_handle_ns(session, src, src_ll);
|
||||
if (!session) {
|
||||
nd_rule_t *rule;
|
||||
ND_LL_SEARCH(proxy->rules, rule, next, nd_addr_match(&rule->addr, tgt, rule->prefix));
|
||||
|
||||
if (!rule) {
|
||||
return;
|
||||
}
|
||||
|
||||
session = nd_session_create(rule, tgt);
|
||||
}
|
||||
|
||||
// If we get down here it means we don't have any valid sessions we can use.
|
||||
// See if we can find one more more matching rules.
|
||||
|
||||
nd_rule_t *rule;
|
||||
ND_LL_SEARCH(proxy->rules, rule, next, nd_addr_match(&rule->addr, tgt, rule->prefix));
|
||||
|
||||
if (!rule) {
|
||||
return;
|
||||
}
|
||||
|
||||
nd_session_handle_ns(nd_session_create(rule, tgt), src, src_ll);
|
||||
}
|
||||
|
||||
void nd_proxy_update_all()
|
||||
{
|
||||
ND_LL_FOREACH (ndL_proxies, proxy, next) {
|
||||
ND_LL_FOREACH_S (proxy->sessions, session, tmp, next_in_proxy) {
|
||||
nd_session_update(session);
|
||||
}
|
||||
}
|
||||
nd_session_handle_ns(session, src, src_ll);
|
||||
}
|
||||
|
||||
bool nd_proxy_startup()
|
||||
|
@ -28,7 +28,15 @@ extern int nd_conf_retrans_limit;
|
||||
extern int nd_conf_retrans_time;
|
||||
extern bool nd_conf_keepalive;
|
||||
|
||||
#ifndef NDPPD_SESSION_BUCKETS
|
||||
# define NDPPD_SESSION_BUCKETS 64
|
||||
#endif
|
||||
|
||||
#define NDL_BUCKET(a) (nd_addr_hash(a) % NDPPD_SESSION_BUCKETS)
|
||||
|
||||
static nd_session_t *ndL_free_sessions;
|
||||
static nd_session_t *ndL_sessions[NDPPD_SESSION_BUCKETS];
|
||||
static nd_session_t *ndL_sessions_r[NDPPD_SESSION_BUCKETS];
|
||||
|
||||
static void ndL_up(nd_session_t *session)
|
||||
{
|
||||
@ -70,7 +78,7 @@ void nd_session_handle_ns(nd_session_t *session, const nd_addr_t *src, const nd_
|
||||
void nd_session_handle_na(nd_session_t *session)
|
||||
{
|
||||
if (session->state != ND_STATE_VALID) {
|
||||
nd_log_debug("session [%s] %s -> VALID", session->rule->proxy->ifname, nd_ntoa(&session->tgt));
|
||||
nd_log_debug("Session [%s] %s -> VALID", session->rule->proxy->ifname, nd_ntoa(&session->tgt));
|
||||
|
||||
ndL_up(session);
|
||||
session->state = ND_STATE_VALID;
|
||||
@ -83,7 +91,7 @@ nd_session_t *nd_session_create(nd_rule_t *rule, const nd_addr_t *tgt)
|
||||
nd_session_t *session = ndL_free_sessions;
|
||||
|
||||
if (session) {
|
||||
ND_LL_DELETE(ndL_free_sessions, session, next_in_proxy);
|
||||
ND_LL_DELETE(ndL_free_sessions, session, next);
|
||||
} else {
|
||||
session = ND_ALLOC(nd_session_t);
|
||||
}
|
||||
@ -94,9 +102,10 @@ nd_session_t *nd_session_create(nd_rule_t *rule, const nd_addr_t *tgt)
|
||||
.tgt = *tgt,
|
||||
};
|
||||
|
||||
nd_addr_combine(&rule->rewrite_tgt, tgt, rule->rewrite_pflen, &session->real_tgt);
|
||||
nd_addr_combine(&rule->rewrite_tgt, tgt, rule->rewrite_pflen, &session->tgt_r);
|
||||
|
||||
ND_LL_PREPEND(rule->proxy->sessions, session, next_in_proxy);
|
||||
ND_LL_PREPEND(ndL_sessions[NDL_BUCKET(&session->tgt)], session, next);
|
||||
ND_LL_PREPEND(ndL_sessions_r[NDL_BUCKET(&session->tgt_r)], session, next_r);
|
||||
|
||||
if (rule->mode == ND_MODE_AUTO) {
|
||||
nd_rt_route_t *route = nd_rt_find_route(tgt, rule->table);
|
||||
@ -110,12 +119,10 @@ nd_session_t *nd_session_create(nd_rule_t *rule, const nd_addr_t *tgt)
|
||||
}
|
||||
|
||||
if (session->iface) {
|
||||
ND_LL_PREPEND(session->iface->sessions, session, next_in_iface);
|
||||
|
||||
session->state = ND_STATE_INCOMPLETE;
|
||||
session->ons_count = 1;
|
||||
session->ons_time = nd_current_time;
|
||||
nd_iface_send_ns(session->iface, &session->real_tgt);
|
||||
nd_iface_send_ns(session->iface, &session->tgt_r);
|
||||
} else if (rule->mode == ND_MODE_STATIC) {
|
||||
session->state = ND_STATE_VALID;
|
||||
}
|
||||
@ -139,7 +146,7 @@ void nd_session_update(nd_session_t *session)
|
||||
break;
|
||||
}
|
||||
|
||||
nd_iface_send_ns(session->iface, &session->real_tgt);
|
||||
nd_iface_send_ns(session->iface, &session->tgt_r);
|
||||
break;
|
||||
|
||||
case ND_STATE_INVALID:
|
||||
@ -150,12 +157,12 @@ void nd_session_update(nd_session_t *session)
|
||||
ndL_down(session);
|
||||
|
||||
if (session->iface) {
|
||||
ND_LL_DELETE(session->iface->sessions, session, next_in_iface);
|
||||
nd_iface_close(session->iface);
|
||||
}
|
||||
|
||||
ND_LL_DELETE(session->rule->proxy->sessions, session, next_in_proxy);
|
||||
ND_LL_PREPEND(ndL_free_sessions, session, next_in_proxy);
|
||||
ND_LL_DELETE(ndL_sessions[NDL_BUCKET(&session->tgt)], session, next);
|
||||
ND_LL_DELETE(ndL_sessions_r[NDL_BUCKET(&session->tgt_r)], session, next_r);
|
||||
ND_LL_PREPEND(ndL_free_sessions, session, next);
|
||||
|
||||
nd_log_debug("session [%s] %s INVALID -> (deleted)", //
|
||||
session->rule->proxy->ifname, nd_ntoa(&session->tgt));
|
||||
@ -175,7 +182,7 @@ void nd_session_update(nd_session_t *session)
|
||||
|
||||
if (nd_conf_keepalive || nd_current_time - session->ins_time < nd_conf_valid_ttl) {
|
||||
session->ons_count = 1;
|
||||
nd_iface_send_ns(session->iface, &session->real_tgt);
|
||||
nd_iface_send_ns(session->iface, &session->tgt_r);
|
||||
} else {
|
||||
session->ons_count = 0;
|
||||
}
|
||||
@ -207,8 +214,34 @@ void nd_session_update(nd_session_t *session)
|
||||
|
||||
session->ons_count++;
|
||||
session->ons_time = nd_current_time;
|
||||
nd_iface_send_ns(session->iface, &session->real_tgt);
|
||||
nd_iface_send_ns(session->iface, &session->tgt_r);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nd_session_t *nd_session_find(const nd_addr_t *tgt, const nd_proxy_t *proxy)
|
||||
{
|
||||
nd_session_t *session;
|
||||
ND_LL_SEARCH(ndL_sessions[NDL_BUCKET(tgt)], session, next,
|
||||
session->rule->proxy == proxy && nd_addr_eq(&session->tgt, tgt));
|
||||
return session;
|
||||
}
|
||||
|
||||
nd_session_t *nd_session_find_r(const nd_addr_t *tgt, const nd_iface_t *iface)
|
||||
{
|
||||
nd_session_t *session;
|
||||
ND_LL_SEARCH(ndL_sessions_r[NDL_BUCKET(tgt)], session, next_r,
|
||||
session->iface == iface && nd_addr_eq(&session->tgt_r, tgt));
|
||||
return session;
|
||||
}
|
||||
|
||||
void nd_session_update_all()
|
||||
{
|
||||
for (int i = 0; i < NDPPD_SESSION_BUCKETS; i++) {
|
||||
ND_LL_FOREACH(ndL_sessions[i], session, next) {
|
||||
nd_session_update(session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
23
test.sh
23
test.sh
@ -62,19 +62,24 @@ case "$1" in
|
||||
ip netns exec ndppd.rt ip link set ndppd.rt1 up
|
||||
ip netns exec ndppd.1 ip link set ndppd.1 up
|
||||
|
||||
ip netns exec ndppd.0 ip -6 addr add dead::1 dev ndppd.0
|
||||
ip netns exec ndppd.0 ip -6 route add default dev ndppd.0
|
||||
ip netns exec ndppd.0 ip -6 addr add dead::1/64 dev ndppd.0
|
||||
ip netns exec ndppd.0 ip -6 addr add dead::2/64 dev ndppd.0
|
||||
|
||||
ip netns exec ndppd.rt ip -6 addr add dead:: dev ndppd.rt0
|
||||
ip netns exec ndppd.rt ip -6 route add dead::/64 dev ndppd.rt0
|
||||
while ! ip netns exec ndppd.0 ip -6 route add default dev ndppd.0 src dead::1 &>/dev/null; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
ip netns exec ndppd.rt ip -6 addr add dead:1:: dev ndppd.rt1
|
||||
ip netns exec ndppd.rt ip -6 route add dead:1::/64 dev ndppd.rt1
|
||||
ip netns exec ndppd.rt ip -6 addr add dead::/64 dev ndppd.rt0
|
||||
ip netns exec ndppd.rt ip -6 addr add dead:1::/64 dev ndppd.rt1
|
||||
|
||||
ip netns exec ndppd.1 ip -6 addr add dead:1::1 dev ndppd.1
|
||||
ip netns exec ndppd.1 ip -6 route add default dev ndppd.1
|
||||
ip netns exec ndppd.1 ip -6 addr add dead:1::1/64 dev ndppd.1
|
||||
ip netns exec ndppd.1 ip -6 addr add dead:1::2/64 dev ndppd.1
|
||||
|
||||
ip netns exec ndppd.rt sysctl net.ipv6.conf.all.forwarding=1
|
||||
while ! ip netns exec ndppd.1 ip -6 route add default dev ndppd.1 src dead:1::1 &>/dev/null; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
ip netns exec ndppd.rt sysctl -q net.ipv6.conf.all.forwarding=1
|
||||
;;
|
||||
|
||||
"ndppd")
|
||||
|
Loading…
x
Reference in New Issue
Block a user