Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/ipfw/nat64/nat64lsn.h
/*- | /*- | ||||
* Copyright (c) 2015 Yandex LLC | * SPDX-License-Identifier: BSD-2-Clause-FreeBSD | ||||
* | |||||
* Copyright (c) 2015-2019 Yandex LLC | |||||
* Copyright (c) 2015 Alexander V. Chernikov <melifaro@FreeBSD.org> | * Copyright (c) 2015 Alexander V. Chernikov <melifaro@FreeBSD.org> | ||||
* Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org> | * Copyright (c) 2015-2019 Andrey V. Elsukov <ae@FreeBSD.org> | ||||
* All rights reserved. | |||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
* | * | ||||
* 1. Redistributions of source code must retain the above copyright | * 1. Redistributions of source code must retain the above copyright | ||||
* notice, this list of conditions and the following disclaimer. | * notice, this list of conditions and the following disclaimer. | ||||
* 2. Redistributions in binary form must reproduce the above copyright | * 2. Redistributions in binary form must reproduce the above copyright | ||||
Show All 15 Lines | |||||
*/ | */ | ||||
#ifndef _IP_FW_NAT64LSN_H_ | #ifndef _IP_FW_NAT64LSN_H_ | ||||
#define _IP_FW_NAT64LSN_H_ | #define _IP_FW_NAT64LSN_H_ | ||||
#include "ip_fw_nat64.h" | #include "ip_fw_nat64.h" | ||||
#include "nat64_translate.h" | #include "nat64_translate.h" | ||||
#define NAT64_CHUNK_SIZE_BITS 6 /* 64 ports */ | |||||
#define NAT64_CHUNK_SIZE (1 << NAT64_CHUNK_SIZE_BITS) | |||||
#define NAT64_MIN_PORT 1024 | #define NAT64_MIN_PORT 1024 | ||||
#define NAT64_MIN_CHUNK (NAT64_MIN_PORT >> NAT64_CHUNK_SIZE_BITS) | struct nat64lsn_host; | ||||
struct nat64lsn_alias; | |||||
struct st_ptr { | struct nat64lsn_state { | ||||
uint8_t idx; /* index in nh->pg_ptr array. | /* IPv6 host entry keeps hash table to speedup state lookup */ | ||||
* NOTE: it starts from 1. | CK_SLIST_ENTRY(nat64lsn_state) entries; | ||||
*/ | struct nat64lsn_host *host; | ||||
uint8_t off; | |||||
}; | |||||
#define NAT64LSN_MAXPGPTR ((1 << (sizeof(uint8_t) * NBBY)) - 1) | |||||
#define NAT64LSN_PGPTRMASKBITS (sizeof(uint64_t) * NBBY) | |||||
#define NAT64LSN_PGPTRNMASK (roundup(NAT64LSN_MAXPGPTR, \ | |||||
NAT64LSN_PGPTRMASKBITS) / NAT64LSN_PGPTRMASKBITS) | |||||
struct nat64lsn_portgroup; | struct in6_addr ip6_dst; /* Destination IPv6 address */ | ||||
/* sizeof(struct nat64lsn_host) = 64 + 64x2 + 8x8 = 256 bytes */ | |||||
struct nat64lsn_host { | |||||
struct rwlock h_lock; /* Host states lock */ | |||||
struct in6_addr addr; | in_addr_t ip_src; /* Alias IPv4 address */ | ||||
struct nat64lsn_host *next; | in_addr_t ip_dst; /* Destination IPv4 address */ | ||||
uint16_t timestamp; /* Last altered */ | uint16_t dport; /* Destination port */ | ||||
uint16_t hsize; /* ports hash size */ | uint16_t sport; /* Source port */ | ||||
uint16_t pg_used; /* Number of portgroups used */ | |||||
#define NAT64LSN_REMAININGPG 8 /* Number of remaining PG before | uint32_t hval; | ||||
* requesting of new chunk of indexes. | uint32_t flags; /* Internal flags */ | ||||
*/ | uint16_t aport; | ||||
uint16_t pg_allocated; /* Number of portgroups indexes | uint16_t timestamp; /* last used */ | ||||
* allocated. | uint8_t proto; | ||||
*/ | uint8_t _spare[7]; | ||||
#define NAT64LSN_HSIZE 64 | |||||
struct st_ptr phash[NAT64LSN_HSIZE]; /* XXX: hardcoded size */ | |||||
/* | |||||
* PG indexes are stored in chunks with 32 elements. | |||||
* The maximum count is limited to 255 due to st_ptr->idx is uint8_t. | |||||
*/ | |||||
#define NAT64LSN_PGIDX_CHUNK 32 | |||||
#define NAT64LSN_PGNIDX (roundup(NAT64LSN_MAXPGPTR, \ | |||||
NAT64LSN_PGIDX_CHUNK) / NAT64LSN_PGIDX_CHUNK) | |||||
struct nat64lsn_portgroup **pg_ptr[NAT64LSN_PGNIDX]; /* PG indexes */ | |||||
}; | }; | ||||
#define NAT64_RLOCK_ASSERT(h) rw_assert(&(h)->h_lock, RA_RLOCKED) | struct nat64lsn_states_chunk { | ||||
#define NAT64_WLOCK_ASSERT(h) rw_assert(&(h)->h_lock, RA_WLOCKED) | struct nat64lsn_state state[64]; | ||||
}; | |||||
#define NAT64_RLOCK(h) rw_rlock(&(h)->h_lock) | #define ISSET64(mask, bit) ((mask) & ((uint64_t)1 << (bit))) | ||||
#define NAT64_RUNLOCK(h) rw_runlock(&(h)->h_lock) | #define ISSET32(mask, bit) ((mask) & ((uint32_t)1 << (bit))) | ||||
#define NAT64_WLOCK(h) rw_wlock(&(h)->h_lock) | struct nat64lsn_pg { | ||||
#define NAT64_WUNLOCK(h) rw_wunlock(&(h)->h_lock) | CK_SLIST_ENTRY(nat64lsn_pg) entries; | ||||
#define NAT64_LOCK(h) NAT64_WLOCK(h) | |||||
#define NAT64_UNLOCK(h) NAT64_WUNLOCK(h) | |||||
#define NAT64_LOCK_INIT(h) do { \ | |||||
rw_init(&(h)->h_lock, "NAT64 host lock"); \ | |||||
} while (0) | |||||
#define NAT64_LOCK_DESTROY(h) do { \ | uint16_t base_port; | ||||
rw_destroy(&(h)->h_lock); \ | uint16_t timestamp; | ||||
} while (0) | uint8_t proto; | ||||
uint8_t chunks_count; | |||||
uint8_t spare[2]; | |||||
/* Internal proto index */ | union { | ||||
#define NAT_PROTO_TCP 1 | uint64_t freemask; | ||||
#define NAT_PROTO_UDP 2 | uint64_t *freemask_chunk; | ||||
#define NAT_PROTO_ICMP 3 | }; | ||||
union { | |||||
struct nat64lsn_states_chunk *states; | |||||
struct nat64lsn_states_chunk **states_chunk; | |||||
}; | |||||
}; | |||||
#define NAT_MAX_PROTO 4 | struct nat64lsn_pgchunk { | ||||
extern uint8_t nat64lsn_rproto_map[NAT_MAX_PROTO]; | struct nat64lsn_pg *pgptr[32]; | ||||
}; | |||||
VNET_DECLARE(uint16_t, nat64lsn_eid); | struct nat64lsn_aliaslink { | ||||
#define V_nat64lsn_eid VNET(nat64lsn_eid) | CK_SLIST_ENTRY(nat64lsn_aliaslink) alias_entries; | ||||
#define IPFW_TLV_NAT64LSN_NAME IPFW_TLV_EACTION_NAME(V_nat64lsn_eid) | CK_SLIST_ENTRY(nat64lsn_aliaslink) host_entries; | ||||
struct nat64lsn_alias *alias; | |||||
}; | |||||
/* Timestamp macro */ | CK_SLIST_HEAD(nat64lsn_aliaslink_slist, nat64lsn_aliaslink); | ||||
#define _CT ((int)time_uptime % 65536) | CK_SLIST_HEAD(nat64lsn_states_slist, nat64lsn_state); | ||||
#define SET_AGE(x) (x) = _CT | CK_SLIST_HEAD(nat64lsn_hosts_slist, nat64lsn_host); | ||||
#define GET_AGE(x) ((_CT >= (x)) ? _CT - (x) : \ | CK_SLIST_HEAD(nat64lsn_pg_slist, nat64lsn_pg); | ||||
(int)65536 + _CT - (x)) | |||||
#ifdef __LP64__ | struct nat64lsn_alias { | ||||
/* ffsl() is capable of checking 64-bit ints */ | struct nat64lsn_aliaslink_slist hosts; | ||||
#define _FFS64 | struct nat64lsn_pg_slist portgroups; | ||||
#endif | |||||
/* 16 bytes */ | struct mtx lock; | ||||
struct nat64lsn_state { | in_addr_t addr; /* host byte order */ | ||||
union { | uint32_t hosts_count; | ||||
struct { | uint32_t portgroups_count; | ||||
in_addr_t faddr; /* Remote IPv4 address */ | uint32_t tcp_chunkmask; | ||||
uint16_t fport; /* Remote IPv4 port */ | uint32_t udp_chunkmask; | ||||
uint16_t lport; /* Local IPv6 port */ | uint32_t icmp_chunkmask; | ||||
}s; | |||||
uint64_t hkey; | uint32_t tcp_pgidx; | ||||
} u; | uint32_t udp_pgidx; | ||||
uint8_t nat_proto; | uint32_t icmp_pgidx; | ||||
uint8_t flags; | |||||
uint16_t timestamp; | uint16_t timestamp; | ||||
struct st_ptr cur; /* Index of portgroup in nat64lsn_host */ | uint16_t spare; | ||||
struct st_ptr next; /* Next entry index */ | |||||
uint32_t tcp_pgmask[32]; | |||||
uint32_t udp_pgmask[32]; | |||||
uint32_t icmp_pgmask[32]; | |||||
struct nat64lsn_pgchunk *tcp[32]; | |||||
struct nat64lsn_pgchunk *udp[32]; | |||||
struct nat64lsn_pgchunk *icmp[32]; | |||||
/* pointer to PG that can be used for faster state allocation */ | |||||
struct nat64lsn_pg *tcp_pg; | |||||
struct nat64lsn_pg *udp_pg; | |||||
struct nat64lsn_pg *icmp_pg; | |||||
}; | }; | ||||
#define ALIAS_LOCK_INIT(p) \ | |||||
mtx_init(&(p)->lock, "alias_lock", NULL, MTX_DEF) | |||||
#define ALIAS_LOCK_DESTROY(p) mtx_destroy(&(p)->lock) | |||||
#define ALIAS_LOCK(p) mtx_lock(&(p)->lock) | |||||
#define ALIAS_UNLOCK(p) mtx_unlock(&(p)->lock) | |||||
/* | #define NAT64LSN_HSIZE 256 | ||||
* 1024+32 bytes per 64 states, used to store state | #define NAT64LSN_MAX_HSIZE 4096 | ||||
* AND for outside-in state lookup | #define NAT64LSN_HOSTS_HSIZE 1024 | ||||
*/ | |||||
struct nat64lsn_portgroup { | struct nat64lsn_host { | ||||
struct nat64lsn_host *host; /* IPv6 source host info */ | struct in6_addr addr; | ||||
in_addr_t aaddr; /* Alias addr, network format */ | struct nat64lsn_aliaslink_slist aliases; | ||||
uint16_t aport; /* Base port */ | struct nat64lsn_states_slist *states_hash; | ||||
CK_SLIST_ENTRY(nat64lsn_host) entries; | |||||
uint32_t states_count; | |||||
uint32_t hval; | |||||
uint32_t flags; | |||||
#define NAT64LSN_DEADHOST 1 | |||||
#define NAT64LSN_GROWHASH 2 | |||||
uint16_t states_hashsize; | |||||
uint16_t timestamp; | uint16_t timestamp; | ||||
uint8_t nat_proto; | struct mtx lock; | ||||
uint8_t spare[3]; | |||||
uint32_t idx; | |||||
#ifdef _FFS64 | |||||
uint64_t freemask; /* Mask of free entries */ | |||||
#else | |||||
uint32_t freemask[2]; /* Mask of free entries */ | |||||
#endif | |||||
struct nat64lsn_state states[NAT64_CHUNK_SIZE]; /* State storage */ | |||||
}; | }; | ||||
#ifdef _FFS64 | |||||
#define PG_MARK_BUSY_IDX(_pg, _idx) (_pg)->freemask &= ~((uint64_t)1<<(_idx)) | |||||
#define PG_MARK_FREE_IDX(_pg, _idx) (_pg)->freemask |= ((uint64_t)1<<(_idx)) | |||||
#define PG_IS_FREE_IDX(_pg, _idx) ((_pg)->freemask & ((uint64_t)1<<(_idx))) | |||||
#define PG_IS_BUSY_IDX(_pg, _idx) (PG_IS_FREE_IDX(_pg, _idx) == 0) | |||||
#define PG_GET_FREE_IDX(_pg) (ffsll((_pg)->freemask)) | |||||
#define PG_IS_EMPTY(_pg) (((_pg)->freemask + 1) == 0) | |||||
#else | |||||
#define PG_MARK_BUSY_IDX(_pg, _idx) \ | |||||
(_pg)->freemask[(_idx) / 32] &= ~((u_long)1<<((_idx) % 32)) | |||||
#define PG_MARK_FREE_IDX(_pg, _idx) \ | |||||
(_pg)->freemask[(_idx) / 32] |= ((u_long)1<<((_idx) % 32)) | |||||
#define PG_IS_FREE_IDX(_pg, _idx) \ | |||||
((_pg)->freemask[(_idx) / 32] & ((u_long)1<<((_idx) % 32))) | |||||
#define PG_IS_BUSY_IDX(_pg, _idx) (PG_IS_FREE_IDX(_pg, _idx) == 0) | |||||
#define PG_GET_FREE_IDX(_pg) _pg_get_free_idx(_pg) | |||||
#define PG_IS_EMPTY(_pg) \ | |||||
((((_pg)->freemask[0] + 1) == 0 && ((_pg)->freemask[1] + 1) == 0)) | |||||
static inline int | #define HOST_LOCK_INIT(p) \ | ||||
_pg_get_free_idx(const struct nat64lsn_portgroup *pg) | mtx_init(&(p)->lock, "host_lock", NULL, MTX_DEF|MTX_NEW) | ||||
{ | #define HOST_LOCK_DESTROY(p) mtx_destroy(&(p)->lock) | ||||
int i; | #define HOST_LOCK(p) mtx_lock(&(p)->lock) | ||||
#define HOST_UNLOCK(p) mtx_unlock(&(p)->lock) | |||||
if ((i = ffsl(pg->freemask[0])) != 0) | VNET_DECLARE(uint16_t, nat64lsn_eid); | ||||
return (i); | #define V_nat64lsn_eid VNET(nat64lsn_eid) | ||||
if ((i = ffsl(pg->freemask[1])) != 0) | #define IPFW_TLV_NAT64LSN_NAME IPFW_TLV_EACTION_NAME(V_nat64lsn_eid) | ||||
return (i + 32); | |||||
return (0); | |||||
} | |||||
#endif | /* Timestamp macro */ | ||||
#define _CT ((int)time_uptime % 65536) | |||||
#define SET_AGE(x) (x) = _CT | |||||
#define GET_AGE(x) ((_CT >= (x)) ? _CT - (x): (int)65536 + _CT - (x)) | |||||
TAILQ_HEAD(nat64lsn_job_head, nat64lsn_job_item); | STAILQ_HEAD(nat64lsn_job_head, nat64lsn_job_item); | ||||
struct nat64lsn_cfg { | struct nat64lsn_cfg { | ||||
struct named_object no; | struct named_object no; | ||||
struct nat64lsn_portgroup **pg; /* XXX: array of pointers */ | |||||
struct nat64lsn_host **ih; /* Host hash */ | struct nat64lsn_hosts_slist *hosts_hash; | ||||
struct nat64lsn_alias *aliases; /* array of aliases */ | |||||
struct mtx lock; | |||||
uint32_t hosts_hashsize; | |||||
uint32_t hash_seed; | |||||
uint32_t prefix4; /* IPv4 prefix */ | uint32_t prefix4; /* IPv4 prefix */ | ||||
uint32_t pmask4; /* IPv4 prefix mask */ | uint32_t pmask4; /* IPv4 prefix mask */ | ||||
uint32_t ihsize; /* IPv6 host hash size */ | |||||
uint8_t plen4; | uint8_t plen4; | ||||
uint8_t nomatch_verdict;/* What to return to ipfw on no-match */ | uint8_t nomatch_verdict;/* Return value on no-match */ | ||||
uint32_t ihcount; /* Number of items in host hash */ | uint32_t hosts_count; /* Number of items in host hash */ | ||||
int max_chunks; /* Max chunks per client */ | uint32_t states_chunks; /* Number of states chunks per PG */ | ||||
int agg_prefix_len; /* Prefix length to count */ | |||||
int agg_prefix_max; /* Max hosts per agg prefix */ | |||||
uint32_t jmaxlen; /* Max jobqueue length */ | uint32_t jmaxlen; /* Max jobqueue length */ | ||||
uint16_t min_chunk; /* Min port group # to use */ | uint16_t host_delete_delay; /* Stale host delete delay */ | ||||
uint16_t max_chunk; /* Max port group # to use */ | uint16_t pgchunk_delete_delay; | ||||
uint16_t nh_delete_delay; /* Stale host delete delay */ | |||||
uint16_t pg_delete_delay; /* Stale portgroup del delay */ | uint16_t pg_delete_delay; /* Stale portgroup del delay */ | ||||
uint16_t st_syn_ttl; /* TCP syn expire */ | uint16_t st_syn_ttl; /* TCP syn expire */ | ||||
uint16_t st_close_ttl; /* TCP fin expire */ | uint16_t st_close_ttl; /* TCP fin expire */ | ||||
uint16_t st_estab_ttl; /* TCP established expire */ | uint16_t st_estab_ttl; /* TCP established expire */ | ||||
uint16_t st_udp_ttl; /* UDP expire */ | uint16_t st_udp_ttl; /* UDP expire */ | ||||
uint16_t st_icmp_ttl; /* ICMP expire */ | uint16_t st_icmp_ttl; /* ICMP expire */ | ||||
uint32_t protochunks[NAT_MAX_PROTO];/* Number of chunks used */ | |||||
struct nat64_config base; | struct nat64_config base; | ||||
#define NAT64LSN_FLAGSMASK (NAT64_LOG) | #define NAT64LSN_FLAGSMASK (NAT64_LOG | NAT64_ALLOW_PRIVATE) | ||||
#define NAT64LSN_ANYPREFIX 0x00000100 | |||||
struct mtx periodic_lock; | |||||
struct callout periodic; | struct callout periodic; | ||||
struct callout jcallout; | struct callout jcallout; | ||||
struct ip_fw_chain *ch; | |||||
struct vnet *vp; | struct vnet *vp; | ||||
struct nat64lsn_job_head jhead; | struct nat64lsn_job_head jhead; | ||||
int jlen; | int jlen; | ||||
char name[64]; /* Nat instance name */ | char name[64]; /* Nat instance name */ | ||||
}; | }; | ||||
/* CFG_LOCK protects cfg->hosts_hash from modification */ | |||||
#define CFG_LOCK_INIT(p) \ | |||||
mtx_init(&(p)->lock, "cfg_lock", NULL, MTX_DEF) | |||||
#define CFG_LOCK_DESTROY(p) mtx_destroy(&(p)->lock) | |||||
#define CFG_LOCK(p) mtx_lock(&(p)->lock) | |||||
#define CFG_UNLOCK(p) mtx_unlock(&(p)->lock) | |||||
#define CALLOUT_LOCK_INIT(p) \ | |||||
mtx_init(&(p)->periodic_lock, "periodic_lock", NULL, MTX_DEF) | |||||
#define CALLOUT_LOCK_DESTROY(p) mtx_destroy(&(p)->periodic_lock) | |||||
#define CALLOUT_LOCK(p) mtx_lock(&(p)->periodic_lock) | |||||
#define CALLOUT_UNLOCK(p) mtx_unlock(&(p)->periodic_lock) | |||||
struct nat64lsn_cfg *nat64lsn_init_instance(struct ip_fw_chain *ch, | struct nat64lsn_cfg *nat64lsn_init_instance(struct ip_fw_chain *ch, | ||||
size_t numaddr); | in_addr_t prefix, int plen); | ||||
void nat64lsn_destroy_instance(struct nat64lsn_cfg *cfg); | void nat64lsn_destroy_instance(struct nat64lsn_cfg *cfg); | ||||
void nat64lsn_start_instance(struct nat64lsn_cfg *cfg); | void nat64lsn_start_instance(struct nat64lsn_cfg *cfg); | ||||
void nat64lsn_init_internal(void); | void nat64lsn_init_internal(void); | ||||
void nat64lsn_uninit_internal(void); | void nat64lsn_uninit_internal(void); | ||||
int ipfw_nat64lsn(struct ip_fw_chain *ch, struct ip_fw_args *args, | int ipfw_nat64lsn(struct ip_fw_chain *ch, struct ip_fw_args *args, | ||||
ipfw_insn *cmd, int *done); | ipfw_insn *cmd, int *done); | ||||
void | |||||
nat64lsn_dump_state(const struct nat64lsn_cfg *cfg, | |||||
const struct nat64lsn_portgroup *pg, const struct nat64lsn_state *st, | |||||
const char *px, int off); | |||||
/* | |||||
* Portgroup layout | |||||
* addr x nat_proto x port_off | |||||
* | |||||
*/ | |||||
#define _ADDR_PG_PROTO_COUNT (65536 >> NAT64_CHUNK_SIZE_BITS) | |||||
#define _ADDR_PG_COUNT (_ADDR_PG_PROTO_COUNT * NAT_MAX_PROTO) | |||||
#define GET_ADDR_IDX(_cfg, _addr) ((_addr) - ((_cfg)->prefix4)) | |||||
#define __GET_PORTGROUP_IDX(_proto, _port) \ | |||||
((_proto - 1) * _ADDR_PG_PROTO_COUNT + \ | |||||
((_port) >> NAT64_CHUNK_SIZE_BITS)) | |||||
#define _GET_PORTGROUP_IDX(_cfg, _addr, _proto, _port) \ | |||||
GET_ADDR_IDX(_cfg, _addr) * _ADDR_PG_COUNT + \ | |||||
__GET_PORTGROUP_IDX(_proto, _port) | |||||
#define GET_PORTGROUP(_cfg, _addr, _proto, _port) \ | |||||
((_cfg)->pg[_GET_PORTGROUP_IDX(_cfg, _addr, _proto, _port)]) | |||||
#define PORTGROUP_CHUNK(_nh, _idx) \ | |||||
((_nh)->pg_ptr[(_idx)]) | |||||
#define PORTGROUP_BYSIDX(_cfg, _nh, _idx) \ | |||||
(PORTGROUP_CHUNK(_nh, (_idx - 1) / NAT64LSN_PGIDX_CHUNK) \ | |||||
[((_idx) - 1) % NAT64LSN_PGIDX_CHUNK]) | |||||
/* Chained hash table */ | |||||
#define CHT_FIND(_ph, _hsize, _PX, _x, _key) do { \ | |||||
unsigned int _buck = _PX##hash(_key) & (_hsize - 1); \ | |||||
_PX##lock(_ph, _buck); \ | |||||
_x = _PX##first(_ph, _buck); \ | |||||
for ( ; _x != NULL; _x = _PX##next(_x)) { \ | |||||
if (_PX##cmp(_key, _PX##val(_x))) \ | |||||
break; \ | |||||
} \ | |||||
if (_x == NULL) \ | |||||
_PX##unlock(_ph, _buck); \ | |||||
} while(0) | |||||
#define CHT_UNLOCK_BUCK(_ph, _PX, _buck) \ | |||||
_PX##unlock(_ph, _buck); | |||||
#define CHT_UNLOCK_KEY(_ph, _hsize, _PX, _key) do { \ | |||||
unsigned int _buck = _PX##hash(_key) & (_hsize - 1); \ | |||||
_PX##unlock(_ph, _buck); \ | |||||
} while(0) | |||||
#define CHT_INSERT_HEAD(_ph, _hsize, _PX, _i) do { \ | |||||
unsigned int _buck = _PX##hash(_PX##val(_i)) & (_hsize - 1); \ | |||||
_PX##lock(_ph, _buck); \ | |||||
_PX##next(_i) = _PX##first(_ph, _buck); \ | |||||
_PX##first(_ph, _buck) = _i; \ | |||||
_PX##unlock(_ph, _buck); \ | |||||
} while(0) | |||||
#define CHT_REMOVE(_ph, _hsize, _PX, _x, _tmp, _key) do { \ | |||||
unsigned int _buck = _PX##hash(_key) & (_hsize - 1); \ | |||||
_PX##lock(_ph, _buck); \ | |||||
_x = _PX##first(_ph, _buck); \ | |||||
_tmp = NULL; \ | |||||
for ( ; _x != NULL; _tmp = _x, _x = _PX##next(_x)) { \ | |||||
if (_PX##cmp(_key, _PX##val(_x))) \ | |||||
break; \ | |||||
} \ | |||||
if (_x != NULL) { \ | |||||
if (_tmp == NULL) \ | |||||
_PX##first(_ph, _buck) = _PX##next(_x); \ | |||||
else \ | |||||
_PX##next(_tmp) = _PX##next(_x); \ | |||||
} \ | |||||
_PX##unlock(_ph, _buck); \ | |||||
} while(0) | |||||
#define CHT_FOREACH_SAFE(_ph, _hsize, _PX, _x, _tmp, _cb, _arg) do { \ | |||||
for (unsigned int _i = 0; _i < _hsize; _i++) { \ | |||||
_PX##lock(_ph, _i); \ | |||||
_x = _PX##first(_ph, _i); \ | |||||
_tmp = NULL; \ | |||||
for (; _x != NULL; _tmp = _x, _x = _PX##next(_x)) { \ | |||||
if (_cb(_x, _arg) == 0) \ | |||||
continue; \ | |||||
if (_tmp == NULL) \ | |||||
_PX##first(_ph, _i) = _PX##next(_x); \ | |||||
else \ | |||||
_tmp = _PX##next(_x); \ | |||||
} \ | |||||
_PX##unlock(_ph, _i); \ | |||||
} \ | |||||
} while(0) | |||||
#define CHT_RESIZE(_ph, _hsize, _nph, _nhsize, _PX, _x, _y) do { \ | |||||
unsigned int _buck; \ | |||||
for (unsigned int _i = 0; _i < _hsize; _i++) { \ | |||||
_x = _PX##first(_ph, _i); \ | |||||
_y = _x; \ | |||||
while (_y != NULL) { \ | |||||
_buck = _PX##hash(_PX##val(_x)) & (_nhsize - 1);\ | |||||
_y = _PX##next(_x); \ | |||||
_PX##next(_x) = _PX##first(_nph, _buck); \ | |||||
_PX##first(_nph, _buck) = _x; \ | |||||
} \ | |||||
} \ | |||||
} while(0) | |||||
#endif /* _IP_FW_NAT64LSN_H_ */ | #endif /* _IP_FW_NAT64LSN_H_ */ | ||||