Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netinet6/frag6.c
Show First 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | struct ip6asfrag { | ||||
int ip6af_off; /* fragment offset */ | int ip6af_off; /* fragment offset */ | ||||
u_int16_t ip6af_mff; /* more fragment bit in frag off */ | u_int16_t ip6af_mff; /* more fragment bit in frag off */ | ||||
}; | }; | ||||
#define IP6_REASS_MBUF(ip6af) (*(struct mbuf **)&((ip6af)->ip6af_m)) | #define IP6_REASS_MBUF(ip6af) (*(struct mbuf **)&((ip6af)->ip6af_m)) | ||||
static MALLOC_DEFINE(M_FRAG6, "frag6", "IPv6 fragment reassembly header"); | static MALLOC_DEFINE(M_FRAG6, "frag6", "IPv6 fragment reassembly header"); | ||||
#ifdef VIMAGE | |||||
/* A flag to indicate if IPv6 fragmentation is initialized. */ | |||||
VNET_DEFINE_STATIC(bool, frag6_on); | |||||
#define V_frag6_on VNET(frag6_on) | |||||
#endif | |||||
/* System wide (global) maximum and count of packets in reassembly queues. */ | /* System wide (global) maximum and count of packets in reassembly queues. */ | ||||
static int ip6_maxfrags; | static int ip6_maxfrags; | ||||
static volatile u_int frag6_nfrags = 0; | static volatile u_int frag6_nfrags = 0; | ||||
/* Maximum and current packets in per-VNET reassembly queue. */ | /* Maximum and current packets in per-VNET reassembly queue. */ | ||||
VNET_DEFINE_STATIC(int, ip6_maxfragpackets); | VNET_DEFINE_STATIC(int, ip6_maxfragpackets); | ||||
VNET_DEFINE_STATIC(volatile u_int, frag6_nfragpackets); | VNET_DEFINE_STATIC(volatile u_int, frag6_nfragpackets); | ||||
#define V_ip6_maxfragpackets VNET(ip6_maxfragpackets) | #define V_ip6_maxfragpackets VNET(ip6_maxfragpackets) | ||||
▲ Show 20 Lines • Show All 173 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct ip6q *q6, *q6n, *head; | struct ip6q *q6, *q6n, *head; | ||||
struct ip6asfrag *af6; | struct ip6asfrag *af6; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
int i; | int i; | ||||
KASSERT(ifp != NULL, ("%s: ifp is NULL", __func__)); | KASSERT(ifp != NULL, ("%s: ifp is NULL", __func__)); | ||||
#ifdef VIMAGE | |||||
/* | |||||
* Skip processing if IPv6 reassembly is not initialised or | |||||
* torn down by frag6_destroy(). | |||||
*/ | |||||
if (!V_frag6_on) | |||||
return; | |||||
#endif | |||||
CURVNET_SET_QUIET(ifp->if_vnet); | CURVNET_SET_QUIET(ifp->if_vnet); | ||||
for (i = 0; i < IP6REASS_NHASH; i++) { | for (i = 0; i < IP6REASS_NHASH; i++) { | ||||
IP6QB_LOCK(i); | IP6QB_LOCK(i); | ||||
head = IP6QB_HEAD(i); | head = IP6QB_HEAD(i); | ||||
/* Scan fragment list. */ | /* Scan fragment list. */ | ||||
for (q6 = head->ip6q_next; q6 != head; q6 = q6n) { | for (q6 = head->ip6q_next; q6 != head; q6 = q6n) { | ||||
q6n = q6->ip6q_next; | q6n = q6->ip6q_next; | ||||
▲ Show 20 Lines • Show All 624 Lines • ▼ Show 20 Lines | frag6_init(void) | ||||
for (bucket = 0; bucket < IP6REASS_NHASH; bucket++) { | for (bucket = 0; bucket < IP6REASS_NHASH; bucket++) { | ||||
q6 = IP6QB_HEAD(bucket); | q6 = IP6QB_HEAD(bucket); | ||||
q6->ip6q_next = q6->ip6q_prev = q6; | q6->ip6q_next = q6->ip6q_prev = q6; | ||||
mtx_init(&V_ip6qb[bucket].lock, "ip6qlock", NULL, MTX_DEF); | mtx_init(&V_ip6qb[bucket].lock, "ip6qlock", NULL, MTX_DEF); | ||||
V_ip6qb[bucket].count = 0; | V_ip6qb[bucket].count = 0; | ||||
} | } | ||||
V_ip6qb_hashseed = arc4random(); | V_ip6qb_hashseed = arc4random(); | ||||
V_ip6_maxfragsperpacket = 64; | V_ip6_maxfragsperpacket = 64; | ||||
#ifdef VIMAGE | |||||
V_frag6_on = true; | |||||
#endif | |||||
if (!IS_DEFAULT_VNET(curvnet)) | if (!IS_DEFAULT_VNET(curvnet)) | ||||
return; | return; | ||||
ip6_maxfrags = IP6_MAXFRAGS; | ip6_maxfrags = IP6_MAXFRAGS; | ||||
EVENTHANDLER_REGISTER(nmbclusters_change, | EVENTHANDLER_REGISTER(nmbclusters_change, | ||||
frag6_change, NULL, EVENTHANDLER_PRI_ANY); | frag6_change, NULL, EVENTHANDLER_PRI_ANY); | ||||
} | } | ||||
/* | /* | ||||
* Drain off all datagram fragments. | * Drain off all datagram fragments. | ||||
*/ | */ | ||||
void | static void | ||||
frag6_drain(void) | frag6_drain_one(void) | ||||
{ | { | ||||
VNET_ITERATOR_DECL(vnet_iter); | |||||
struct ip6q *head; | struct ip6q *head; | ||||
uint32_t bucket; | uint32_t bucket; | ||||
VNET_LIST_RLOCK_NOSLEEP(); | |||||
VNET_FOREACH(vnet_iter) { | |||||
CURVNET_SET(vnet_iter); | |||||
for (bucket = 0; bucket < IP6REASS_NHASH; bucket++) { | for (bucket = 0; bucket < IP6REASS_NHASH; bucket++) { | ||||
if (IP6QB_TRYLOCK(bucket) == 0) | IP6QB_LOCK(bucket); | ||||
continue; | |||||
head = IP6QB_HEAD(bucket); | head = IP6QB_HEAD(bucket); | ||||
while (head->ip6q_next != head) { | while (head->ip6q_next != head) { | ||||
IP6STAT_INC(ip6s_fragdropped); | IP6STAT_INC(ip6s_fragdropped); | ||||
/* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ | /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ | ||||
frag6_freef(head->ip6q_next, bucket); | frag6_freef(head->ip6q_next, bucket); | ||||
} | } | ||||
IP6QB_UNLOCK(bucket); | IP6QB_UNLOCK(bucket); | ||||
} | } | ||||
} | |||||
void | |||||
frag6_drain(void) | |||||
{ | |||||
VNET_ITERATOR_DECL(vnet_iter); | |||||
VNET_LIST_RLOCK_NOSLEEP(); | |||||
VNET_FOREACH(vnet_iter) { | |||||
CURVNET_SET(vnet_iter); | |||||
frag6_drain_one(); | |||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
} | } | ||||
VNET_LIST_RUNLOCK_NOSLEEP(); | VNET_LIST_RUNLOCK_NOSLEEP(); | ||||
} | } | ||||
#ifdef VIMAGE | |||||
/* | |||||
* Clear up IPv6 reassembly structures. | |||||
*/ | |||||
void | |||||
frag6_destroy(void) | |||||
{ | |||||
uint32_t bucket; | |||||
frag6_drain_one(); | |||||
V_frag6_on = false; | |||||
for (bucket = 0; bucket < IP6REASS_NHASH; bucket++) { | |||||
KASSERT(V_ip6qb[bucket].count == 0, | |||||
("%s: V_ip6qb[%d] (%p) count not 0 (%d)", __func__, | |||||
bucket, &V_ip6qb[bucket], V_ip6qb[bucket].count)); | |||||
mtx_destroy(&V_ip6qb[bucket].lock); | |||||
} | |||||
} | |||||
#endif | |||||
/* | /* | ||||
* Put an ip fragment on a reassembly chain. | * Put an ip fragment on a reassembly chain. | ||||
* Like insque, but pointers in middle of structure. | * Like insque, but pointers in middle of structure. | ||||
*/ | */ | ||||
static void | static void | ||||
frag6_enq(struct ip6asfrag *af6, struct ip6asfrag *up6, | frag6_enq(struct ip6asfrag *af6, struct ip6asfrag *up6, | ||||
uint32_t bucket __unused) | uint32_t bucket __unused) | ||||
▲ Show 20 Lines • Show All 49 Lines • Show Last 20 Lines |