Add IP_FW_DUMP_SOPTCODES sopt to be able to determine

which opcodes are currently available in kernel.
This commit is contained in:
Alexander V. Chernikov 2014-10-08 11:12:14 +00:00
parent eadf3b965c
commit be8bc45790
3 changed files with 72 additions and 1 deletions

View File

@ -104,6 +104,8 @@ typedef struct _ip_fw3_opheader {
#define IP_FW_NAT44_LIST_NAT 114 /* List all NAT44 instances */
#define IP_FW_NAT44_XGETLOG 115 /* Get log from NAT44 instance */
#define IP_FW_DUMP_SOPTCODES 116 /* Dump available sopts/versions */
/*
* The kernel representation of ipfw rules is made of a list of
* 'instructions' (for all practical purposes equivalent to BPF
@ -991,4 +993,12 @@ typedef struct _ipfw_range_header {
ipfw_range_tlv range;
} ipfw_range_header;
typedef struct _ipfw_sopt_info {
uint16_t opcode;
uint8_t version;
uint8_t dir;
uint8_t spare;
uint64_t refcnt;
} ipfw_sopt_info;
#endif /* _IPFW2_H */

View File

@ -115,6 +115,8 @@ static int move_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
struct sockopt_data *sd);
static int manage_sets(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
struct sockopt_data *sd);
static int dump_soptcodes(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
struct sockopt_data *sd);
/* ctl3 handler data */
struct mtx ctl3_lock;
@ -141,6 +143,7 @@ static struct ipfw_sopt_handler scodes[] = {
{ IP_FW_SET_SWAP, 0, HDIR_SET, manage_sets },
{ IP_FW_SET_MOVE, 0, HDIR_SET, manage_sets },
{ IP_FW_SET_ENABLE, 0, HDIR_SET, manage_sets },
{ IP_FW_DUMP_SOPTCODES, 0, HDIR_GET, dump_soptcodes },
};
/*
@ -2284,6 +2287,57 @@ add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
return (error);
}
/*
* Lists all sopts currently registered.
* Data layout (v0)(current):
* Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size
* Reply: [ ipfw_obj_lheader ipfw_sopt_info x N ]
*
* Returns 0 on success
*/
static int
dump_soptcodes(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
struct sockopt_data *sd)
{
struct _ipfw_obj_lheader *olh;
ipfw_sopt_info *i;
struct ipfw_sopt_handler *sh;
uint32_t count, n, size;
olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
if (olh == NULL)
return (EINVAL);
if (sd->valsize < olh->size)
return (EINVAL);
CTL3_LOCK();
count = ctl3_hsize;
size = count * sizeof(ipfw_sopt_info) + sizeof(ipfw_obj_lheader);
/* Fill in header regadless of buffer size */
olh->count = count;
olh->objsize = sizeof(ipfw_sopt_info);
if (size > olh->size) {
olh->size = size;
CTL3_UNLOCK();
return (ENOMEM);
}
olh->size = size;
for (n = 1; n <= count; n++) {
i = (ipfw_sopt_info *)ipfw_get_sopt_space(sd, sizeof(*i));
KASSERT(i != 0, ("previously checked buffer is not enough"));
sh = &ctl3_handlers[n];
i->opcode = sh->opcode;
i->version = sh->version;
i->refcnt = sh->refcnt;
}
CTL3_UNLOCK();
return (0);
}
/*
* Compares two sopt handlers (code, version and handler ptr).
* Used both as qsort() and bsearch().

View File

@ -547,8 +547,15 @@ ipfw_link_table_values(struct ip_fw_chain *ch, struct tableop_state *ts)
IPFW_UH_WLOCK(ch);
tc_unref(tc);
del_toperation_state(ch, ts);
if (ts->modified != 0)
if (ts->modified != 0) {
/*
* In general, we should free all state/indexes here
* and return. However, we keep allocated state instead
* to ensure we achieve some progress on each restart.
*/
return (0);
}
KASSERT(pval == ch->tablestate, ("resize_storage() notify failure"));