Re: [RFC v2] nf_tables: Transaction API proposal

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Pablo,

About the commit, you are right Pablo: only one at a time, this is mandatory.
I missed the point on my first proposal.
To do so I introduced a mutex. If it's already locked it return -EAGAIN, so it's up
to the client to retry. I guess this is anyway not going to happen very often.
I don't know if we could get something better here, at least now no client can
lock up the other indefinitely, it enables per-client transaction...
Races may still occur if we try to support simultaneous transactions.

client 1
start transaction                 client 2
add rule X1, table Y1, chain Z1   start transaction
... more rule updates             delete all rules in table Y1, chain Z1
... more rule updates             commit

1 line is missing
notifications (other rules deleted) notifications (ok chain Z1 has no rules)

commit

and:
notifications (own rules added) notifications (hum, new rules added. ok)

client 2 will see rules in table Y1, chain Z1 after its commit but
will not know why. However, if it hits -EBUSY because another client
was performing a transaction, it can retry a fresh update with the
current rule-set, not based on the stale one.

Your example is wrong: it is valid, as it would be also in a unique transaction based approach as your are proposing:
client 2 - start / delete all rules / commit
client 2 - notifications: see no rules
client 1 - start / add rules / commit
client 2 - notifications: see rules again.
=> exact same result, which is a legitimate one in both case.

As long as transaction n cannot mess up with any other transaction m, there is definitely no race condition between transactions. It would be a race condition in your example if client 2 can delete the rule updates of client 1. But this must not be the case, and that's also why we should not dump the non-active rules to anybody BUT to the owner.
--> As long as a rule is not active: it does not exist but in a transaction.
With transaction you never know the result as long as it did not end up to a commit, so there is no point to tell everybody about it before.

I still think it's really wrong to propose unique transaction approach: if the client is bogus (and they will! ^^) and never commit/abort its transaction, it locks all others.

Anyway, there are issues in my proposal I agree: it's an RFC not a patch.
For instance:
In your proposal, as long a the transaction is "going on" no other manipulation can be done to the rule base. It's wrong because it locks all other clients (even on untouched tables/chains by the transaction) but it "fixes" the case where non-transaction based manipulation could be done: these are locked as well. And it does that to all manipulations, whatever table/chain is in the game.

--> in my RFC, getting non-transaction based manipulation could lead to troubles: what if a non-atomic manipulation removes all rules and the chain itself, where a transaction was working? (yes that one is a valid race condition ;-) ) Here we could fix it, if there is a transaction going on in that specific chain, either by killing the entire transaction and notifying its owner (I would prefer that one), or like you are doing: return ebusy. But I don't like the idea of a transaction being able to lock anyone (I repeat myself, sorry). To me, non-transaction (so non-atomic) based manipulation should always have the highest priority versus any transactions, unless a commit is going on of course. We have to maintain this difference of transaction and non-transaction based manipulation.

We have to think properly about that: how we store the transaction in an efficient way so it would not be a performance issue to look-up for a table/chain in transaction list. Things like that. I am sure we can get something still simple and reliable from API point of view but way more flexible than your approach. And with nobody being able to lock this subsystem. We are not in a hurry anyway.

+
+static void nf_tables_transaction_remove(struct nft_transaction *transaction)
+{
+	nfnl_lock();
Won't work. nfnl_lock is already held when calling this function. Note
that all nfnetlink functions are currently protected by nfnl_lock.

Indeed, did that patch too quickly. Loosely looked at nf_tables_expressions.

+	/* Check if a commit is on-going */
+	if (mutex_trylock(&nf_tables_commit_lock))
+		return -EAGAIN;
You should use -EBUSY. -EAGAIN is used internally by nfnetlink to
retry on module autoload.

Ok good to know.

Br,

Tomasz
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux