diff options
author | melifaro <melifaro@FreeBSD.org> | 2014-08-03 21:37:12 +0000 |
---|---|---|
committer | melifaro <melifaro@FreeBSD.org> | 2014-08-03 21:37:12 +0000 |
commit | 42eca8abfbfe2a7615fc4450f0943a0f09a75429 (patch) | |
tree | f7035ed64afbdd233982d5a7b86d95577128ca94 /sbin/ipfw/tables.c | |
parent | becbec7be8fc96c65142c29024e62335a3e0a95c (diff) | |
download | FreeBSD-src-42eca8abfbfe2a7615fc4450f0943a0f09a75429.zip FreeBSD-src-42eca8abfbfe2a7615fc4450f0943a0f09a75429.tar.gz |
Implement atomic ipfw table swap.
Kernel changes:
* Add opcode IP_FW_TABLE_XSWAP
* Add support for swapping 2 tables with the same type/ftype/vtype.
* Make skipto cache init after ipfw locks init.
Userland changes:
* Add "table X swap Y" command.
Diffstat (limited to 'sbin/ipfw/tables.c')
-rw-r--r-- | sbin/ipfw/tables.c | 50 |
1 files changed, 49 insertions, 1 deletions
diff --git a/sbin/ipfw/tables.c b/sbin/ipfw/tables.c index 06aab5e..bfa04d0 100644 --- a/sbin/ipfw/tables.c +++ b/sbin/ipfw/tables.c @@ -56,6 +56,8 @@ static int table_destroy(ipfw_obj_header *oh); static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i); static void table_create(ipfw_obj_header *oh, int ac, char *av[]); static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]); +static int table_do_swap(ipfw_obj_header *oh, char *second); +static int table_swap(ipfw_obj_header *oh, char *second); static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i); static int table_show_info(ipfw_xtable_info *i, void *arg); static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, @@ -96,10 +98,11 @@ static struct _s_x tablevaltypes[] = { static struct _s_x tablecmds[] = { { "add", TOK_ADD }, - { "create", TOK_CREATE }, { "delete", TOK_DEL }, + { "create", TOK_CREATE }, { "destroy", TOK_DESTROY }, { "flush", TOK_FLUSH }, + { "swap", TOK_SWAP }, { "info", TOK_INFO }, { "detail", TOK_DETAIL }, { "list", TOK_LIST }, @@ -204,6 +207,11 @@ ipfw_table_handler(int ac, char *av[]) err(EX_OSERR, "failed to flush tables list"); } break; + case TOK_SWAP: + ac--; av++; + NEED1("second table name required"); + table_swap(&oh, *av); + break; case TOK_DETAIL: case TOK_INFO: arg = (tcmd == TOK_DETAIL) ? (void *)1 : NULL; @@ -450,6 +458,46 @@ table_flush(ipfw_obj_header *oh) return (0); } +static int +table_do_swap(ipfw_obj_header *oh, char *second) +{ + char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ntlv)]; + int error; + + memset(tbuf, 0, sizeof(tbuf)); + memcpy(tbuf, oh, sizeof(*oh)); + oh = (ipfw_obj_header *)tbuf; + table_fill_ntlv((ipfw_obj_ntlv *)(oh + 1), second, oh->ntlv.set, 1); + + error = do_set3(IP_FW_TABLE_XSWAP, &oh->opheader, sizeof(tbuf)); + + return (error); +} + +/* + * Swaps given table with @second one. + */ +static int +table_swap(ipfw_obj_header *oh, char *second) +{ + int error; + + if (table_check_name(second) != 0) + errx(EX_USAGE, "table name %s is invalid", second); + + error = table_do_swap(oh, second); + + switch (error) { + case EINVAL: + errx(EX_USAGE, "Unable to swap table: check types"); + case EFBIG: + errx(EX_USAGE, "Unable to swap table: check limits"); + } + + return (0); +} + + /* * Retrieves table in given table specified by @oh->ntlv. * it inside @i. |