In pfe_filter.c there is a call to DIOCXCOMMIT ioctl to commit pf rules generated by relayd but in pfe_filter.c:551 there is only a warning about the transaction failing. If transaction_commit fails with EBUSY relayd thinks that the pf rules has been committed but they are not; at this moment relayd is desyncronized. With this patch we try to recommit pf rules another time if DIOCXCOMMIT fails with EBUSY, otherwise we fatalx. I think that it is better to exit the process instead of having a relayd process desynchronized. Opininions ? Better ideas on how to workaround this problem ? Cheers Giovanni
Index: pfe_filter.c =================================================================== RCS file: /cvs/src/usr.sbin/relayd/pfe_filter.c,v retrieving revision 1.52 diff -u -p -r1.52 pfe_filter.c --- pfe_filter.c 19 Oct 2012 16:49:50 -0000 1.52 +++ pfe_filter.c 18 Mar 2013 08:06:42 -0000 @@ -354,9 +354,22 @@ transaction_init(struct relayd *env, con int transaction_commit(struct relayd *env) { +int timer = 0; + if (ioctl(env->sc_pf->dev, DIOCXCOMMIT, - &env->sc_pf->pft) == -1) - return (-1); + &env->sc_pf->pft) == -1) { + /* + * if DIOCXCOMMIT fails with EBUSY retry after some milliseconds + */ + if(errno == EBUSY) { + timer = arc4random_uniform(10000); + usleep(timer); + if (ioctl(env->sc_pf->dev, DIOCXCOMMIT, + &env->sc_pf->pft) == -1) + return (-1); + } + return (0); + } return (0); } @@ -509,7 +522,7 @@ sync_ruleset(struct relayd *env, struct log_debug("%s: rule added to anchor \"%s\"", __func__, anchor); } if (transaction_commit(env) == -1) - log_warn("%s: add rules transaction failed", __func__); + fatalx("add rules transaction failed"); return; toolong: