diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c --- a/sys/netpfil/ipfw/ip_fw2.c +++ b/sys/netpfil/ipfw/ip_fw2.c @@ -1242,7 +1242,7 @@ * whose version is written in f->cached_id * (horrible hacks to avoid changing the ABI). */ - if (num != IP_FW_TARG && f->cached_id == chain->id) + if (num != IP_FW_TARG && atomic_load_32(&f->cached_id) == chain->id) f_pos = f->cached_pos; else { int i = IP_FW_ARG_TABLEARG(chain, num, skipto); @@ -1255,8 +1255,13 @@ f_pos = ipfw_find_rule(chain, i, 0); /* update the cache */ if (num != IP_FW_TARG) { - f->cached_id = chain->id; - f->cached_pos = f_pos; + /* + * We don't care about thread synchronization there. + * Even if multiple threads update the cache simultaneously, + * we still get the correct cache value. + */ + f->cached_pos = f_pos; + atomic_store_32(&f->cached_id, chain->id); } } diff --git a/sys/netpfil/ipfw/ip_fw_private.h b/sys/netpfil/ipfw/ip_fw_private.h --- a/sys/netpfil/ipfw/ip_fw_private.h +++ b/sys/netpfil/ipfw/ip_fw_private.h @@ -275,7 +275,7 @@ counter_u64_t cntr; /* Pointer to rule counters */ uint32_t timestamp; /* tv_sec of last match */ uint32_t id; /* rule id */ - uint32_t cached_id; /* used by jump_fast */ + volatile uint32_t cached_id; /* used by jump_fast */ uint32_t cached_pos; /* used by jump_fast */ uint32_t refcnt; /* number of references */