Changeset View
Standalone View
sys/netpfil/ipfw/ip_fw_nat.c
Show First 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | struct cfg_nat { | ||||
int mode; /* aliasing mode */ | int mode; /* aliasing mode */ | ||||
int redir_cnt; /* number of entry in spool chain */ | int redir_cnt; /* number of entry in spool chain */ | ||||
/* chain of redir instances */ | /* chain of redir instances */ | ||||
LIST_HEAD(redir_chain, cfg_redir) redir_chain; | LIST_HEAD(redir_chain, cfg_redir) redir_chain; | ||||
char if_name[IF_NAMESIZE]; /* interface name */ | char if_name[IF_NAMESIZE]; /* interface name */ | ||||
}; | }; | ||||
static eventhandler_tag ifaddr_event_tag; | static eventhandler_tag ifaddr_event_tag; | ||||
melifaro: Is it `nat_list` or `nat_mgmt` or `nat_ctl` or `nat_priv` or ? | |||||
static void | static void | ||||
Done Inline Actionsalso: why all? Both list and array have all items. Maybe it would be better to consider something like nat_list, nat_idxmap, nat_idxsize etc? melifaro: also: why `all`? Both list and array have all items.
Maybe it would be better to consider… | |||||
Done Inline ActionsNegative values is not only an issue with "size" but also with "id". donner: Negative values is not only an issue with "size" but also with "id".
This is far more serious… | |||||
ifaddr_change(void *arg __unused, struct ifnet *ifp) | ifaddr_change(void *arg __unused, struct ifnet *ifp) | ||||
{ | { | ||||
struct cfg_nat *ptr; | struct cfg_nat *ptr; | ||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
struct ip_fw_chain *chain; | struct ip_fw_chain *chain; | ||||
int i; | |||||
KASSERT(curvnet == ifp->if_vnet, | KASSERT(curvnet == ifp->if_vnet, | ||||
("curvnet(%p) differs from iface vnet(%p)", curvnet, ifp->if_vnet)); | ("curvnet(%p) differs from iface vnet(%p)", curvnet, ifp->if_vnet)); | ||||
if (V_ipfw_vnet_ready == 0 || V_ipfw_nat_ready == 0) | if (V_ipfw_vnet_ready == 0 || V_ipfw_nat_ready == 0) | ||||
return; | return; | ||||
chain = &V_layer3_chain; | chain = &V_layer3_chain; | ||||
IPFW_UH_WLOCK(chain); | IPFW_UH_WLOCK(chain); | ||||
/* Check every nat entry... */ | /* Check every nat entry... */ | ||||
LIST_FOREACH(ptr, &chain->nat, _next) { | for(i = 0; i < chain->nat.len; i++) | ||||
LIST_FOREACH(ptr, &chain->nat.tbl[i], _next) { | |||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
/* ...using nic 'ifp->if_xname' as dynamic alias address. */ | /* ...using nic 'ifp->if_xname' as dynamic alias address. */ | ||||
if (strncmp(ptr->if_name, ifp->if_xname, IF_NAMESIZE) != 0) | if (strncmp(ptr->if_name, ifp->if_xname, IF_NAMESIZE) != 0) | ||||
continue; | continue; | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | ||||
if (ifa->ifa_addr == NULL) | if (ifa->ifa_addr == NULL) | ||||
continue; | continue; | ||||
if (ifa->ifa_addr->sa_family != AF_INET) | if (ifa->ifa_addr->sa_family != AF_INET) | ||||
continue; | continue; | ||||
IPFW_WLOCK(chain); | IPFW_WLOCK(chain); | ||||
ptr->ip = ((struct sockaddr_in *) | ptr->ip = ((struct sockaddr_in *) | ||||
(ifa->ifa_addr))->sin_addr; | (ifa->ifa_addr))->sin_addr; | ||||
LibAliasSetAddress(ptr->lib, ptr->ip); | LibAliasSetAddress(ptr->lib, ptr->ip); | ||||
IPFW_WUNLOCK(chain); | IPFW_WUNLOCK(chain); | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
} | } | ||||
IPFW_UH_WUNLOCK(chain); | IPFW_UH_WUNLOCK(chain); | ||||
} | } | ||||
/* | /* | ||||
* delete the pointers for nat entry ix, or all of them if ix < 0 | * delete the pointers for nat entry ix, or all of them if ix < 0 | ||||
*/ | */ | ||||
static void | static void | ||||
flush_nat_ptrs(struct ip_fw_chain *chain, const int ix) | flush_nat_ptrs(struct ip_fw_chain *chain, const int ix) | ||||
▲ Show 20 Lines • Show All 199 Lines • ▼ Show 20 Lines | ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m) | ||||
if (mcl->m_pkthdr.rcvif == NULL && | if (mcl->m_pkthdr.rcvif == NULL && | ||||
mcl->m_pkthdr.csum_flags & CSUM_DELAY_DATA) | mcl->m_pkthdr.csum_flags & CSUM_DELAY_DATA) | ||||
ldt = 1; | ldt = 1; | ||||
c = mtod(mcl, char *); | c = mtod(mcl, char *); | ||||
/* Check if this is 'global' instance */ | /* Check if this is 'global' instance */ | ||||
if (t == NULL) { | if (t == NULL) { | ||||
int i; | |||||
if (args->flags & IPFW_ARGS_IN) { | if (args->flags & IPFW_ARGS_IN) { | ||||
/* Wrong direction, skip processing */ | /* Wrong direction, skip processing */ | ||||
args->m = mcl; | args->m = mcl; | ||||
return (IP_FW_NAT); | return (IP_FW_NAT); | ||||
} | } | ||||
found = 0; | found = 0; | ||||
chain = &V_layer3_chain; | chain = &V_layer3_chain; | ||||
IPFW_RLOCK_ASSERT(chain); | IPFW_RLOCK_ASSERT(chain); | ||||
/* Check every nat entry... */ | /* Check every nat entry... */ | ||||
LIST_FOREACH(t, &chain->nat, _next) { | for(i = 0; i < chain->nat.len; i++) | ||||
LIST_FOREACH(t, &chain->nat.tbl[i], _next) { | |||||
if ((t->mode & PKT_ALIAS_SKIP_GLOBAL) != 0) | if ((t->mode & PKT_ALIAS_SKIP_GLOBAL) != 0) | ||||
continue; | continue; | ||||
retval = LibAliasOutTry(t->lib, c, | retval = LibAliasOutTry(t->lib, c, | ||||
mcl->m_len + M_TRAILINGSPACE(mcl), 0); | mcl->m_len + M_TRAILINGSPACE(mcl), 0); | ||||
if (retval == PKT_ALIAS_OK) { | if (retval == PKT_ALIAS_OK) { | ||||
/* Nat instance recognises state */ | /* Nat instance recognises state */ | ||||
found = 1; | found = 1; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (found != 1) { | if (found != 1) { | ||||
/* No instance found, return ignore */ | /* No instance found, return ignore */ | ||||
args->m = mcl; | args->m = mcl; | ||||
return (IP_FW_NAT); | return (IP_FW_NAT); | ||||
} | } | ||||
} else { | } else { | ||||
if (args->flags & IPFW_ARGS_IN) | if (args->flags & IPFW_ARGS_IN) | ||||
retval = LibAliasIn(t->lib, c, | retval = LibAliasIn(t->lib, c, | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | if ((mcl->m_pkthdr.csum_flags & CSUM_DELAY_DATA) == 0) { | ||||
mcl->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; | mcl->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; | ||||
} | } | ||||
} | } | ||||
args->m = mcl; | args->m = mcl; | ||||
return (IP_FW_NAT); | return (IP_FW_NAT); | ||||
} | } | ||||
static struct cfg_nat * | static struct cfg_nat * | ||||
lookup_nat(struct nat_list *l, int nat_id) | lookup_nat(struct nat_lists *ls, int nat_id) | ||||
{ | { | ||||
struct cfg_nat *res; | struct cfg_nat *res; | ||||
struct nat_list * l; | |||||
KASSERT(ls->len > 0 && ls->tbl != NULL, "Query an uninitialzed nat chain."); | |||||
l = NAT_TABLE_LIST(*ls, nat_id); | |||||
LIST_FOREACH(res, l, _next) { | LIST_FOREACH(res, l, _next) { | ||||
if (res->id == nat_id) | if (res->id == nat_id) | ||||
break; | break; | ||||
} | } | ||||
return res; | return res; | ||||
} | } | ||||
static struct cfg_nat * | static struct cfg_nat * | ||||
lookup_nat_name(struct nat_list *l, char *name) | lookup_nat_name(struct nat_lists *ls, char *name) | ||||
{ | { | ||||
struct cfg_nat *res; | |||||
int id; | int id; | ||||
char *errptr; | char *errptr; | ||||
id = strtol(name, &errptr, 10); | id = strtol(name, &errptr, 10); | ||||
if (id == 0 || *errptr != '\0') | if (id == 0 || *errptr != '\0') | ||||
return (NULL); | return (NULL); | ||||
LIST_FOREACH(res, l, _next) { | return lookup_nat(ls, id); | ||||
if (res->id == id) | |||||
break; | |||||
} | } | ||||
return (res); | |||||
Done Inline ActionsAvoid code duplication donner: Avoid code duplication | |||||
} | |||||
/* IP_FW3 configuration routines */ | /* IP_FW3 configuration routines */ | ||||
static void | static void | ||||
nat44_config(struct ip_fw_chain *chain, struct nat44_cfg_nat *ucfg) | nat44_config(struct ip_fw_chain *chain, struct nat44_cfg_nat *ucfg) | ||||
{ | { | ||||
struct cfg_nat *ptr, *tcfg; | struct cfg_nat *ptr, *tcfg; | ||||
int gencnt; | int gencnt; | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | nat44_config(struct ip_fw_chain *chain, struct nat44_cfg_nat *ucfg) | ||||
/* Extra check to avoid race with another ipfw_nat_cfg() */ | /* Extra check to avoid race with another ipfw_nat_cfg() */ | ||||
tcfg = NULL; | tcfg = NULL; | ||||
if (gencnt != chain->gencnt) | if (gencnt != chain->gencnt) | ||||
tcfg = lookup_nat_name(&chain->nat, ucfg->name); | tcfg = lookup_nat_name(&chain->nat, ucfg->name); | ||||
IPFW_WLOCK(chain); | IPFW_WLOCK(chain); | ||||
if (tcfg != NULL) | if (tcfg != NULL) | ||||
LIST_REMOVE(tcfg, _next); | LIST_REMOVE(tcfg, _next); | ||||
LIST_INSERT_HEAD(&chain->nat, ptr, _next); | LIST_INSERT_HEAD(NAT_TABLE_LIST(chain->nat, ptr->id), ptr, _next); | ||||
IPFW_WUNLOCK(chain); | IPFW_WUNLOCK(chain); | ||||
chain->gencnt++; | chain->gencnt++; | ||||
IPFW_UH_WUNLOCK(chain); | IPFW_UH_WUNLOCK(chain); | ||||
Done Inline ActionsYou cannot do M_WAITOK while holding non-sleepable lock. To be a bit more specific: nat list is not used in fast path anymore, hence there is no need to acquire IPFW_WLOCK for it, UH_WLOCK is sufficient. Some generic comments: you almost never want to panic in case of memory allocation failure. Typically you either retry a couple of times or return an error to the caller. melifaro: You cannot do M_WAITOK while holding non-sleepable lock.
Also, as this is configuration change… | |||||
Done Inline ActionsM_ZERO is a really good idea. I just had a beautiful panic by configuring an intermediate (go backwards below the largest nat id) unassigend instance. Thank you for the comment. Reading it solved my issue as it happend. donner: M_ZERO is a really good idea. I just had a beautiful panic by configuring an intermediate (go… | |||||
if (tcfg != NULL) | if (tcfg != NULL) | ||||
free_nat_instance(ptr); | free_nat_instance(ptr); | ||||
} | } | ||||
/* | /* | ||||
* Creates/configure nat44 instance | * Creates/configure nat44 instance | ||||
* Data layout (v0)(current): | * Data layout (v0)(current): | ||||
* Request: [ ipfw_obj_header nat44_cfg_nat .. ] | * Request: [ ipfw_obj_header nat44_cfg_nat .. ] | ||||
▲ Show 20 Lines • Show All 203 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
static int | static int | ||||
nat44_list_nat(struct ip_fw_chain *chain, ip_fw3_opheader *op3, | nat44_list_nat(struct ip_fw_chain *chain, ip_fw3_opheader *op3, | ||||
struct sockopt_data *sd) | struct sockopt_data *sd) | ||||
{ | { | ||||
ipfw_obj_lheader *olh; | ipfw_obj_lheader *olh; | ||||
struct nat44_cfg_nat *ucfg; | struct nat44_cfg_nat *ucfg; | ||||
struct cfg_nat *ptr; | struct cfg_nat *ptr; | ||||
int nat_count; | int nat_count, i; | ||||
/* Check minimum header size */ | /* Check minimum header size */ | ||||
if (sd->valsize < sizeof(ipfw_obj_lheader)) | if (sd->valsize < sizeof(ipfw_obj_lheader)) | ||||
return (EINVAL); | return (EINVAL); | ||||
olh = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*olh)); | olh = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*olh)); | ||||
IPFW_UH_RLOCK(chain); | IPFW_UH_RLOCK(chain); | ||||
nat_count = 0; | nat_count = 0; | ||||
LIST_FOREACH(ptr, &chain->nat, _next) | for(i = 0; i < chain->nat.len; i++) | ||||
LIST_FOREACH(ptr, &chain->nat.tbl[i], _next) | |||||
nat_count++; | nat_count++; | ||||
olh->count = nat_count; | olh->count = nat_count; | ||||
olh->objsize = sizeof(struct nat44_cfg_nat); | olh->objsize = sizeof(struct nat44_cfg_nat); | ||||
olh->size = sizeof(*olh) + olh->count * olh->objsize; | olh->size = sizeof(*olh) + olh->count * olh->objsize; | ||||
if (sd->valsize < olh->size) { | if (sd->valsize < olh->size) { | ||||
IPFW_UH_RUNLOCK(chain); | IPFW_UH_RUNLOCK(chain); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
LIST_FOREACH(ptr, &chain->nat, _next) { | for(i = 0; i < chain->nat.len; i++) | ||||
LIST_FOREACH(ptr, &chain->nat.tbl[i], _next) { | |||||
ucfg = (struct nat44_cfg_nat *)ipfw_get_sopt_space(sd, | ucfg = (struct nat44_cfg_nat *)ipfw_get_sopt_space(sd, | ||||
sizeof(*ucfg)); | sizeof(*ucfg)); | ||||
export_nat_cfg(ptr, ucfg); | export_nat_cfg(ptr, ucfg); | ||||
} | } | ||||
IPFW_UH_RUNLOCK(chain); | IPFW_UH_RUNLOCK(chain); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Gets log for given nat instance | * Gets log for given nat instance | ||||
▲ Show 20 Lines • Show All 211 Lines • ▼ Show 20 Lines | ipfw_nat_get_cfg(struct sockopt *sopt) | ||||
struct ip_fw_chain *chain = &V_layer3_chain; | struct ip_fw_chain *chain = &V_layer3_chain; | ||||
struct cfg_nat *n; | struct cfg_nat *n; | ||||
struct cfg_nat_legacy *ucfg; | struct cfg_nat_legacy *ucfg; | ||||
struct cfg_redir *r; | struct cfg_redir *r; | ||||
struct cfg_spool *s; | struct cfg_spool *s; | ||||
struct cfg_redir_legacy *ser_r; | struct cfg_redir_legacy *ser_r; | ||||
struct cfg_spool_legacy *ser_s; | struct cfg_spool_legacy *ser_s; | ||||
char *data; | char *data; | ||||
int gencnt, nat_cnt, len, error; | int gencnt, nat_cnt, len, error, i; | ||||
nat_cnt = 0; | nat_cnt = 0; | ||||
len = sizeof(nat_cnt); | len = sizeof(nat_cnt); | ||||
IPFW_UH_RLOCK(chain); | IPFW_UH_RLOCK(chain); | ||||
retry: | retry: | ||||
gencnt = chain->gencnt; | gencnt = chain->gencnt; | ||||
/* Estimate memory amount */ | /* Estimate memory amount */ | ||||
LIST_FOREACH(n, &chain->nat, _next) { | for(i = 0; i < chain->nat.len; i++) | ||||
LIST_FOREACH(n, &chain->nat.tbl[i], _next) { | |||||
nat_cnt++; | nat_cnt++; | ||||
len += sizeof(struct cfg_nat_legacy); | len += sizeof(struct cfg_nat_legacy); | ||||
LIST_FOREACH(r, &n->redir_chain, _next) { | LIST_FOREACH(r, &n->redir_chain, _next) { | ||||
len += sizeof(struct cfg_redir_legacy); | len += sizeof(struct cfg_redir_legacy); | ||||
LIST_FOREACH(s, &r->spool_chain, _next) | LIST_FOREACH(s, &r->spool_chain, _next) | ||||
len += sizeof(struct cfg_spool_legacy); | len += sizeof(struct cfg_spool_legacy); | ||||
} | } | ||||
} | } | ||||
IPFW_UH_RUNLOCK(chain); | IPFW_UH_RUNLOCK(chain); | ||||
data = malloc(len, M_TEMP, M_WAITOK | M_ZERO); | data = malloc(len, M_TEMP, M_WAITOK | M_ZERO); | ||||
bcopy(&nat_cnt, data, sizeof(nat_cnt)); | bcopy(&nat_cnt, data, sizeof(nat_cnt)); | ||||
nat_cnt = 0; | nat_cnt = 0; | ||||
len = sizeof(nat_cnt); | len = sizeof(nat_cnt); | ||||
IPFW_UH_RLOCK(chain); | IPFW_UH_RLOCK(chain); | ||||
if (gencnt != chain->gencnt) { | if (gencnt != chain->gencnt) { | ||||
free(data, M_TEMP); | free(data, M_TEMP); | ||||
goto retry; | goto retry; | ||||
} | } | ||||
/* Serialize all the data. */ | /* Serialize all the data. */ | ||||
LIST_FOREACH(n, &chain->nat, _next) { | for(i = 0; i < chain->nat.len; i++) | ||||
LIST_FOREACH(n, &chain->nat.tbl[i], _next) { | |||||
ucfg = (struct cfg_nat_legacy *)&data[len]; | ucfg = (struct cfg_nat_legacy *)&data[len]; | ||||
ucfg->id = n->id; | ucfg->id = n->id; | ||||
ucfg->ip = n->ip; | ucfg->ip = n->ip; | ||||
ucfg->redir_cnt = n->redir_cnt; | ucfg->redir_cnt = n->redir_cnt; | ||||
ucfg->mode = n->mode; | ucfg->mode = n->mode; | ||||
strlcpy(ucfg->if_name, n->if_name, sizeof(ucfg->if_name)); | strlcpy(ucfg->if_name, n->if_name, sizeof(ucfg->if_name)); | ||||
len += sizeof(struct cfg_nat_legacy); | len += sizeof(struct cfg_nat_legacy); | ||||
LIST_FOREACH(r, &n->redir_chain, _next) { | LIST_FOREACH(r, &n->redir_chain, _next) { | ||||
ser_r = (struct cfg_redir_legacy *)&data[len]; | ser_r = (struct cfg_redir_legacy *)&data[len]; | ||||
ser_r->mode = r->mode; | ser_r->mode = r->mode; | ||||
ser_r->laddr = r->laddr; | ser_r->laddr = r->laddr; | ||||
ser_r->paddr = r->paddr; | ser_r->paddr = r->paddr; | ||||
ser_r->raddr = r->raddr; | ser_r->raddr = r->raddr; | ||||
ser_r->lport = r->lport; | ser_r->lport = r->lport; | ||||
ser_r->pport = r->pport; | ser_r->pport = r->pport; | ||||
ser_r->rport = r->rport; | ser_r->rport = r->rport; | ||||
ser_r->pport_cnt = r->pport_cnt; | ser_r->pport_cnt = r->pport_cnt; | ||||
ser_r->rport_cnt = r->rport_cnt; | ser_r->rport_cnt = r->rport_cnt; | ||||
ser_r->proto = r->proto; | ser_r->proto = r->proto; | ||||
ser_r->spool_cnt = r->spool_cnt; | ser_r->spool_cnt = r->spool_cnt; | ||||
len += sizeof(struct cfg_redir_legacy); | len += sizeof(struct cfg_redir_legacy); | ||||
LIST_FOREACH(s, &r->spool_chain, _next) { | LIST_FOREACH(s, &r->spool_chain, _next) { | ||||
ser_s = (struct cfg_spool_legacy *)&data[len]; | ser_s = (struct cfg_spool_legacy *)&data[len]; | ||||
ser_s->addr = s->addr; | ser_s->addr = s->addr; | ||||
ser_s->port = s->port; | ser_s->port = s->port; | ||||
len += sizeof(struct cfg_spool_legacy); | len += sizeof(struct cfg_spool_legacy); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
IPFW_UH_RUNLOCK(chain); | IPFW_UH_RUNLOCK(chain); | ||||
error = sooptcopyout(sopt, data, len); | error = sooptcopyout(sopt, data, len); | ||||
free(data, M_TEMP); | free(data, M_TEMP); | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
ipfw_nat_get_log(struct sockopt *sopt) | ipfw_nat_get_log(struct sockopt *sopt) | ||||
{ | { | ||||
uint8_t *data; | uint8_t *data; | ||||
struct cfg_nat *ptr; | struct cfg_nat *ptr; | ||||
int i, size; | int i, k, size; | ||||
struct ip_fw_chain *chain; | struct ip_fw_chain *chain; | ||||
IPFW_RLOCK_TRACKER; | IPFW_RLOCK_TRACKER; | ||||
chain = &V_layer3_chain; | chain = &V_layer3_chain; | ||||
IPFW_RLOCK(chain); | IPFW_RLOCK(chain); | ||||
/* one pass to count, one to copy the data */ | /* one pass to count, one to copy the data */ | ||||
i = 0; | i = 0; | ||||
LIST_FOREACH(ptr, &chain->nat, _next) { | for(k = 0; k < chain->nat.len; k++) | ||||
LIST_FOREACH(ptr, &chain->nat.tbl[k], _next) { | |||||
if (ptr->lib->logDesc == NULL) | if (ptr->lib->logDesc == NULL) | ||||
continue; | continue; | ||||
i++; | i++; | ||||
} | } | ||||
size = i * (LIBALIAS_BUF_SIZE + sizeof(int)); | size = i * (LIBALIAS_BUF_SIZE + sizeof(int)); | ||||
data = malloc(size, M_IPFW, M_NOWAIT | M_ZERO); | data = malloc(size, M_IPFW, M_NOWAIT | M_ZERO); | ||||
if (data == NULL) { | if (data == NULL) { | ||||
IPFW_RUNLOCK(chain); | IPFW_RUNLOCK(chain); | ||||
return (ENOSPC); | return (ENOSPC); | ||||
} | } | ||||
i = 0; | i = 0; | ||||
LIST_FOREACH(ptr, &chain->nat, _next) { | for(k = 0; k < chain->nat.len; k++) | ||||
LIST_FOREACH(ptr, &chain->nat.tbl[k], _next) { | |||||
if (ptr->lib->logDesc == NULL) | if (ptr->lib->logDesc == NULL) | ||||
continue; | continue; | ||||
bcopy(&ptr->id, &data[i], sizeof(int)); | bcopy(&ptr->id, &data[i], sizeof(int)); | ||||
i += sizeof(int); | i += sizeof(int); | ||||
bcopy(ptr->lib->logDesc, &data[i], LIBALIAS_BUF_SIZE); | bcopy(ptr->lib->logDesc, &data[i], LIBALIAS_BUF_SIZE); | ||||
i += LIBALIAS_BUF_SIZE; | i += LIBALIAS_BUF_SIZE; | ||||
} | } | ||||
IPFW_RUNLOCK(chain); | IPFW_RUNLOCK(chain); | ||||
sooptcopyout(sopt, data, size); | sooptcopyout(sopt, data, size); | ||||
free(data, M_IPFW); | free(data, M_IPFW); | ||||
return(0); | return(0); | ||||
} | } | ||||
static int | static int | ||||
vnet_ipfw_nat_init(const void *arg __unused) | vnet_ipfw_nat_init(const void *arg __unused) | ||||
{ | { | ||||
struct ip_fw_chain *chain; | |||||
int i; | |||||
chain = &V_layer3_chain; | |||||
IPFW_WLOCK(chain); | |||||
chain->nat.len = fw_nat_hash; | |||||
chain->nat.tbl = malloc(chain->nat.len * sizeof(*chain->nat.tbl), | |||||
M_IPFW, M_NOWAIT | M_ZERO); | |||||
for(i = 0; i < chain->nat.len; i++) | |||||
LIST_INIT(&chain->nat.tbl[i]); | |||||
V_ipfw_nat_ready = 1; | V_ipfw_nat_ready = 1; | ||||
IPFW_WUNLOCK(chain); | |||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
Done Inline ActionsDo alloc first and then assign to chain under both UH_WLOCK and IPFW_WLOCK. Also, I'm not sure if we're allowed to sleep in vnet_init hooks. Probably yes, but better verify. melifaro: Do alloc first and then assign to chain under both UH_WLOCK and IPFW_WLOCK.
Also, I'm not sure… | |||||
vnet_ipfw_nat_uninit(const void *arg __unused) | vnet_ipfw_nat_uninit(const void *arg __unused) | ||||
{ | { | ||||
struct cfg_nat *ptr, *ptr_temp; | struct cfg_nat *ptr, *ptr_temp; | ||||
struct ip_fw_chain *chain; | struct ip_fw_chain *chain; | ||||
int i; | |||||
chain = &V_layer3_chain; | chain = &V_layer3_chain; | ||||
IPFW_WLOCK(chain); | IPFW_WLOCK(chain); | ||||
V_ipfw_nat_ready = 0; | V_ipfw_nat_ready = 0; | ||||
LIST_FOREACH_SAFE(ptr, &chain->nat, _next, ptr_temp) { | for(i = 0; i < chain->nat.len; i++) | ||||
LIST_FOREACH_SAFE(ptr, &chain->nat.tbl[i], _next, ptr_temp) { | |||||
LIST_REMOVE(ptr, _next); | LIST_REMOVE(ptr, _next); | ||||
free_nat_instance(ptr); | free_nat_instance(ptr); | ||||
} | } | ||||
flush_nat_ptrs(chain, -1 /* flush all */); | flush_nat_ptrs(chain, -1 /* flush all */); | ||||
chain->nat.len = 0; | |||||
free(chain->nat.tbl, M_IPFW); | |||||
IPFW_WUNLOCK(chain); | IPFW_WUNLOCK(chain); | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
ipfw_nat_init(void) | ipfw_nat_init(void) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 75 Lines • Show Last 20 Lines |
Is it nat_list or nat_mgmt or nat_ctl or nat_priv or ?