.. | .. |
---|
76 | 76 | switch (priv->data.verdict.code) { |
---|
77 | 77 | case NFT_JUMP: |
---|
78 | 78 | case NFT_GOTO: |
---|
79 | | - if (nft_chain_is_bound(chain)) { |
---|
80 | | - err = -EBUSY; |
---|
81 | | - goto err1; |
---|
82 | | - } |
---|
83 | | - chain->bound = true; |
---|
| 79 | + err = nf_tables_bind_chain(ctx, chain); |
---|
| 80 | + if (err < 0) |
---|
| 81 | + return err; |
---|
84 | 82 | break; |
---|
85 | 83 | default: |
---|
86 | 84 | break; |
---|
.. | .. |
---|
98 | 96 | const struct nft_expr *expr) |
---|
99 | 97 | { |
---|
100 | 98 | const struct nft_immediate_expr *priv = nft_expr_priv(expr); |
---|
| 99 | + const struct nft_data *data = &priv->data; |
---|
| 100 | + struct nft_ctx chain_ctx; |
---|
| 101 | + struct nft_chain *chain; |
---|
| 102 | + struct nft_rule *rule; |
---|
| 103 | + |
---|
| 104 | + if (priv->dreg == NFT_REG_VERDICT) { |
---|
| 105 | + switch (data->verdict.code) { |
---|
| 106 | + case NFT_JUMP: |
---|
| 107 | + case NFT_GOTO: |
---|
| 108 | + chain = data->verdict.chain; |
---|
| 109 | + if (!nft_chain_binding(chain)) |
---|
| 110 | + break; |
---|
| 111 | + |
---|
| 112 | + chain_ctx = *ctx; |
---|
| 113 | + chain_ctx.chain = chain; |
---|
| 114 | + |
---|
| 115 | + list_for_each_entry(rule, &chain->rules, list) |
---|
| 116 | + nft_rule_expr_activate(&chain_ctx, rule); |
---|
| 117 | + |
---|
| 118 | + nft_clear(ctx->net, chain); |
---|
| 119 | + break; |
---|
| 120 | + default: |
---|
| 121 | + break; |
---|
| 122 | + } |
---|
| 123 | + } |
---|
101 | 124 | |
---|
102 | 125 | return nft_data_hold(&priv->data, nft_dreg_to_type(priv->dreg)); |
---|
| 126 | +} |
---|
| 127 | + |
---|
| 128 | +static void nft_immediate_chain_deactivate(const struct nft_ctx *ctx, |
---|
| 129 | + struct nft_chain *chain, |
---|
| 130 | + enum nft_trans_phase phase) |
---|
| 131 | +{ |
---|
| 132 | + struct nft_ctx chain_ctx; |
---|
| 133 | + struct nft_rule *rule; |
---|
| 134 | + |
---|
| 135 | + chain_ctx = *ctx; |
---|
| 136 | + chain_ctx.chain = chain; |
---|
| 137 | + |
---|
| 138 | + list_for_each_entry(rule, &chain->rules, list) |
---|
| 139 | + nft_rule_expr_deactivate(&chain_ctx, rule, phase); |
---|
103 | 140 | } |
---|
104 | 141 | |
---|
105 | 142 | static void nft_immediate_deactivate(const struct nft_ctx *ctx, |
---|
.. | .. |
---|
107 | 144 | enum nft_trans_phase phase) |
---|
108 | 145 | { |
---|
109 | 146 | const struct nft_immediate_expr *priv = nft_expr_priv(expr); |
---|
| 147 | + const struct nft_data *data = &priv->data; |
---|
| 148 | + struct nft_chain *chain; |
---|
| 149 | + |
---|
| 150 | + if (priv->dreg == NFT_REG_VERDICT) { |
---|
| 151 | + switch (data->verdict.code) { |
---|
| 152 | + case NFT_JUMP: |
---|
| 153 | + case NFT_GOTO: |
---|
| 154 | + chain = data->verdict.chain; |
---|
| 155 | + if (!nft_chain_binding(chain)) |
---|
| 156 | + break; |
---|
| 157 | + |
---|
| 158 | + switch (phase) { |
---|
| 159 | + case NFT_TRANS_PREPARE_ERROR: |
---|
| 160 | + nf_tables_unbind_chain(ctx, chain); |
---|
| 161 | + nft_deactivate_next(ctx->net, chain); |
---|
| 162 | + break; |
---|
| 163 | + case NFT_TRANS_PREPARE: |
---|
| 164 | + nft_immediate_chain_deactivate(ctx, chain, phase); |
---|
| 165 | + nft_deactivate_next(ctx->net, chain); |
---|
| 166 | + break; |
---|
| 167 | + default: |
---|
| 168 | + nft_immediate_chain_deactivate(ctx, chain, phase); |
---|
| 169 | + nft_chain_del(chain); |
---|
| 170 | + chain->bound = false; |
---|
| 171 | + nft_use_dec(&chain->table->use); |
---|
| 172 | + break; |
---|
| 173 | + } |
---|
| 174 | + break; |
---|
| 175 | + default: |
---|
| 176 | + break; |
---|
| 177 | + } |
---|
| 178 | + } |
---|
110 | 179 | |
---|
111 | 180 | if (phase == NFT_TRANS_COMMIT) |
---|
112 | 181 | return; |
---|
.. | .. |
---|
131 | 200 | case NFT_GOTO: |
---|
132 | 201 | chain = data->verdict.chain; |
---|
133 | 202 | |
---|
134 | | - if (!nft_chain_is_bound(chain)) |
---|
| 203 | + if (!nft_chain_binding(chain)) |
---|
135 | 204 | break; |
---|
136 | 205 | |
---|
| 206 | + /* Rule construction failed, but chain is already bound: |
---|
| 207 | + * let the transaction records release this chain and its rules. |
---|
| 208 | + */ |
---|
| 209 | + if (chain->bound) { |
---|
| 210 | + nft_use_dec(&chain->use); |
---|
| 211 | + break; |
---|
| 212 | + } |
---|
| 213 | + |
---|
| 214 | + /* Rule has been deleted, release chain and its rules. */ |
---|
137 | 215 | chain_ctx = *ctx; |
---|
138 | 216 | chain_ctx.chain = chain; |
---|
139 | 217 | |
---|
140 | | - list_for_each_entry_safe(rule, n, &chain->rules, list) |
---|
141 | | - nf_tables_rule_release(&chain_ctx, rule); |
---|
142 | | - |
---|
| 218 | + nft_use_dec(&chain->use); |
---|
| 219 | + list_for_each_entry_safe(rule, n, &chain->rules, list) { |
---|
| 220 | + nft_use_dec(&chain->use); |
---|
| 221 | + list_del(&rule->list); |
---|
| 222 | + nf_tables_rule_destroy(&chain_ctx, rule); |
---|
| 223 | + } |
---|
143 | 224 | nf_tables_chain_destroy(&chain_ctx); |
---|
144 | 225 | break; |
---|
145 | 226 | default: |
---|