Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/in_pcb.c
Show First 20 Lines • Show All 109 Lines • ▼ Show 20 Lines | |||||
#include <security/mac/mac_framework.h> | #include <security/mac/mac_framework.h> | ||||
#define INPCBLBGROUP_SIZMIN 8 | #define INPCBLBGROUP_SIZMIN 8 | ||||
#define INPCBLBGROUP_SIZMAX 256 | #define INPCBLBGROUP_SIZMAX 256 | ||||
static struct callout ipport_tick_callout; | static struct callout ipport_tick_callout; | ||||
#if 0 | |||||
#define LBDEBUG(fmt, ...) do { \ | |||||
printf("%s: " fmt "\n", __func__, ## __VA_ARGS__); \ | |||||
} while (0) | |||||
#define LBDEBUG1(fmt, ...) do { \ | |||||
char _addr[50]; \ | |||||
printf("%s: " fmt "\n", __func__, ## __VA_ARGS__); \ | |||||
} while (0) | |||||
#define LBDEBUG2(fmt, ...) do { \ | |||||
char _laddr[50], _faddr[50]; \ | |||||
printf("%s: " fmt "\n", __func__, ## __VA_ARGS__); \ | |||||
} while (0) | |||||
#else | |||||
#define LBDEBUG(fmt, ...) | |||||
#define LBDEBUG1(fmt, ...) | |||||
#define LBDEBUG2(fmt, ...) | |||||
#endif | |||||
/* | /* | ||||
* These configure the range of local port addresses assigned to | * These configure the range of local port addresses assigned to | ||||
* "unspecified" outgoing connections/packets/whatever. | * "unspecified" outgoing connections/packets/whatever. | ||||
*/ | */ | ||||
VNET_DEFINE(int, ipport_lowfirstauto) = IPPORT_RESERVED - 1; /* 1023 */ | VNET_DEFINE(int, ipport_lowfirstauto) = IPPORT_RESERVED - 1; /* 1023 */ | ||||
VNET_DEFINE(int, ipport_lowlastauto) = IPPORT_RESERVEDSTART; /* 600 */ | VNET_DEFINE(int, ipport_lowlastauto) = IPPORT_RESERVEDSTART; /* 600 */ | ||||
VNET_DEFINE(int, ipport_firstauto) = IPPORT_EPHEMERALFIRST; /* 10000 */ | VNET_DEFINE(int, ipport_firstauto) = IPPORT_EPHEMERALFIRST; /* 10000 */ | ||||
VNET_DEFINE(int, ipport_lastauto) = IPPORT_EPHEMERALLAST; /* 65535 */ | VNET_DEFINE(int, ipport_lastauto) = IPPORT_EPHEMERALLAST; /* 65535 */ | ||||
Show All 14 Lines | |||||
VNET_DEFINE(int, ipport_randomtime) = 45; /* user controlled via sysctl */ | VNET_DEFINE(int, ipport_randomtime) = 45; /* user controlled via sysctl */ | ||||
VNET_DEFINE(int, ipport_stoprandom); /* toggled by ipport_tick */ | VNET_DEFINE(int, ipport_stoprandom); /* toggled by ipport_tick */ | ||||
VNET_DEFINE(int, ipport_tcpallocs); | VNET_DEFINE(int, ipport_tcpallocs); | ||||
VNET_DEFINE_STATIC(int, ipport_tcplastcount); | VNET_DEFINE_STATIC(int, ipport_tcplastcount); | ||||
#define V_ipport_tcplastcount VNET(ipport_tcplastcount) | #define V_ipport_tcplastcount VNET(ipport_tcplastcount) | ||||
static void in_pcbremlists(struct inpcb *inp); | static void in_pcbremlists(struct inpcb *inp); | ||||
static void in_pcblbstate_free(epoch_context_t ctx); | |||||
#ifdef INET | #ifdef INET | ||||
static struct inpcb *in_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, | static struct inpcb *in_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, | ||||
struct in_addr faddr, u_int fport_arg, | struct in_addr faddr, u_int fport_arg, | ||||
struct in_addr laddr, u_int lport_arg, | struct in_addr laddr, u_int lport_arg, | ||||
int lookupflags, struct ifnet *ifp); | int lookupflags, struct ifnet *ifp); | ||||
#define RANGECHK(var, min, max) \ | #define RANGECHK(var, min, max) \ | ||||
if ((var) < (min)) { (var) = (min); } \ | if ((var) < (min)) { (var) = (min); } \ | ||||
▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | in_pcblbgroup_alloc(struct inpcblbgrouphead *hdr, u_char vflag, | ||||
grp->il_lport = port; | grp->il_lport = port; | ||||
grp->il_dependladdr = *addr; | grp->il_dependladdr = *addr; | ||||
grp->il_inpsiz = size; | grp->il_inpsiz = size; | ||||
CK_LIST_INSERT_HEAD(hdr, grp, il_list); | CK_LIST_INSERT_HEAD(hdr, grp, il_list); | ||||
return (grp); | return (grp); | ||||
} | } | ||||
static void | static void | ||||
lbstate_tick(void *arg) | |||||
{ | |||||
struct inpcblbgroup *grp; | |||||
struct inpcb_lbstate *s, *ts; | |||||
int i; | |||||
grp = arg; | |||||
CURVNET_SET(grp->il_pcbinfo->ipi_vnet); | |||||
for (i = 0; i < LBSTATE_HASHSIZE; i++) { | |||||
CK_LIST_FOREACH_SAFE(s, &grp->il_htbl[i], grpchain, ts) { | |||||
if (time_uptime - s->ts < V_udp_lbstate_lifetime) | |||||
continue; | |||||
#if 0 | |||||
switch (INP_SOCKAF(s->inp->inp_socket)) { | |||||
case AF_INET: | |||||
LBDEBUG2("expired state: %s:%u -> %s:%u", | |||||
inet_ntop(AF_INET, | |||||
&s->ie.ie_laddr, _laddr, sizeof(_laddr)), | |||||
ntohs(s->ie.ie_lport), | |||||
inet_ntop(AF_INET, | |||||
&s->ie.ie_faddr, _faddr, sizeof(_faddr)), | |||||
ntohs(s->ie.ie_fport)); | |||||
break; | |||||
case AF_INET6: | |||||
LBDEBUG2("expired state: %s:%u -> %s:%u", | |||||
inet_ntop(AF_INET6, | |||||
&s->ie.ie6_laddr, _laddr, sizeof(_laddr)), | |||||
ntohs(s->ie.ie_lport), | |||||
inet_ntop(AF_INET6, | |||||
&s->ie.ie6_faddr, _faddr, sizeof(_faddr)), | |||||
ntohs(s->ie.ie_fport)); | |||||
break; | |||||
default: | |||||
LBDEBUG("expired state"); | |||||
} | |||||
#endif | |||||
CK_LIST_REMOVE(s, grpchain); | |||||
CK_LIST_REMOVE(s, pcbchain); | |||||
s->inp->inp_lbscnt--; | |||||
NET_EPOCH_CALL(in_pcblbstate_free, &s->epoch_ctx); | |||||
} | |||||
} | |||||
CURVNET_RESTORE(); | |||||
callout_reset(grp->il_callout, hz, lbstate_tick, grp); | |||||
} | |||||
static void | |||||
in_pcblbgroup_free_deferred(epoch_context_t ctx) | in_pcblbgroup_free_deferred(epoch_context_t ctx) | ||||
{ | { | ||||
struct inpcblbgroup *grp; | struct inpcblbgroup *grp; | ||||
grp = __containerof(ctx, struct inpcblbgroup, il_epoch_ctx); | grp = __containerof(ctx, struct inpcblbgroup, il_epoch_ctx); | ||||
free(grp, M_PCB); | free(grp, M_PCB); | ||||
} | } | ||||
static void | static void | ||||
in_pcblbgroup_free(struct inpcblbgroup *grp) | in_pcblbgroup_free(struct inpcblbgroup *grp) | ||||
{ | { | ||||
CK_LIST_REMOVE(grp, il_list); | CK_LIST_REMOVE(grp, il_list); | ||||
NET_EPOCH_CALL(in_pcblbgroup_free_deferred, &grp->il_epoch_ctx); | NET_EPOCH_CALL(in_pcblbgroup_free_deferred, &grp->il_epoch_ctx); | ||||
} | } | ||||
static struct inpcblbgroup * | static struct inpcblbgroup * | ||||
in_pcblbgroup_alloc0(struct inpcblbgrouphead *hdr, u_char vflag, | |||||
uint16_t port, const union in_dependaddr *addr, int size) | |||||
{ | |||||
struct inpcblbgroup *grp; | |||||
grp = in_pcblbgroup_alloc(hdr, vflag, port, addr, size); | |||||
if (grp == NULL) | |||||
return (NULL); | |||||
grp->il_lock = malloc(sizeof(*grp->il_lock), M_PCB, M_NOWAIT); | |||||
if (grp->il_lock == NULL) { | |||||
in_pcblbgroup_free(grp); | |||||
return (NULL); | |||||
} | |||||
grp->il_callout = malloc(sizeof(*grp->il_callout), M_PCB, | |||||
M_NOWAIT); | |||||
if (grp->il_callout == NULL) { | |||||
free(grp->il_lock, M_PCB); | |||||
in_pcblbgroup_free(grp); | |||||
return (NULL); | |||||
} | |||||
grp->il_htbl = malloc(sizeof(*grp->il_htbl) * LBSTATE_HASHSIZE, | |||||
M_PCB, M_NOWAIT | M_ZERO); | |||||
if (grp->il_htbl == NULL) { | |||||
free(grp->il_callout, M_PCB); | |||||
free(grp->il_lock, M_PCB); | |||||
in_pcblbgroup_free(grp); | |||||
return (NULL); | |||||
} | |||||
mtx_init(grp->il_lock, "inplbhtbl", NULL, MTX_DEF | MTX_NEW); | |||||
callout_init_mtx(grp->il_callout, grp->il_lock, 0); | |||||
mtx_lock(grp->il_lock); | |||||
callout_reset(grp->il_callout, hz, lbstate_tick, grp); | |||||
mtx_unlock(grp->il_lock); | |||||
LBDEBUG("new lbgroup for port %u", ntohs(port)); | |||||
return (grp); | |||||
} | |||||
static struct inpcblbgroup * | |||||
in_pcblbgroup_resize(struct inpcblbgrouphead *hdr, | in_pcblbgroup_resize(struct inpcblbgrouphead *hdr, | ||||
struct inpcblbgroup *old_grp, int size) | struct inpcblbgroup *old_grp, int size) | ||||
{ | { | ||||
struct inpcblbgroup *grp; | struct inpcblbgroup *grp; | ||||
int i; | int i; | ||||
grp = in_pcblbgroup_alloc(hdr, old_grp->il_vflag, | grp = in_pcblbgroup_alloc(hdr, old_grp->il_vflag, | ||||
old_grp->il_lport, &old_grp->il_dependladdr, size); | old_grp->il_lport, &old_grp->il_dependladdr, size); | ||||
if (grp == NULL) | if (grp == NULL) | ||||
return (NULL); | return (NULL); | ||||
KASSERT(old_grp->il_inpcnt < grp->il_inpsiz, | KASSERT(old_grp->il_inpcnt < grp->il_inpsiz, | ||||
("invalid new local group size %d and old local group count %d", | ("invalid new local group size %d and old local group count %d", | ||||
grp->il_inpsiz, old_grp->il_inpcnt)); | grp->il_inpsiz, old_grp->il_inpcnt)); | ||||
for (i = 0; i < old_grp->il_inpcnt; ++i) | for (i = 0; i < old_grp->il_inpcnt; ++i) | ||||
grp->il_inp[i] = old_grp->il_inp[i]; | grp->il_inp[i] = old_grp->il_inp[i]; | ||||
grp->il_pcbinfo = old_grp->il_pcbinfo; | |||||
grp->il_inpcnt = old_grp->il_inpcnt; | grp->il_inpcnt = old_grp->il_inpcnt; | ||||
/* Inherit lock and htbl from old group */ | |||||
grp->il_lock = old_grp->il_lock; | |||||
grp->il_htbl = old_grp->il_htbl; | |||||
grp->il_callout = old_grp->il_callout; | |||||
/* Reschedule callout with new group */ | |||||
mtx_lock(grp->il_lock); | |||||
callout_reset(grp->il_callout, hz, lbstate_tick, grp); | |||||
mtx_unlock(grp->il_lock); | |||||
in_pcblbgroup_free(old_grp); | in_pcblbgroup_free(old_grp); | ||||
return (grp); | return (grp); | ||||
} | } | ||||
/* | /* | ||||
* PCB at index 'i' is removed from the group. Pull up the ones below il_inp[i] | * PCB at index 'i' is removed from the group. Pull up the ones below il_inp[i] | ||||
* and shrink group if possible. | * and shrink group if possible. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | if (grp->il_vflag == inp->inp_vflag && | ||||
grp->il_lport == inp->inp_lport && | grp->il_lport == inp->inp_lport && | ||||
memcmp(&grp->il_dependladdr, | memcmp(&grp->il_dependladdr, | ||||
&inp->inp_inc.inc_ie.ie_dependladdr, | &inp->inp_inc.inc_ie.ie_dependladdr, | ||||
sizeof(grp->il_dependladdr)) == 0) | sizeof(grp->il_dependladdr)) == 0) | ||||
break; | break; | ||||
} | } | ||||
if (grp == NULL) { | if (grp == NULL) { | ||||
/* Create new load balance group. */ | /* Create new load balance group. */ | ||||
grp = in_pcblbgroup_alloc(hdr, inp->inp_vflag, | grp = in_pcblbgroup_alloc0(hdr, inp->inp_vflag, | ||||
inp->inp_lport, &inp->inp_inc.inc_ie.ie_dependladdr, | inp->inp_lport, &inp->inp_inc.inc_ie.ie_dependladdr, | ||||
INPCBLBGROUP_SIZMIN); | INPCBLBGROUP_SIZMIN); | ||||
if (grp == NULL) | if (grp == NULL) | ||||
return (ENOBUFS); | return (ENOBUFS); | ||||
grp->il_pcbinfo = pcbinfo; | |||||
} else if (grp->il_inpcnt == grp->il_inpsiz) { | } else if (grp->il_inpcnt == grp->il_inpsiz) { | ||||
if (grp->il_inpsiz >= INPCBLBGROUP_SIZMAX) { | if (grp->il_inpsiz >= INPCBLBGROUP_SIZMAX) { | ||||
if (ratecheck(&lastprint, &interval)) | if (ratecheck(&lastprint, &interval)) | ||||
printf("lb group port %d, limit reached\n", | printf("lb group port %d, limit reached\n", | ||||
ntohs(grp->il_lport)); | ntohs(grp->il_lport)); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* Expand this local group. */ | /* Expand this local group. */ | ||||
grp = in_pcblbgroup_resize(hdr, grp, grp->il_inpsiz * 2); | grp = in_pcblbgroup_resize(hdr, grp, grp->il_inpsiz * 2); | ||||
if (grp == NULL) | if (grp == NULL) | ||||
return (ENOBUFS); | return (ENOBUFS); | ||||
} | } | ||||
KASSERT(grp->il_inpcnt < grp->il_inpsiz, | KASSERT(grp->il_inpcnt < grp->il_inpsiz, | ||||
("invalid local group size %d and count %d", grp->il_inpsiz, | ("invalid local group size %d and count %d", grp->il_inpsiz, | ||||
grp->il_inpcnt)); | grp->il_inpcnt)); | ||||
grp->il_inp[grp->il_inpcnt] = inp; | grp->il_inp[grp->il_inpcnt] = inp; | ||||
grp->il_inpcnt++; | grp->il_inpcnt++; | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | |||||
in_pcblbstate_free(epoch_context_t ctx) | |||||
{ | |||||
struct inpcb_lbstate *s; | |||||
s = __containerof(ctx, struct inpcb_lbstate, epoch_ctx); | |||||
free(s, M_PCB); | |||||
} | |||||
/* | /* | ||||
* Free LB states releated to PCB. | |||||
*/ | |||||
static void | |||||
in_pcblbstates_destroy(struct inpcblbgroup *grp, struct inpcb *inp) | |||||
{ | |||||
struct inpcb_lbstate *s; | |||||
mtx_lock(grp->il_lock); | |||||
while (!CK_LIST_EMPTY(&inp->inp_lbstates)) { | |||||
s = CK_LIST_FIRST(&inp->inp_lbstates); | |||||
CK_LIST_REMOVE(s, grpchain); | |||||
CK_LIST_REMOVE(s, pcbchain); | |||||
NET_EPOCH_CALL(in_pcblbstate_free, &s->epoch_ctx); | |||||
} | |||||
mtx_unlock(grp->il_lock); | |||||
} | |||||
static void | |||||
in_pcblbhtbl_free(struct inpcblbgroup *grp) | |||||
{ | |||||
struct inpcb_lbstate *s; | |||||
int i; | |||||
mtx_lock(grp->il_lock); | |||||
callout_stop(grp->il_callout); | |||||
for (i = 0; i < LBSTATE_HASHSIZE; i++) { | |||||
while (!CK_LIST_EMPTY(&grp->il_htbl[i])) { | |||||
s = CK_LIST_FIRST(&grp->il_htbl[i]); | |||||
CK_LIST_REMOVE(s, grpchain); | |||||
CK_LIST_REMOVE(s, pcbchain); | |||||
NET_EPOCH_CALL(in_pcblbstate_free, &s->epoch_ctx); | |||||
} | |||||
} | |||||
mtx_unlock(grp->il_lock); | |||||
mtx_destroy(grp->il_lock); | |||||
free(grp->il_callout, M_PCB); | |||||
free(grp->il_lock, M_PCB); | |||||
free(grp->il_htbl, M_PCB); | |||||
} | |||||
/* | |||||
* Remove PCB from load balance group. | * Remove PCB from load balance group. | ||||
*/ | */ | ||||
static void | static void | ||||
in_pcbremlbgrouphash(struct inpcb *inp) | in_pcbremlbgrouphash(struct inpcb *inp) | ||||
{ | { | ||||
struct inpcbinfo *pcbinfo; | struct inpcbinfo *pcbinfo; | ||||
struct inpcblbgrouphead *hdr; | struct inpcblbgrouphead *hdr; | ||||
struct inpcblbgroup *grp; | struct inpcblbgroup *grp; | ||||
int i; | int i; | ||||
pcbinfo = inp->inp_pcbinfo; | pcbinfo = inp->inp_pcbinfo; | ||||
INP_WLOCK_ASSERT(inp); | INP_WLOCK_ASSERT(inp); | ||||
INP_HASH_WLOCK_ASSERT(pcbinfo); | INP_HASH_WLOCK_ASSERT(pcbinfo); | ||||
hdr = &pcbinfo->ipi_lbgrouphashbase[ | hdr = &pcbinfo->ipi_lbgrouphashbase[ | ||||
INP_PCBPORTHASH(inp->inp_lport, pcbinfo->ipi_lbgrouphashmask)]; | INP_PCBPORTHASH(inp->inp_lport, pcbinfo->ipi_lbgrouphashmask)]; | ||||
CK_LIST_FOREACH(grp, hdr, il_list) { | CK_LIST_FOREACH(grp, hdr, il_list) { | ||||
for (i = 0; i < grp->il_inpcnt; ++i) { | for (i = 0; i < grp->il_inpcnt; ++i) { | ||||
if (grp->il_inp[i] != inp) | if (grp->il_inp[i] != inp) | ||||
continue; | continue; | ||||
if (grp->il_inpcnt == 1) { | if (grp->il_inpcnt == 1) { | ||||
/* We are the last, free this local group. */ | /* We are the last, free this local group. */ | ||||
in_pcblbhtbl_free(grp); | |||||
in_pcblbgroup_free(grp); | in_pcblbgroup_free(grp); | ||||
} else { | } else { | ||||
/* Pull up inpcbs, shrink group if possible. */ | /* Pull up inpcbs, shrink group if possible. */ | ||||
in_pcblbgroup_reorder(hdr, &grp, i); | in_pcblbgroup_reorder(hdr, &grp, i); | ||||
in_pcblbstates_destroy(grp, inp); | |||||
} | } | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Different protocols initialize their inpcbs differently - giving | * Different protocols initialize their inpcbs differently - giving | ||||
▲ Show 20 Lines • Show All 1,557 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return (match); | return (match); | ||||
} | } | ||||
} | } | ||||
#undef INP_LOOKUP_MAPPED_PCB_COST | #undef INP_LOOKUP_MAPPED_PCB_COST | ||||
static struct inpcb * | static struct inpcblbgroup * | ||||
in_pcblookup_lbgroup(const struct inpcbinfo *pcbinfo, | in_pcblbgroup_lookup(const struct inpcbinfo *pcbinfo, | ||||
const struct in_addr *laddr, uint16_t lport, const struct in_addr *faddr, | const struct in_addr *laddr, uint16_t lport, const struct in_addr *faddr, | ||||
uint16_t fport, int lookupflags) | uint16_t fport, int lookupflags) | ||||
{ | { | ||||
struct inpcb *local_wild; | |||||
const struct inpcblbgrouphead *hdr; | const struct inpcblbgrouphead *hdr; | ||||
struct inpcblbgroup *grp; | struct inpcblbgroup *grp, *grp_local_wild; | ||||
uint32_t idx; | |||||
INP_HASH_LOCK_ASSERT(pcbinfo); | |||||
hdr = &pcbinfo->ipi_lbgrouphashbase[ | |||||
INP_PCBPORTHASH(lport, pcbinfo->ipi_lbgrouphashmask)]; | |||||
/* | /* | ||||
* Order of socket selection: | * Order of group selection: | ||||
* 1. non-wild. | * 1. non-wild. | ||||
* 2. wild (if lookupflags contains INPLOOKUP_WILDCARD). | * 2. wild (if lookupflags contains INPLOOKUP_WILDCARD). | ||||
* | * | ||||
* NOTE: | * NOTE: | ||||
* - Load balanced group does not contain jailed sockets | * - Load balanced group does not contain jailed sockets | ||||
* - Load balanced group does not contain IPv4 mapped INET6 wild sockets | * - Load balanced group does not contain IPv4 mapped INET6 | ||||
* wild sockets | |||||
*/ | */ | ||||
local_wild = NULL; | INP_HASH_LOCK_ASSERT(pcbinfo); | ||||
hdr = &pcbinfo->ipi_lbgrouphashbase[ | |||||
INP_PCBPORTHASH(lport, pcbinfo->ipi_lbgrouphashmask)]; | |||||
grp_local_wild = NULL; | |||||
CK_LIST_FOREACH(grp, hdr, il_list) { | CK_LIST_FOREACH(grp, hdr, il_list) { | ||||
#ifdef INET6 | #ifdef INET6 | ||||
if (!(grp->il_vflag & INP_IPV4)) | if (!(grp->il_vflag & INP_IPV4)) | ||||
continue; | continue; | ||||
#endif | #endif | ||||
if (grp->il_lport != lport) | if (grp->il_lport != lport) | ||||
continue; | continue; | ||||
idx = INP_PCBLBGROUP_PKTHASH(faddr->s_addr, lport, fport) % | |||||
grp->il_inpcnt; | |||||
if (grp->il_laddr.s_addr == laddr->s_addr) | if (grp->il_laddr.s_addr == laddr->s_addr) | ||||
return (grp->il_inp[idx]); | return (grp); | ||||
if (grp->il_laddr.s_addr == INADDR_ANY && | if (grp->il_laddr.s_addr == INADDR_ANY && | ||||
(lookupflags & INPLOOKUP_WILDCARD) != 0) | (lookupflags & INPLOOKUP_WILDCARD)) | ||||
local_wild = grp->il_inp[idx]; | grp_local_wild = grp; | ||||
} | } | ||||
return (local_wild); | return (grp_local_wild); | ||||
} | |||||
static struct inpcb_lbstate * | |||||
in_pcblbstate_lookup(struct inpcblbgroup *grp, uint32_t hash, | |||||
const struct in_addr *faddr, uint16_t fport) | |||||
{ | |||||
struct inpcb_lbstate *s; | |||||
NET_EPOCH_ASSERT(); | |||||
CK_LIST_FOREACH(s, &INP_LBSTATE_HASH(grp, hash), grpchain) { | |||||
if (s->ie.ie_faddr.s_addr == faddr->s_addr && | |||||
s->ie.ie_fport == fport && | |||||
s->ie.ie_laddr.s_addr == grp->il_laddr.s_addr && | |||||
s->ie.ie_lport == grp->il_lport) { | |||||
LBDEBUG2("matched state: %s:%u -> %s:%u", | |||||
inet_ntop(AF_INET, | |||||
&grp->il_laddr, _laddr, sizeof(_laddr)), | |||||
grp->il_lport, | |||||
inet_ntop(AF_INET, | |||||
faddr, _faddr, sizeof(_faddr)), | |||||
fport); | |||||
break; | |||||
} | |||||
} | |||||
return (s); | |||||
} | |||||
void | |||||
in_pcblbstate_update(struct inpcb *inp, const struct in_addr *laddr, | |||||
uint16_t lport, const struct in_addr *faddr, uint16_t fport) | |||||
{ | |||||
struct inpcblbgroup *grp; | |||||
struct inpcb_lbstate *s; | |||||
uint32_t hash; | |||||
grp = in_pcblbgroup_lookup(inp->inp_pcbinfo, laddr, lport, faddr, | |||||
fport, INPLOOKUP_WILDCARD); | |||||
if (grp == NULL) | |||||
return; | |||||
/* Update timestamp if state is existing */ | |||||
hash = INP_PCBLBGROUP_PKTHASH(faddr->s_addr, lport, fport); | |||||
NET_EPOCH_ASSERT(); | |||||
s = in_pcblbstate_lookup(grp, hash, faddr, fport); | |||||
if (s != NULL) { | |||||
s->ts = time_uptime; | |||||
MPASS(s->inp == inp); | |||||
return; | |||||
} | |||||
/* No state found. Try to allocate one. */ | |||||
s = malloc(sizeof(*s), M_PCB, M_ZERO | M_NOWAIT); | |||||
if (s == NULL) | |||||
return; | |||||
s->ie.ie_faddr.s_addr = faddr->s_addr; | |||||
s->ie.ie_laddr.s_addr = laddr->s_addr; | |||||
s->ie.ie_fport = fport; | |||||
s->ie.ie_lport = lport; | |||||
s->ts = time_uptime; | |||||
s->inp = inp; | |||||
mtx_lock(grp->il_lock); | |||||
if (in_pcblbstate_lookup(grp, hash, faddr, fport) == NULL) { | |||||
CK_LIST_INSERT_HEAD(&INP_LBSTATE_HASH(grp, hash), | |||||
s, grpchain); | |||||
CK_LIST_INSERT_HEAD(&inp->inp_lbstates, s, pcbchain); | |||||
inp->inp_lbscnt++; | |||||
LBDEBUG2("new state: %s:%u -> %s:%u", | |||||
inet_ntop(AF_INET, | |||||
&grp->il_laddr, _laddr, sizeof(_laddr)), | |||||
ntohs(grp->il_lport), | |||||
inet_ntop(AF_INET, | |||||
faddr, _faddr, sizeof(_faddr)), | |||||
ntohs(fport)); | |||||
} else { | |||||
free(s, M_PCB); | |||||
} | |||||
mtx_unlock(grp->il_lock); | |||||
} | |||||
static struct inpcb * | |||||
in_pcblookup_lbgroup(const struct inpcbinfo *pcbinfo, | |||||
const struct in_addr *laddr, uint16_t lport, const struct in_addr *faddr, | |||||
uint16_t fport, int lookupflags) | |||||
{ | |||||
struct inpcb_lbstate *s; | |||||
struct inpcblbgroup *grp; | |||||
struct inpcb *inp; | |||||
uint32_t hash; | |||||
int i; | |||||
grp = in_pcblbgroup_lookup(pcbinfo, laddr, lport, faddr, | |||||
fport, lookupflags); | |||||
if (grp == NULL) | |||||
return (NULL); | |||||
hash = INP_PCBLBGROUP_PKTHASH(faddr->s_addr, lport, fport); | |||||
s = in_pcblbstate_lookup(grp, hash, faddr, fport); | |||||
if (s == NULL) { | |||||
inp = grp->il_inp[hash % grp->il_inpcnt]; | |||||
for (i = 0; i < grp->il_inpcnt; i++) { | |||||
if (inp->inp_lbscnt == 0) | |||||
break; | |||||
if (inp->inp_lbscnt > grp->il_inp[i]->inp_lbscnt) | |||||
inp = grp->il_inp[i]; | |||||
} | |||||
} else | |||||
inp = s->inp; | |||||
return (inp); | |||||
} | } | ||||
#ifdef PCBGROUP | #ifdef PCBGROUP | ||||
/* | /* | ||||
* Lookup PCB in hash list, using pcbgroup tables. | * Lookup PCB in hash list, using pcbgroup tables. | ||||
*/ | */ | ||||
static struct inpcb * | static struct inpcb * | ||||
in_pcblookup_group(struct inpcbinfo *pcbinfo, struct inpcbgroup *pcbgroup, | in_pcblookup_group(struct inpcbinfo *pcbinfo, struct inpcbgroup *pcbgroup, | ||||
▲ Show 20 Lines • Show All 1,468 Lines • Show Last 20 Lines |