FreeBSD/sys/netpfil/ipfw/ip_fw_table.c
/*
 * Flushes given table.
 *
 * Function create new table instance with the same
 * parameters, swaps it with old one and
 * flushes state without holding runtime WLOCK.
 *
 * Returns 0 on success.
 */
Flushes given table.
Function create new table instance with the same
parameters, swaps it with old one and
flushes state without holding runtime WLOCK.

Returns 0 on success.
Flushes given table . Function create new table instance with the same parameters swaps it with old one and flushes state without holding runtime WLOCK . Returns 0 on success .
int
flush_table(struct ip_fw_chain *ch, struct tid_info *ti)
{
	struct namedobj_instance *ni;
	struct table_config *tc;
	struct table_algo *ta;
	struct table_info ti_old, ti_new, *tablestate;
	void *astate_old, *astate_new;
	char algostate[64], *pstate;
	struct tableop_state ts;
	int error, need_gc;
	uint16_t kidx;
	uint8_t tflags;
	IPFW_UH_WLOCK(ch);
	ni = CHAIN_TO_NI(ch);
	if ((tc = find_table(ni, ti)) == NULL) {
		IPFW_UH_WUNLOCK(ch);
		return (ESRCH);
	}
	need_gc = 0;
	astate_new = NULL;
	memset(&ti_new, 0, sizeof(ti_new));
restart:
	memset(&ts, 0, sizeof(ts));
	ts.opstate.func = restart_flush;
	ts.tc = tc;
	ta = tc->ta;
	if ((ta->flags & TA_FLAG_READONLY) != 0) {
		IPFW_UH_WUNLOCK(ch);
		return (EACCES);
	}
	if (ta->print_config != NULL) {
		ta->print_config(tc->astate, KIDX_TO_TI(ch, tc->no.kidx),
		    algostate, sizeof(algostate));
		pstate = algostate;
	} else
		pstate = NULL;
	tflags = tc->tflags;
	tc->no.refcnt++;
	add_toperation_state(ch, &ts);
	IPFW_UH_WUNLOCK(ch);
	if (need_gc != 0) {
		ta->destroy(astate_new, &ti_new);
		need_gc = 0;
	}
	memset(&ti_new, 0, sizeof(struct table_info));
	error = ta->init(ch, &astate_new, &ti_new, pstate, tflags);
	IPFW_UH_WLOCK(ch);
	tc->no.refcnt--;
	del_toperation_state(ch, &ts);
	if (error != 0) {
		IPFW_UH_WUNLOCK(ch);
		return (error);
	}
	if (ts.modified != 0) {
		need_gc = 1;
		goto restart;
	}
	ni = CHAIN_TO_NI(ch);
	kidx = tc->no.kidx;
	tablestate = (struct table_info *)ch->tablestate;
	IPFW_WLOCK(ch);
	ti_old = tablestate[kidx];
	tablestate[kidx] = ti_new;
	IPFW_WUNLOCK(ch);
	astate_old = tc->astate;
	tc->astate = astate_new;
	tc->ti_copy = ti_new;
	tc->count = 0;
	if (ta->change_ti != NULL)
		ta->change_ti(tc->astate, &tablestate[kidx]);
	ipfw_unref_table_values(ch, tc, ta, astate_old, &ti_old);
	IPFW_UH_WUNLOCK(ch);
	ta->destroy(astate_old, &ti_old);
	return (0);
}
int flush_table ( struct ip_fw_chain * ch , struct tid_info * ti ) { struct namedobj_instance * ni ; struct table_config * tc ; struct table_algo * ta ; struct table_info ti_old , ti_new , * tablestate ; void * astate_old , * astate_new ; char algostate [ 64 ] , * pstate ; struct tableop_state ts ; int error , need_gc ; uint16_t kidx ; uint8_t tflags ; IPFW_UH_WLOCK ( ch ) ; ni = CHAIN_TO_NI ( ch ) ; if ( ( tc = find_table ( ni , ti ) ) == NULL ) { IPFW_UH_WUNLOCK ( ch ) ; return ( ESRCH ) ; } need_gc = 0 ; astate_new = NULL ; memset ( & ti_new , 0 , sizeof ( ti_new ) ) ; restart : memset ( & ts , 0 , sizeof ( ts ) ) ; ts . opstate . func = restart_flush ; ts . tc = tc ; ta = tc -> ta ; if ( ( ta -> flags & TA_FLAG_READONLY ) != 0 ) { IPFW_UH_WUNLOCK ( ch ) ; return ( EACCES ) ; } if ( ta -> print_config != NULL ) { ta -> print_config ( tc -> astate , KIDX_TO_TI ( ch , tc -> no . kidx ) , algostate , sizeof ( algostate ) ) ; pstate = algostate ; } else pstate = NULL ; tflags = tc -> tflags ; tc -> no . refcnt ++ ; add_toperation_state ( ch , & ts ) ; IPFW_UH_WUNLOCK ( ch ) ; if ( need_gc != 0 ) { ta -> destroy ( astate_new , & ti_new ) ; need_gc = 0 ; } memset ( & ti_new , 0 , sizeof ( struct table_info ) ) ; error = ta -> init ( ch , & astate_new , & ti_new , pstate , tflags ) ; IPFW_UH_WLOCK ( ch ) ; tc -> no . refcnt -- ; del_toperation_state ( ch , & ts ) ; if ( error != 0 ) { IPFW_UH_WUNLOCK ( ch ) ; return ( error ) ; } if ( ts . modified != 0 ) { need_gc = 1 ; goto restart ; } ni = CHAIN_TO_NI ( ch ) ; kidx = tc -> no . kidx ; tablestate = ( struct table_info * ) ch -> tablestate ; IPFW_WLOCK ( ch ) ; ti_old = tablestate [ kidx ] ; tablestate [ kidx ] = ti_new ; IPFW_WUNLOCK ( ch ) ; astate_old = tc -> astate ; tc -> astate = astate_new ; tc -> ti_copy = ti_new ; tc -> count = 0 ; if ( ta -> change_ti != NULL ) ta -> change_ti ( tc -> astate , & tablestate [ kidx ] ) ; ipfw_unref_table_values ( ch , tc , ta , astate_old , & ti_old ) ; IPFW_UH_WUNLOCK ( ch ) ; ta -> destroy ( astate_old , & ti_old ) ; return ( 0 ) ; }
Flushes given table.
Flushes given table .
/*
	 * Stage 1: save table algorithm.
	 * Reference found table to ensure it won't disappear.
	 */ /* Set up swap handler */ /* Do not flush readonly tables */ /* Save startup algo parameters */ /*
	 * Stage 1.5: if this is not the first attempt, destroy previous state
	 */ /*
	 * Stage 2: allocate new table instance using same algo.
	 */ /*
	 * Stage 3: swap old state pointers with newly-allocated ones.
	 * Decrease refcount.
	 */ /*
	 * Restart operation if table swap has happened:
	 * even if algo may be the same, algo init parameters
	 * may change. Restart operation instead of doing
	 * complex checks.
	 */ /* Delay destroying data since we're holding UH lock */ /* Notify algo on real @ti address */ /*
	 * Stage 4: unref values.
	 */ /*
	 * Stage 5: perform real flush/destroy.
	 */