summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander V. Chernikov <melifaro@FreeBSD.org>2019-12-19 09:19:27 +0000
committerAlexander V. Chernikov <melifaro@FreeBSD.org>2019-12-19 09:19:27 +0000
commit880266635d8be2c7ed3514bba4bac4c9324febb7 (patch)
treed3f6d3433151081686d268e1511f8279ca7f3156
parent494278bb263de1100afee702b7867a609ba738e5 (diff)
Notes
-rw-r--r--sys/netpfil/ipfw/ip_fw_table.c10
-rw-r--r--sys/netpfil/ipfw/ip_fw_table.h3
-rw-r--r--sys/netpfil/ipfw/ip_fw_table_value.c19
3 files changed, 20 insertions, 12 deletions
diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c
index 7d34977c224f5..0d36d589ba5eb 100644
--- a/sys/netpfil/ipfw/ip_fw_table.c
+++ b/sys/netpfil/ipfw/ip_fw_table.c
@@ -623,7 +623,7 @@ restart:
*
* May release/reacquire UH_WLOCK.
*/
- error = ipfw_link_table_values(ch, &ts);
+ error = ipfw_link_table_values(ch, &ts, flags);
if (error != 0)
goto cleanup;
if (ts.modified != 0)
@@ -654,6 +654,14 @@ restart:
num = 0;
/* check limit before adding */
if ((error = check_table_limit(tc, ptei)) == 0) {
+ /*
+ * It should be safe to insert a record w/o
+ * a properly-linked value if atomicity is
+ * not required.
+ *
+ * If the added item does not have a valid value
+ * index, it would get rejected by ta->add().
+ * */
error = ta->add(tc->astate, KIDX_TO_TI(ch, kidx),
ptei, v, &num);
/* Set status flag to inform userland */
diff --git a/sys/netpfil/ipfw/ip_fw_table.h b/sys/netpfil/ipfw/ip_fw_table.h
index d6578482fb338..ed5e3832adde0 100644
--- a/sys/netpfil/ipfw/ip_fw_table.h
+++ b/sys/netpfil/ipfw/ip_fw_table.h
@@ -168,7 +168,8 @@ struct table_config;
struct tableop_state;
void ipfw_table_value_init(struct ip_fw_chain *ch, int first);
void ipfw_table_value_destroy(struct ip_fw_chain *ch, int last);
-int ipfw_link_table_values(struct ip_fw_chain *ch, struct tableop_state *ts);
+int ipfw_link_table_values(struct ip_fw_chain *ch, struct tableop_state *ts,
+ uint8_t flags);
void ipfw_garbage_table_values(struct ip_fw_chain *ch, struct table_config *tc,
struct tentry_info *tei, uint32_t count, int rollback);
void ipfw_import_table_value_v1(ipfw_table_value *iv);
diff --git a/sys/netpfil/ipfw/ip_fw_table_value.c b/sys/netpfil/ipfw/ip_fw_table_value.c
index e92a5a979fb80..9e1055235b2fb 100644
--- a/sys/netpfil/ipfw/ip_fw_table_value.c
+++ b/sys/netpfil/ipfw/ip_fw_table_value.c
@@ -363,7 +363,7 @@ rollback_table_values(struct tableop_state *ts)
*/
static int
alloc_table_vidx(struct ip_fw_chain *ch, struct tableop_state *ts,
- struct namedobj_instance *vi, uint16_t *pvidx)
+ struct namedobj_instance *vi, uint16_t *pvidx, uint8_t flags)
{
int error, vlimit;
uint16_t vidx;
@@ -384,16 +384,13 @@ alloc_table_vidx(struct ip_fw_chain *ch, struct tableop_state *ts,
}
vlimit = ts->ta->vlimit;
- if (vlimit != 0 && vidx >= vlimit) {
+ if (vlimit != 0 && vidx >= vlimit && !(flags & IPFW_CTF_ATOMIC)) {
/*
* Algorithm is not able to store given index.
* We have to rollback state, start using
* per-table value array or return error
* if we're already using it.
- *
- * TODO: do not rollback state if
- * atomicity is not required.
*/
if (ts->vshared != 0) {
/* shared -> per-table */
@@ -426,9 +423,10 @@ ipfw_garbage_table_values(struct ip_fw_chain *ch, struct table_config *tc,
* either (1) we are successful / partially successful,
* in that case we need
* * to ignore ADDED entries values
- * * rollback every other values (either UPDATED since
- * old value has been stored there, or some failure like
- * EXISTS or LIMIT or simply "ignored" case.
+ * * rollback every other values if atomicity is not
+ * * required (either UPDATED since old value has been
+ * stored there, or some failure like EXISTS or LIMIT
+ * or simply "ignored" case.
*
* (2): atomic rollback of partially successful operation
* in that case we simply need to unref all entries.
@@ -473,7 +471,8 @@ ipfw_garbage_table_values(struct ip_fw_chain *ch, struct table_config *tc,
* Success: return 0.
*/
int
-ipfw_link_table_values(struct ip_fw_chain *ch, struct tableop_state *ts)
+ipfw_link_table_values(struct ip_fw_chain *ch, struct tableop_state *ts,
+ uint8_t flags)
{
int error, i, found;
struct namedobj_instance *vi;
@@ -577,7 +576,7 @@ ipfw_link_table_values(struct ip_fw_chain *ch, struct tableop_state *ts)
}
/* May perform UH unlock/lock */
- error = alloc_table_vidx(ch, ts, vi, &vidx);
+ error = alloc_table_vidx(ch, ts, vi, &vidx, flags);
if (error != 0) {
ts->opstate.func(ts->tc, &ts->opstate);
return (error);