From 05ab1ef64ebe48e68a7a3975c1f06e2ced5460a9 Mon Sep 17 00:00:00 2001 From: "Andrey V. Elsukov" Date: Fri, 24 May 2019 11:06:24 +0000 Subject: [PATCH] Add `missing` and `or-flush` options to "ipfw table create" command to simplify firewall reloading. The `missing` option suppresses EEXIST error code, but does check that existing table has the same parameters as new one. The `or-flush` option implies `missing` option and additionally does flush for table if it is already exist. Submitted by: lev MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D18339 --- sbin/ipfw/ipfw.8 | 11 +++++++++-- sbin/ipfw/ipfw2.h | 3 +++ sbin/ipfw/tables.c | 38 +++++++++++++++++++++++++++++++++----- 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index cf0c3affe029..fcba4a4b03f2 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -1,7 +1,7 @@ .\" .\" $FreeBSD$ .\" -.Dd April 21, 2019 +.Dd May 24, 2019 .Dt IPFW 8 .Os .Sh NAME @@ -2138,7 +2138,7 @@ The following creation options are supported: .Bl -tag -width indent .It Ar create-options : Ar create-option | create-options .It Ar create-option : Cm type Ar table-type | Cm valtype Ar value-mask | Cm algo Ar algo-desc | -.Cm limit Ar number | Cm locked +.Cm limit Ar number | Cm locked | Cm missing | Cm or-flush .It Cm type Table key type. .It Cm valtype @@ -2149,6 +2149,13 @@ Table algorithm to use (see below). Maximum number of items that may be inserted into table. .It Cm locked Restrict any table modifications. +.It Cm missing +Do not fail if table already exists and has exactly same options as new one. +.It Cm or-flush +Flush existing table with same name instead of returning error. +Implies +.Cm missing +so existing table must be compatible with new one. .El .Pp Some of these options may be modified later via diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h index 2b562734d15f..659285366c2c 100644 --- a/sbin/ipfw/ipfw2.h +++ b/sbin/ipfw/ipfw2.h @@ -264,6 +264,9 @@ enum tokens { TOK_UNLOCK, TOK_VLIST, TOK_OLIST, + TOK_MISSING, + TOK_ORFLUSH, + TOK_OPTIONAL, /* NAT64 tokens */ TOK_NAT64STL, diff --git a/sbin/ipfw/tables.c b/sbin/ipfw/tables.c index 3fa806348a27..4be24210d4f0 100644 --- a/sbin/ipfw/tables.c +++ b/sbin/ipfw/tables.c @@ -327,6 +327,8 @@ static struct _s_x tablenewcmds[] = { { "algo", TOK_ALGO }, { "limit", TOK_LIMIT }, { "locked", TOK_LOCK }, + { "missing", TOK_MISSING }, + { "or-flush", TOK_ORFLUSH }, { NULL, 0 } }; @@ -389,19 +391,19 @@ table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags) * Creates new table * * ipfw table NAME create [ type { addr | iface | number | flow } ] - * [ algo algoname ] + * [ algo algoname ] [missing] [or-flush] */ static void table_create(ipfw_obj_header *oh, int ac, char *av[]) { - ipfw_xtable_info xi; - int error, tcmd, val; + ipfw_xtable_info xi, xie; + int error, missing, orflush, tcmd, val; uint32_t fset, fclear; char *e, *p; char tbuf[128]; + missing = orflush = 0; memset(&xi, 0, sizeof(xi)); - while (ac > 0) { tcmd = get_token(tablenewcmds, *av, "option"); ac--; av++; @@ -457,6 +459,12 @@ table_create(ipfw_obj_header *oh, int ac, char *av[]) case TOK_LOCK: xi.flags |= IPFW_TGFLAGS_LOCKED; break; + case TOK_ORFLUSH: + orflush = 1; + /* FALLTHROUGH */ + case TOK_MISSING: + missing = 1; + break; } } @@ -466,8 +474,28 @@ table_create(ipfw_obj_header *oh, int ac, char *av[]) if (xi.vmask == 0) xi.vmask = IPFW_VTYPE_LEGACY; - if ((error = table_do_create(oh, &xi)) != 0) + error = table_do_create(oh, &xi); + + if (error == 0) + return; + + if (errno != EEXIST || missing == 0) err(EX_OSERR, "Table creation failed"); + + /* Check that existing table is the same we are trying to create */ + if (table_get_info(oh, &xie) != 0) + err(EX_OSERR, "Existing table check failed"); + + if (xi.limit != xie.limit || xi.type != xie.type || + xi.tflags != xie.tflags || xi.vmask != xie.vmask || ( + xi.algoname[0] != '\0' && strcmp(xi.algoname, + xie.algoname) != 0) || xi.flags != xie.flags) + errx(EX_DATAERR, "The existing table is not compatible " + "with one you are creating."); + + /* Flush existing table if instructed to do so */ + if (orflush != 0 && table_flush(oh) != 0) + err(EX_OSERR, "Table flush on creation failed"); } /*