Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'sched-introduce-chain-templates-support-with-offloading-to-mlxsw'

Jiri Pirko says:

====================
sched: introduce chain templates support with offloading to mlxsw

For the TC clsact offload these days, some of HW drivers need
to hold a magic ball. The reason is, with the first inserted rule inside
HW they need to guess what fields will be used for the matching. If
later on this guess proves to be wrong and user adds a filter with a
different field to match, there's a problem. Mlxsw resolves it now with
couple of patterns. Those try to cover as many match fields as possible.
This aproach is far from optimal, both performance-wise and scale-wise.
Also, there is a combination of filters that in certain order won't
succeed.

Most of the time, when user inserts filters in chain, he knows right away
how the filters are going to look like - what type and option will they
have. For example, he knows that he will only insert filters of type
flower matching destination IP address. He can specify a template that
would cover all the filters in the chain.

This patchset is providing the possibility to user to provide such
template to kernel and propagate it all the way down to device
drivers.

See the examples below.

Create dummy device with clsact first:

There is no chain present by by default:

Add chain number 11 by explicit command:
chain parent ffff: chain 11

Add filter to chain number 12 which does not exist. That will create
implicit chain 12:
chain parent ffff: chain 11
chain parent ffff: chain 12

Delete both chains:

Add a chain with template of type flower allowing to insert rules matching
on last 2 bytes of destination mac address:

The chain with template is now showed in the list:
chain parent ffff: flower chain 0
dst_mac 00:00:00:00:00:00/00:00:00:00:ff:ff
eth_type ipv4

Add another chain (number 22) with template:
chain parent ffff: flower chain 0
dst_mac 00:00:00:00:00:00/00:00:00:00:ff:ff
eth_type ipv4
chain parent ffff: flower chain 22
eth_type ipv4
dst_ip 0.0.0.0/16

Add a filter that fits the template:

Addition of filters that does not fit the template would fail:
Error: cls_flower: Mask does not fit the template.
We have an error talking to the kernel, -1
Error: cls_flower: Mask does not fit the template.
We have an error talking to the kernel, -1

Additions of filters to chain 22:
Error: cls_flower: Mask does not fit the template.
We have an error talking to the kernel, -1
Error: cls_flower: Mask does not fit the template.
We have an error talking to the kernel, -1

---
v3->v4:
- patch 2:
- new patch
- patch 3:
- new patch, derived from the previous v3 chaintemplate obj patch
- patch 4:
- only templates part as chains creation/deletion is now a separate patch
- don't pass template priv as arg of "change" op
- patch 6:
- rebased on top of flower cvlan patch and ip tos/ttl patch
- patch 7:
- templave priv is no longer passed as an arg to "change" op
- patch 11:
- split from the originally single patch
- patch 12:
- split from the originally single patch
v2->v3:
- patch 7:
- rebase on top of the reoffload patchset
- patch 8:
- rebase on top of the reoffload patchset
v1->v2:
- patch 8:
- remove leftover extack arg in fl_hw_create_tmplt()
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+829 -139
+5
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
··· 1455 1455 return 0; 1456 1456 case TC_CLSFLOWER_STATS: 1457 1457 return mlxsw_sp_flower_stats(mlxsw_sp, acl_block, f); 1458 + case TC_CLSFLOWER_TMPLT_CREATE: 1459 + return mlxsw_sp_flower_tmplt_create(mlxsw_sp, acl_block, f); 1460 + case TC_CLSFLOWER_TMPLT_DESTROY: 1461 + mlxsw_sp_flower_tmplt_destroy(mlxsw_sp, acl_block, f); 1462 + return 0; 1458 1463 default: 1459 1464 return -EOPNOTSUPP; 1460 1465 }
+8 -1
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
··· 543 543 struct mlxsw_sp_acl_ruleset * 544 544 mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp, 545 545 struct mlxsw_sp_acl_block *block, u32 chain_index, 546 - enum mlxsw_sp_acl_profile profile); 546 + enum mlxsw_sp_acl_profile profile, 547 + struct mlxsw_afk_element_usage *tmplt_elusage); 547 548 void mlxsw_sp_acl_ruleset_put(struct mlxsw_sp *mlxsw_sp, 548 549 struct mlxsw_sp_acl_ruleset *ruleset); 549 550 u16 mlxsw_sp_acl_ruleset_group_id(struct mlxsw_sp_acl_ruleset *ruleset); ··· 668 667 int mlxsw_sp_flower_stats(struct mlxsw_sp *mlxsw_sp, 669 668 struct mlxsw_sp_acl_block *block, 670 669 struct tc_cls_flower_offload *f); 670 + int mlxsw_sp_flower_tmplt_create(struct mlxsw_sp *mlxsw_sp, 671 + struct mlxsw_sp_acl_block *block, 672 + struct tc_cls_flower_offload *f); 673 + void mlxsw_sp_flower_tmplt_destroy(struct mlxsw_sp *mlxsw_sp, 674 + struct mlxsw_sp_acl_block *block, 675 + struct tc_cls_flower_offload *f); 671 676 672 677 /* spectrum_qdisc.c */ 673 678 int mlxsw_sp_tc_qdisc_init(struct mlxsw_sp_port *mlxsw_sp_port);
+8 -4
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
··· 317 317 static struct mlxsw_sp_acl_ruleset * 318 318 mlxsw_sp_acl_ruleset_create(struct mlxsw_sp *mlxsw_sp, 319 319 struct mlxsw_sp_acl_block *block, u32 chain_index, 320 - const struct mlxsw_sp_acl_profile_ops *ops) 320 + const struct mlxsw_sp_acl_profile_ops *ops, 321 + struct mlxsw_afk_element_usage *tmplt_elusage) 321 322 { 322 323 struct mlxsw_sp_acl *acl = mlxsw_sp->acl; 323 324 struct mlxsw_sp_acl_ruleset *ruleset; ··· 338 337 if (err) 339 338 goto err_rhashtable_init; 340 339 341 - err = ops->ruleset_add(mlxsw_sp, &acl->tcam, ruleset->priv); 340 + err = ops->ruleset_add(mlxsw_sp, &acl->tcam, ruleset->priv, 341 + tmplt_elusage); 342 342 if (err) 343 343 goto err_ops_ruleset_add; 344 344 ··· 421 419 struct mlxsw_sp_acl_ruleset * 422 420 mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp, 423 421 struct mlxsw_sp_acl_block *block, u32 chain_index, 424 - enum mlxsw_sp_acl_profile profile) 422 + enum mlxsw_sp_acl_profile profile, 423 + struct mlxsw_afk_element_usage *tmplt_elusage) 425 424 { 426 425 const struct mlxsw_sp_acl_profile_ops *ops; 427 426 struct mlxsw_sp_acl *acl = mlxsw_sp->acl; ··· 437 434 mlxsw_sp_acl_ruleset_ref_inc(ruleset); 438 435 return ruleset; 439 436 } 440 - return mlxsw_sp_acl_ruleset_create(mlxsw_sp, block, chain_index, ops); 437 + return mlxsw_sp_acl_ruleset_create(mlxsw_sp, block, chain_index, ops, 438 + tmplt_elusage); 441 439 } 442 440 443 441 void mlxsw_sp_acl_ruleset_put(struct mlxsw_sp *mlxsw_sp,
+22 -3
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
··· 189 189 struct mlxsw_sp_acl_tcam_group_ops *ops; 190 190 const struct mlxsw_sp_acl_tcam_pattern *patterns; 191 191 unsigned int patterns_count; 192 + bool tmplt_elusage_set; 193 + struct mlxsw_afk_element_usage tmplt_elusage; 192 194 }; 193 195 194 196 struct mlxsw_sp_acl_tcam_chunk { ··· 236 234 struct mlxsw_sp_acl_tcam *tcam, 237 235 struct mlxsw_sp_acl_tcam_group *group, 238 236 const struct mlxsw_sp_acl_tcam_pattern *patterns, 239 - unsigned int patterns_count) 237 + unsigned int patterns_count, 238 + struct mlxsw_afk_element_usage *tmplt_elusage) 240 239 { 241 240 int err; 242 241 243 242 group->tcam = tcam; 244 243 group->patterns = patterns; 245 244 group->patterns_count = patterns_count; 245 + if (tmplt_elusage) { 246 + group->tmplt_elusage_set = true; 247 + memcpy(&group->tmplt_elusage, tmplt_elusage, 248 + sizeof(group->tmplt_elusage)); 249 + } 246 250 INIT_LIST_HEAD(&group->region_list); 247 251 err = mlxsw_sp_acl_tcam_group_id_get(tcam, &group->id); 248 252 if (err) ··· 456 448 { 457 449 const struct mlxsw_sp_acl_tcam_pattern *pattern; 458 450 int i; 451 + 452 + /* In case the template is set, we don't have to look up the pattern 453 + * and just use the template. 454 + */ 455 + if (group->tmplt_elusage_set) { 456 + memcpy(out, &group->tmplt_elusage, sizeof(*out)); 457 + WARN_ON(!mlxsw_afk_element_usage_subset(elusage, out)); 458 + return; 459 + } 459 460 460 461 for (i = 0; i < group->patterns_count; i++) { 461 462 pattern = &group->patterns[i]; ··· 882 865 static int 883 866 mlxsw_sp_acl_tcam_flower_ruleset_add(struct mlxsw_sp *mlxsw_sp, 884 867 struct mlxsw_sp_acl_tcam *tcam, 885 - void *ruleset_priv) 868 + void *ruleset_priv, 869 + struct mlxsw_afk_element_usage *tmplt_elusage) 886 870 { 887 871 struct mlxsw_sp_acl_tcam_flower_ruleset *ruleset = ruleset_priv; 888 872 889 873 return mlxsw_sp_acl_tcam_group_add(mlxsw_sp, tcam, &ruleset->group, 890 874 mlxsw_sp_acl_tcam_patterns, 891 - MLXSW_SP_ACL_TCAM_PATTERNS_COUNT); 875 + MLXSW_SP_ACL_TCAM_PATTERNS_COUNT, 876 + tmplt_elusage); 892 877 } 893 878 894 879 static void
+2 -1
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h
··· 64 64 struct mlxsw_sp_acl_profile_ops { 65 65 size_t ruleset_priv_size; 66 66 int (*ruleset_add)(struct mlxsw_sp *mlxsw_sp, 67 - struct mlxsw_sp_acl_tcam *tcam, void *ruleset_priv); 67 + struct mlxsw_sp_acl_tcam *tcam, void *ruleset_priv, 68 + struct mlxsw_afk_element_usage *tmplt_elusage); 68 69 void (*ruleset_del)(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv); 69 70 int (*ruleset_bind)(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv, 70 71 struct mlxsw_sp_port *mlxsw_sp_port,
+41 -3
drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
··· 414 414 415 415 ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, block, 416 416 f->common.chain_index, 417 - MLXSW_SP_ACL_PROFILE_FLOWER); 417 + MLXSW_SP_ACL_PROFILE_FLOWER, NULL); 418 418 if (IS_ERR(ruleset)) 419 419 return PTR_ERR(ruleset); 420 420 ··· 458 458 459 459 ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, block, 460 460 f->common.chain_index, 461 - MLXSW_SP_ACL_PROFILE_FLOWER); 461 + MLXSW_SP_ACL_PROFILE_FLOWER, NULL); 462 462 if (IS_ERR(ruleset)) 463 463 return; 464 464 ··· 484 484 485 485 ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, block, 486 486 f->common.chain_index, 487 - MLXSW_SP_ACL_PROFILE_FLOWER); 487 + MLXSW_SP_ACL_PROFILE_FLOWER, NULL); 488 488 if (WARN_ON(IS_ERR(ruleset))) 489 489 return -EINVAL; 490 490 ··· 505 505 err_rule_get_stats: 506 506 mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset); 507 507 return err; 508 + } 509 + 510 + int mlxsw_sp_flower_tmplt_create(struct mlxsw_sp *mlxsw_sp, 511 + struct mlxsw_sp_acl_block *block, 512 + struct tc_cls_flower_offload *f) 513 + { 514 + struct mlxsw_sp_acl_ruleset *ruleset; 515 + struct mlxsw_sp_acl_rule_info rulei; 516 + int err; 517 + 518 + memset(&rulei, 0, sizeof(rulei)); 519 + err = mlxsw_sp_flower_parse(mlxsw_sp, block, &rulei, f); 520 + if (err) 521 + return err; 522 + ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, block, 523 + f->common.chain_index, 524 + MLXSW_SP_ACL_PROFILE_FLOWER, 525 + &rulei.values.elusage); 526 + if (IS_ERR(ruleset)) 527 + return PTR_ERR(ruleset); 528 + /* keep the reference to the ruleset */ 529 + return 0; 530 + } 531 + 532 + void mlxsw_sp_flower_tmplt_destroy(struct mlxsw_sp *mlxsw_sp, 533 + struct mlxsw_sp_acl_block *block, 534 + struct tc_cls_flower_offload *f) 535 + { 536 + struct mlxsw_sp_acl_ruleset *ruleset; 537 + 538 + ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, block, 539 + f->common.chain_index, 540 + MLXSW_SP_ACL_PROFILE_FLOWER, NULL); 541 + if (IS_ERR(ruleset)) 542 + return; 543 + /* put the reference to the ruleset kept in create */ 544 + mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset); 545 + mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset); 508 546 }
+2
include/net/pkt_cls.h
··· 721 721 TC_CLSFLOWER_REPLACE, 722 722 TC_CLSFLOWER_DESTROY, 723 723 TC_CLSFLOWER_STATS, 724 + TC_CLSFLOWER_TMPLT_CREATE, 725 + TC_CLSFLOWER_TMPLT_DESTROY, 724 726 }; 725 727 726 728 struct tc_cls_flower_offload {
+17 -1
include/net/sch_generic.h
··· 238 238 }; 239 239 }; 240 240 241 + struct tcf_chain; 242 + 241 243 struct tcf_proto_ops { 242 244 struct list_head head; 243 245 char kind[IFNAMSIZ]; ··· 265 263 tc_setup_cb_t *cb, void *cb_priv, 266 264 struct netlink_ext_ack *extack); 267 265 void (*bind_class)(void *, u32, unsigned long); 266 + void * (*tmplt_create)(struct net *net, 267 + struct tcf_chain *chain, 268 + struct nlattr **tca, 269 + struct netlink_ext_ack *extack); 270 + void (*tmplt_destroy)(void *tmplt_priv); 268 271 269 272 /* rtnetlink specific */ 270 273 int (*dump)(struct net*, struct tcf_proto*, void *, 271 274 struct sk_buff *skb, struct tcmsg*); 275 + int (*tmplt_dump)(struct sk_buff *skb, 276 + struct net *net, 277 + void *tmplt_priv); 272 278 273 279 struct module *owner; 274 280 }; ··· 310 300 311 301 struct tcf_chain { 312 302 struct tcf_proto __rcu *filter_chain; 313 - struct list_head filter_chain_list; 314 303 struct list_head list; 315 304 struct tcf_block *block; 316 305 u32 index; /* chain index */ 317 306 unsigned int refcnt; 307 + bool explicitly_created; 308 + const struct tcf_proto_ops *tmplt_ops; 309 + void *tmplt_priv; 318 310 }; 319 311 320 312 struct tcf_block { ··· 330 318 bool keep_dst; 331 319 unsigned int offloadcnt; /* Number of oddloaded filters */ 332 320 unsigned int nooffloaddevcnt; /* Number of devs unable to do offload */ 321 + struct { 322 + struct tcf_chain *chain; 323 + struct list_head filter_chain_list; 324 + } chain0; 333 325 }; 334 326 335 327 static inline void tcf_block_offload_inc(struct tcf_block *block, u32 *flags)
+7
include/uapi/linux/rtnetlink.h
··· 150 150 RTM_NEWCACHEREPORT = 96, 151 151 #define RTM_NEWCACHEREPORT RTM_NEWCACHEREPORT 152 152 153 + RTM_NEWCHAIN = 100, 154 + #define RTM_NEWCHAIN RTM_NEWCHAIN 155 + RTM_DELCHAIN, 156 + #define RTM_DELCHAIN RTM_DELCHAIN 157 + RTM_GETCHAIN, 158 + #define RTM_GETCHAIN RTM_GETCHAIN 159 + 153 160 __RTM_MAX, 154 161 #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) 155 162 };
+435 -77
net/sched/cls_api.c
··· 39 39 40 40 /* Find classifier type by string name */ 41 41 42 - static const struct tcf_proto_ops *tcf_proto_lookup_ops(const char *kind) 42 + static const struct tcf_proto_ops *__tcf_proto_lookup_ops(const char *kind) 43 43 { 44 44 const struct tcf_proto_ops *t, *res = NULL; 45 45 ··· 55 55 read_unlock(&cls_mod_lock); 56 56 } 57 57 return res; 58 + } 59 + 60 + static const struct tcf_proto_ops * 61 + tcf_proto_lookup_ops(const char *kind, struct netlink_ext_ack *extack) 62 + { 63 + const struct tcf_proto_ops *ops; 64 + 65 + ops = __tcf_proto_lookup_ops(kind); 66 + if (ops) 67 + return ops; 68 + #ifdef CONFIG_MODULES 69 + rtnl_unlock(); 70 + request_module("cls_%s", kind); 71 + rtnl_lock(); 72 + ops = __tcf_proto_lookup_ops(kind); 73 + /* We dropped the RTNL semaphore in order to perform 74 + * the module load. So, even if we succeeded in loading 75 + * the module we have to replay the request. We indicate 76 + * this using -EAGAIN. 77 + */ 78 + if (ops) { 79 + module_put(ops->owner); 80 + return ERR_PTR(-EAGAIN); 81 + } 82 + #endif 83 + NL_SET_ERR_MSG(extack, "TC classifier not found"); 84 + return ERR_PTR(-ENOENT); 58 85 } 59 86 60 87 /* Register(unregister) new classifier type */ ··· 160 133 if (!tp) 161 134 return ERR_PTR(-ENOBUFS); 162 135 163 - err = -ENOENT; 164 - tp->ops = tcf_proto_lookup_ops(kind); 165 - if (!tp->ops) { 166 - #ifdef CONFIG_MODULES 167 - rtnl_unlock(); 168 - request_module("cls_%s", kind); 169 - rtnl_lock(); 170 - tp->ops = tcf_proto_lookup_ops(kind); 171 - /* We dropped the RTNL semaphore in order to perform 172 - * the module load. So, even if we succeeded in loading 173 - * the module we have to replay the request. We indicate 174 - * this using -EAGAIN. 175 - */ 176 - if (tp->ops) { 177 - module_put(tp->ops->owner); 178 - err = -EAGAIN; 179 - } else { 180 - NL_SET_ERR_MSG(extack, "TC classifier not found"); 181 - err = -ENOENT; 182 - } 183 - #endif 136 + tp->ops = tcf_proto_lookup_ops(kind, extack); 137 + if (IS_ERR(tp->ops)) { 138 + err = PTR_ERR(tp->ops); 184 139 goto errout; 185 140 } 186 141 tp->classify = tp->ops->classify; ··· 204 195 chain = kzalloc(sizeof(*chain), GFP_KERNEL); 205 196 if (!chain) 206 197 return NULL; 207 - INIT_LIST_HEAD(&chain->filter_chain_list); 208 198 list_add_tail(&chain->list, &block->chain_list); 209 199 chain->block = block; 210 200 chain->index = chain_index; 211 201 chain->refcnt = 1; 202 + if (!chain->index) 203 + block->chain0.chain = chain; 212 204 return chain; 213 205 } 214 206 ··· 219 209 if (item->chain_head_change) 220 210 item->chain_head_change(tp_head, item->chain_head_change_priv); 221 211 } 222 - static void tcf_chain_head_change(struct tcf_chain *chain, 223 - struct tcf_proto *tp_head) 212 + 213 + static void tcf_chain0_head_change(struct tcf_chain *chain, 214 + struct tcf_proto *tp_head) 224 215 { 225 216 struct tcf_filter_chain_list_item *item; 217 + struct tcf_block *block = chain->block; 226 218 227 - list_for_each_entry(item, &chain->filter_chain_list, list) 219 + if (chain->index) 220 + return; 221 + list_for_each_entry(item, &block->chain0.filter_chain_list, list) 228 222 tcf_chain_head_change_item(item, tp_head); 229 223 } 230 224 ··· 236 222 { 237 223 struct tcf_proto *tp = rtnl_dereference(chain->filter_chain); 238 224 239 - tcf_chain_head_change(chain, NULL); 225 + tcf_chain0_head_change(chain, NULL); 240 226 while (tp) { 241 227 RCU_INIT_POINTER(chain->filter_chain, tp->next); 242 228 tcf_proto_destroy(tp, NULL); ··· 250 236 struct tcf_block *block = chain->block; 251 237 252 238 list_del(&chain->list); 239 + if (!chain->index) 240 + block->chain0.chain = NULL; 253 241 kfree(chain); 254 - if (list_empty(&block->chain_list)) 242 + if (list_empty(&block->chain_list) && block->refcnt == 0) 255 243 kfree(block); 256 244 } 257 245 ··· 262 246 ++chain->refcnt; 263 247 } 264 248 265 - struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index, 266 - bool create) 249 + static struct tcf_chain *tcf_chain_lookup(struct tcf_block *block, 250 + u32 chain_index) 267 251 { 268 252 struct tcf_chain *chain; 269 253 270 254 list_for_each_entry(chain, &block->chain_list, list) { 271 - if (chain->index == chain_index) { 272 - tcf_chain_hold(chain); 255 + if (chain->index == chain_index) 273 256 return chain; 274 - } 257 + } 258 + return NULL; 259 + } 260 + 261 + static int tc_chain_notify(struct tcf_chain *chain, struct sk_buff *oskb, 262 + u32 seq, u16 flags, int event, bool unicast); 263 + 264 + struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index, 265 + bool create) 266 + { 267 + struct tcf_chain *chain = tcf_chain_lookup(block, chain_index); 268 + 269 + if (chain) { 270 + tcf_chain_hold(chain); 271 + return chain; 275 272 } 276 273 277 - return create ? tcf_chain_create(block, chain_index) : NULL; 274 + if (!create) 275 + return NULL; 276 + chain = tcf_chain_create(block, chain_index); 277 + if (!chain) 278 + return NULL; 279 + tc_chain_notify(chain, NULL, 0, NLM_F_CREATE | NLM_F_EXCL, 280 + RTM_NEWCHAIN, false); 281 + return chain; 278 282 } 279 283 EXPORT_SYMBOL(tcf_chain_get); 280 284 285 + static void tc_chain_tmplt_del(struct tcf_chain *chain); 286 + 281 287 void tcf_chain_put(struct tcf_chain *chain) 282 288 { 283 - if (--chain->refcnt == 0) 289 + if (--chain->refcnt == 0) { 290 + tc_chain_notify(chain, NULL, 0, 0, RTM_DELCHAIN, false); 291 + tc_chain_tmplt_del(chain); 284 292 tcf_chain_destroy(chain); 293 + } 285 294 } 286 295 EXPORT_SYMBOL(tcf_chain_put); 296 + 297 + static void tcf_chain_put_explicitly_created(struct tcf_chain *chain) 298 + { 299 + if (chain->explicitly_created) 300 + tcf_chain_put(chain); 301 + } 287 302 288 303 static bool tcf_block_offload_in_use(struct tcf_block *block) 289 304 { ··· 384 337 } 385 338 386 339 static int 387 - tcf_chain_head_change_cb_add(struct tcf_chain *chain, 388 - struct tcf_block_ext_info *ei, 389 - struct netlink_ext_ack *extack) 340 + tcf_chain0_head_change_cb_add(struct tcf_block *block, 341 + struct tcf_block_ext_info *ei, 342 + struct netlink_ext_ack *extack) 390 343 { 344 + struct tcf_chain *chain0 = block->chain0.chain; 391 345 struct tcf_filter_chain_list_item *item; 392 346 393 347 item = kmalloc(sizeof(*item), GFP_KERNEL); ··· 398 350 } 399 351 item->chain_head_change = ei->chain_head_change; 400 352 item->chain_head_change_priv = ei->chain_head_change_priv; 401 - if (chain->filter_chain) 402 - tcf_chain_head_change_item(item, chain->filter_chain); 403 - list_add(&item->list, &chain->filter_chain_list); 353 + if (chain0 && chain0->filter_chain) 354 + tcf_chain_head_change_item(item, chain0->filter_chain); 355 + list_add(&item->list, &block->chain0.filter_chain_list); 404 356 return 0; 405 357 } 406 358 407 359 static void 408 - tcf_chain_head_change_cb_del(struct tcf_chain *chain, 409 - struct tcf_block_ext_info *ei) 360 + tcf_chain0_head_change_cb_del(struct tcf_block *block, 361 + struct tcf_block_ext_info *ei) 410 362 { 363 + struct tcf_chain *chain0 = block->chain0.chain; 411 364 struct tcf_filter_chain_list_item *item; 412 365 413 - list_for_each_entry(item, &chain->filter_chain_list, list) { 366 + list_for_each_entry(item, &block->chain0.filter_chain_list, list) { 414 367 if ((!ei->chain_head_change && !ei->chain_head_change_priv) || 415 368 (item->chain_head_change == ei->chain_head_change && 416 369 item->chain_head_change_priv == ei->chain_head_change_priv)) { 417 - tcf_chain_head_change_item(item, NULL); 370 + if (chain0) 371 + tcf_chain_head_change_item(item, NULL); 418 372 list_del(&item->list); 419 373 kfree(item); 420 374 return; ··· 452 402 struct netlink_ext_ack *extack) 453 403 { 454 404 struct tcf_block *block; 455 - struct tcf_chain *chain; 456 - int err; 457 405 458 406 block = kzalloc(sizeof(*block), GFP_KERNEL); 459 407 if (!block) { ··· 461 413 INIT_LIST_HEAD(&block->chain_list); 462 414 INIT_LIST_HEAD(&block->cb_list); 463 415 INIT_LIST_HEAD(&block->owner_list); 416 + INIT_LIST_HEAD(&block->chain0.filter_chain_list); 464 417 465 - /* Create chain 0 by default, it has to be always present. */ 466 - chain = tcf_chain_create(block, 0); 467 - if (!chain) { 468 - NL_SET_ERR_MSG(extack, "Failed to create new tcf chain"); 469 - err = -ENOMEM; 470 - goto err_chain_create; 471 - } 472 418 block->refcnt = 1; 473 419 block->net = net; 474 420 block->index = block_index; ··· 471 429 if (!tcf_block_shared(block)) 472 430 block->q = q; 473 431 return block; 474 - 475 - err_chain_create: 476 - kfree(block); 477 - return ERR_PTR(err); 478 432 } 479 433 480 434 static struct tcf_block *tcf_block_lookup(struct net *net, u32 block_index) ··· 550 512 } 551 513 552 514 return block; 553 - } 554 - 555 - static struct tcf_chain *tcf_block_chain_zero(struct tcf_block *block) 556 - { 557 - return list_first_entry(&block->chain_list, struct tcf_chain, list); 558 515 } 559 516 560 517 struct tcf_block_owner_item { ··· 645 612 646 613 tcf_block_owner_netif_keep_dst(block, q, ei->binder_type); 647 614 648 - err = tcf_chain_head_change_cb_add(tcf_block_chain_zero(block), 649 - ei, extack); 615 + err = tcf_chain0_head_change_cb_add(block, ei, extack); 650 616 if (err) 651 - goto err_chain_head_change_cb_add; 617 + goto err_chain0_head_change_cb_add; 652 618 653 619 err = tcf_block_offload_bind(block, q, ei, extack); 654 620 if (err) ··· 657 625 return 0; 658 626 659 627 err_block_offload_bind: 660 - tcf_chain_head_change_cb_del(tcf_block_chain_zero(block), ei); 661 - err_chain_head_change_cb_add: 628 + tcf_chain0_head_change_cb_del(block, ei); 629 + err_chain0_head_change_cb_add: 662 630 tcf_block_owner_del(block, q, ei->binder_type); 663 631 err_block_owner_add: 664 632 if (created) { 665 633 if (tcf_block_shared(block)) 666 634 tcf_block_remove(block, net); 667 635 err_block_insert: 668 - kfree(tcf_block_chain_zero(block)); 669 636 kfree(block); 670 637 } else { 671 638 block->refcnt--; ··· 704 673 705 674 if (!block) 706 675 return; 707 - tcf_chain_head_change_cb_del(tcf_block_chain_zero(block), ei); 676 + tcf_chain0_head_change_cb_del(block, ei); 708 677 tcf_block_owner_del(block, q, ei->binder_type); 709 678 710 - if (--block->refcnt == 0) { 679 + if (block->refcnt == 1) { 711 680 if (tcf_block_shared(block)) 712 681 tcf_block_remove(block, block->net); 713 682 ··· 723 692 724 693 tcf_block_offload_unbind(block, q, ei); 725 694 726 - if (block->refcnt == 0) { 695 + if (block->refcnt == 1) { 727 696 /* At this point, all the chains should have refcnt >= 1. */ 728 - list_for_each_entry_safe(chain, tmp, &block->chain_list, list) 697 + list_for_each_entry_safe(chain, tmp, &block->chain_list, list) { 698 + tcf_chain_put_explicitly_created(chain); 729 699 tcf_chain_put(chain); 700 + } 730 701 731 - /* Finally, put chain 0 and allow block to be freed. */ 732 - tcf_chain_put(tcf_block_chain_zero(block)); 702 + block->refcnt--; 703 + if (list_empty(&block->chain_list)) 704 + kfree(block); 733 705 } 734 706 } 735 707 EXPORT_SYMBOL(tcf_block_put_ext); ··· 972 938 struct tcf_proto *tp) 973 939 { 974 940 if (*chain_info->pprev == chain->filter_chain) 975 - tcf_chain_head_change(chain, tp); 941 + tcf_chain0_head_change(chain, tp); 976 942 RCU_INIT_POINTER(tp->next, tcf_chain_tp_prev(chain_info)); 977 943 rcu_assign_pointer(*chain_info->pprev, tp); 978 944 tcf_chain_hold(chain); ··· 985 951 struct tcf_proto *next = rtnl_dereference(chain_info->next); 986 952 987 953 if (tp == chain->filter_chain) 988 - tcf_chain_head_change(chain, next); 954 + tcf_chain0_head_change(chain, next); 989 955 RCU_INIT_POINTER(*chain_info->pprev, next); 990 956 tcf_chain_put(chain); 991 957 } ··· 1258 1224 } else if (n->nlmsg_flags & NLM_F_EXCL) { 1259 1225 NL_SET_ERR_MSG(extack, "Filter already exists"); 1260 1226 err = -EEXIST; 1227 + goto errout; 1228 + } 1229 + 1230 + if (chain->tmplt_ops && chain->tmplt_ops != tp->ops) { 1231 + NL_SET_ERR_MSG(extack, "Chain template is set to a different filter kind"); 1232 + err = -EINVAL; 1261 1233 goto errout; 1262 1234 } 1263 1235 ··· 1648 1608 return skb->len; 1649 1609 } 1650 1610 1611 + static int tc_chain_fill_node(struct tcf_chain *chain, struct net *net, 1612 + struct sk_buff *skb, struct tcf_block *block, 1613 + u32 portid, u32 seq, u16 flags, int event) 1614 + { 1615 + unsigned char *b = skb_tail_pointer(skb); 1616 + const struct tcf_proto_ops *ops; 1617 + struct nlmsghdr *nlh; 1618 + struct tcmsg *tcm; 1619 + void *priv; 1620 + 1621 + ops = chain->tmplt_ops; 1622 + priv = chain->tmplt_priv; 1623 + 1624 + nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags); 1625 + if (!nlh) 1626 + goto out_nlmsg_trim; 1627 + tcm = nlmsg_data(nlh); 1628 + tcm->tcm_family = AF_UNSPEC; 1629 + tcm->tcm__pad1 = 0; 1630 + tcm->tcm__pad2 = 0; 1631 + tcm->tcm_handle = 0; 1632 + if (block->q) { 1633 + tcm->tcm_ifindex = qdisc_dev(block->q)->ifindex; 1634 + tcm->tcm_parent = block->q->handle; 1635 + } else { 1636 + tcm->tcm_ifindex = TCM_IFINDEX_MAGIC_BLOCK; 1637 + tcm->tcm_block_index = block->index; 1638 + } 1639 + 1640 + if (nla_put_u32(skb, TCA_CHAIN, chain->index)) 1641 + goto nla_put_failure; 1642 + 1643 + if (ops) { 1644 + if (nla_put_string(skb, TCA_KIND, ops->kind)) 1645 + goto nla_put_failure; 1646 + if (ops->tmplt_dump(skb, net, priv) < 0) 1647 + goto nla_put_failure; 1648 + } 1649 + 1650 + nlh->nlmsg_len = skb_tail_pointer(skb) - b; 1651 + return skb->len; 1652 + 1653 + out_nlmsg_trim: 1654 + nla_put_failure: 1655 + nlmsg_trim(skb, b); 1656 + return -EMSGSIZE; 1657 + } 1658 + 1659 + static int tc_chain_notify(struct tcf_chain *chain, struct sk_buff *oskb, 1660 + u32 seq, u16 flags, int event, bool unicast) 1661 + { 1662 + u32 portid = oskb ? NETLINK_CB(oskb).portid : 0; 1663 + struct tcf_block *block = chain->block; 1664 + struct net *net = block->net; 1665 + struct sk_buff *skb; 1666 + 1667 + skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 1668 + if (!skb) 1669 + return -ENOBUFS; 1670 + 1671 + if (tc_chain_fill_node(chain, net, skb, block, portid, 1672 + seq, flags, event) <= 0) { 1673 + kfree_skb(skb); 1674 + return -EINVAL; 1675 + } 1676 + 1677 + if (unicast) 1678 + return netlink_unicast(net->rtnl, skb, portid, MSG_DONTWAIT); 1679 + 1680 + return rtnetlink_send(skb, net, portid, RTNLGRP_TC, flags & NLM_F_ECHO); 1681 + } 1682 + 1683 + static int tc_chain_tmplt_add(struct tcf_chain *chain, struct net *net, 1684 + struct nlattr **tca, 1685 + struct netlink_ext_ack *extack) 1686 + { 1687 + const struct tcf_proto_ops *ops; 1688 + void *tmplt_priv; 1689 + 1690 + /* If kind is not set, user did not specify template. */ 1691 + if (!tca[TCA_KIND]) 1692 + return 0; 1693 + 1694 + ops = tcf_proto_lookup_ops(nla_data(tca[TCA_KIND]), extack); 1695 + if (IS_ERR(ops)) 1696 + return PTR_ERR(ops); 1697 + if (!ops->tmplt_create || !ops->tmplt_destroy || !ops->tmplt_dump) { 1698 + NL_SET_ERR_MSG(extack, "Chain templates are not supported with specified classifier"); 1699 + return -EOPNOTSUPP; 1700 + } 1701 + 1702 + tmplt_priv = ops->tmplt_create(net, chain, tca, extack); 1703 + if (IS_ERR(tmplt_priv)) { 1704 + module_put(ops->owner); 1705 + return PTR_ERR(tmplt_priv); 1706 + } 1707 + chain->tmplt_ops = ops; 1708 + chain->tmplt_priv = tmplt_priv; 1709 + return 0; 1710 + } 1711 + 1712 + static void tc_chain_tmplt_del(struct tcf_chain *chain) 1713 + { 1714 + const struct tcf_proto_ops *ops = chain->tmplt_ops; 1715 + 1716 + /* If template ops are set, no work to do for us. */ 1717 + if (!ops) 1718 + return; 1719 + 1720 + ops->tmplt_destroy(chain->tmplt_priv); 1721 + module_put(ops->owner); 1722 + } 1723 + 1724 + /* Add/delete/get a chain */ 1725 + 1726 + static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n, 1727 + struct netlink_ext_ack *extack) 1728 + { 1729 + struct net *net = sock_net(skb->sk); 1730 + struct nlattr *tca[TCA_MAX + 1]; 1731 + struct tcmsg *t; 1732 + u32 parent; 1733 + u32 chain_index; 1734 + struct Qdisc *q = NULL; 1735 + struct tcf_chain *chain = NULL; 1736 + struct tcf_block *block; 1737 + unsigned long cl; 1738 + int err; 1739 + 1740 + if (n->nlmsg_type != RTM_GETCHAIN && 1741 + !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) 1742 + return -EPERM; 1743 + 1744 + replay: 1745 + err = nlmsg_parse(n, sizeof(*t), tca, TCA_MAX, NULL, extack); 1746 + if (err < 0) 1747 + return err; 1748 + 1749 + t = nlmsg_data(n); 1750 + parent = t->tcm_parent; 1751 + cl = 0; 1752 + 1753 + block = tcf_block_find(net, &q, &parent, &cl, 1754 + t->tcm_ifindex, t->tcm_block_index, extack); 1755 + if (IS_ERR(block)) 1756 + return PTR_ERR(block); 1757 + 1758 + chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0; 1759 + if (chain_index > TC_ACT_EXT_VAL_MASK) { 1760 + NL_SET_ERR_MSG(extack, "Specified chain index exceeds upper limit"); 1761 + return -EINVAL; 1762 + } 1763 + chain = tcf_chain_lookup(block, chain_index); 1764 + if (n->nlmsg_type == RTM_NEWCHAIN) { 1765 + if (chain) { 1766 + NL_SET_ERR_MSG(extack, "Filter chain already exists"); 1767 + return -EEXIST; 1768 + } 1769 + if (!(n->nlmsg_flags & NLM_F_CREATE)) { 1770 + NL_SET_ERR_MSG(extack, "Need both RTM_NEWCHAIN and NLM_F_CREATE to create a new chain"); 1771 + return -ENOENT; 1772 + } 1773 + chain = tcf_chain_create(block, chain_index); 1774 + if (!chain) { 1775 + NL_SET_ERR_MSG(extack, "Failed to create filter chain"); 1776 + return -ENOMEM; 1777 + } 1778 + } else { 1779 + if (!chain) { 1780 + NL_SET_ERR_MSG(extack, "Cannot find specified filter chain"); 1781 + return -EINVAL; 1782 + } 1783 + tcf_chain_hold(chain); 1784 + } 1785 + 1786 + switch (n->nlmsg_type) { 1787 + case RTM_NEWCHAIN: 1788 + err = tc_chain_tmplt_add(chain, net, tca, extack); 1789 + if (err) 1790 + goto errout; 1791 + /* In case the chain was successfully added, take a reference 1792 + * to the chain. This ensures that an empty chain 1793 + * does not disappear at the end of this function. 1794 + */ 1795 + tcf_chain_hold(chain); 1796 + chain->explicitly_created = true; 1797 + tc_chain_notify(chain, NULL, 0, NLM_F_CREATE | NLM_F_EXCL, 1798 + RTM_NEWCHAIN, false); 1799 + break; 1800 + case RTM_DELCHAIN: 1801 + /* Flush the chain first as the user requested chain removal. */ 1802 + tcf_chain_flush(chain); 1803 + /* In case the chain was successfully deleted, put a reference 1804 + * to the chain previously taken during addition. 1805 + */ 1806 + tcf_chain_put_explicitly_created(chain); 1807 + break; 1808 + case RTM_GETCHAIN: 1809 + break; 1810 + err = tc_chain_notify(chain, skb, n->nlmsg_seq, 1811 + n->nlmsg_seq, n->nlmsg_type, true); 1812 + if (err < 0) 1813 + NL_SET_ERR_MSG(extack, "Failed to send chain notify message"); 1814 + break; 1815 + default: 1816 + err = -EOPNOTSUPP; 1817 + NL_SET_ERR_MSG(extack, "Unsupported message type"); 1818 + goto errout; 1819 + } 1820 + 1821 + errout: 1822 + tcf_chain_put(chain); 1823 + if (err == -EAGAIN) 1824 + /* Replay the request. */ 1825 + goto replay; 1826 + return err; 1827 + } 1828 + 1829 + /* called with RTNL */ 1830 + static int tc_dump_chain(struct sk_buff *skb, struct netlink_callback *cb) 1831 + { 1832 + struct net *net = sock_net(skb->sk); 1833 + struct nlattr *tca[TCA_MAX + 1]; 1834 + struct Qdisc *q = NULL; 1835 + struct tcf_block *block; 1836 + struct tcf_chain *chain; 1837 + struct tcmsg *tcm = nlmsg_data(cb->nlh); 1838 + long index_start; 1839 + long index; 1840 + u32 parent; 1841 + int err; 1842 + 1843 + if (nlmsg_len(cb->nlh) < sizeof(*tcm)) 1844 + return skb->len; 1845 + 1846 + err = nlmsg_parse(cb->nlh, sizeof(*tcm), tca, TCA_MAX, NULL, NULL); 1847 + if (err) 1848 + return err; 1849 + 1850 + if (tcm->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK) { 1851 + block = tcf_block_lookup(net, tcm->tcm_block_index); 1852 + if (!block) 1853 + goto out; 1854 + /* If we work with block index, q is NULL and parent value 1855 + * will never be used in the following code. The check 1856 + * in tcf_fill_node prevents it. However, compiler does not 1857 + * see that far, so set parent to zero to silence the warning 1858 + * about parent being uninitialized. 1859 + */ 1860 + parent = 0; 1861 + } else { 1862 + const struct Qdisc_class_ops *cops; 1863 + struct net_device *dev; 1864 + unsigned long cl = 0; 1865 + 1866 + dev = __dev_get_by_index(net, tcm->tcm_ifindex); 1867 + if (!dev) 1868 + return skb->len; 1869 + 1870 + parent = tcm->tcm_parent; 1871 + if (!parent) { 1872 + q = dev->qdisc; 1873 + parent = q->handle; 1874 + } else { 1875 + q = qdisc_lookup(dev, TC_H_MAJ(tcm->tcm_parent)); 1876 + } 1877 + if (!q) 1878 + goto out; 1879 + cops = q->ops->cl_ops; 1880 + if (!cops) 1881 + goto out; 1882 + if (!cops->tcf_block) 1883 + goto out; 1884 + if (TC_H_MIN(tcm->tcm_parent)) { 1885 + cl = cops->find(q, tcm->tcm_parent); 1886 + if (cl == 0) 1887 + goto out; 1888 + } 1889 + block = cops->tcf_block(q, cl, NULL); 1890 + if (!block) 1891 + goto out; 1892 + if (tcf_block_shared(block)) 1893 + q = NULL; 1894 + } 1895 + 1896 + index_start = cb->args[0]; 1897 + index = 0; 1898 + 1899 + list_for_each_entry(chain, &block->chain_list, list) { 1900 + if ((tca[TCA_CHAIN] && 1901 + nla_get_u32(tca[TCA_CHAIN]) != chain->index)) 1902 + continue; 1903 + if (index < index_start) { 1904 + index++; 1905 + continue; 1906 + } 1907 + err = tc_chain_fill_node(chain, net, skb, block, 1908 + NETLINK_CB(cb->skb).portid, 1909 + cb->nlh->nlmsg_seq, NLM_F_MULTI, 1910 + RTM_NEWCHAIN); 1911 + if (err <= 0) 1912 + break; 1913 + index++; 1914 + } 1915 + 1916 + cb->args[0] = index; 1917 + 1918 + out: 1919 + /* If we did no progress, the error (EMSGSIZE) is real */ 1920 + if (skb->len == 0 && err) 1921 + return err; 1922 + return skb->len; 1923 + } 1924 + 1651 1925 void tcf_exts_destroy(struct tcf_exts *exts) 1652 1926 { 1653 1927 #ifdef CONFIG_NET_CLS_ACT ··· 2178 1824 rtnl_register(PF_UNSPEC, RTM_DELTFILTER, tc_del_tfilter, NULL, 0); 2179 1825 rtnl_register(PF_UNSPEC, RTM_GETTFILTER, tc_get_tfilter, 2180 1826 tc_dump_tfilter, 0); 1827 + rtnl_register(PF_UNSPEC, RTM_NEWCHAIN, tc_ctl_chain, NULL, 0); 1828 + rtnl_register(PF_UNSPEC, RTM_DELCHAIN, tc_ctl_chain, NULL, 0); 1829 + rtnl_register(PF_UNSPEC, RTM_GETCHAIN, tc_ctl_chain, 1830 + tc_dump_chain, 0); 2181 1831 2182 1832 return 0; 2183 1833
+203 -47
net/sched/cls_flower.c
··· 72 72 struct list_head list; 73 73 }; 74 74 75 + struct fl_flow_tmplt { 76 + struct fl_flow_key dummy_key; 77 + struct fl_flow_key mask; 78 + struct flow_dissector dissector; 79 + struct tcf_chain *chain; 80 + }; 81 + 75 82 struct cls_fl_head { 76 83 struct rhashtable ht; 77 84 struct list_head masks; ··· 152 145 153 146 for (i = 0; i < fl_mask_range(mask); i += sizeof(long)) 154 147 *lmkey++ = *lkey++ & *lmask++; 148 + } 149 + 150 + static bool fl_mask_fits_tmplt(struct fl_flow_tmplt *tmplt, 151 + struct fl_flow_mask *mask) 152 + { 153 + const long *lmask = fl_key_get_start(&mask->key, mask); 154 + const long *ltmplt; 155 + int i; 156 + 157 + if (!tmplt) 158 + return true; 159 + ltmplt = fl_key_get_start(&tmplt->mask, mask); 160 + for (i = 0; i < fl_mask_range(mask); i += sizeof(long)) { 161 + if (~*ltmplt++ & *lmask++) 162 + return false; 163 + } 164 + return true; 155 165 } 156 166 157 167 static void fl_clear_masked_range(struct fl_flow_key *key, ··· 850 826 FL_KEY_SET(keys, cnt, id, member); \ 851 827 } while(0); 852 828 853 - static void fl_init_dissector(struct fl_flow_mask *mask) 829 + static void fl_init_dissector(struct flow_dissector *dissector, 830 + struct fl_flow_key *mask) 854 831 { 855 832 struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX]; 856 833 size_t cnt = 0; 857 834 858 835 FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control); 859 836 FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic); 860 - FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 837 + FL_KEY_SET_IF_MASKED(mask, keys, cnt, 861 838 FLOW_DISSECTOR_KEY_ETH_ADDRS, eth); 862 - FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 839 + FL_KEY_SET_IF_MASKED(mask, keys, cnt, 863 840 FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4); 864 - FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 841 + FL_KEY_SET_IF_MASKED(mask, keys, cnt, 865 842 FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6); 866 - FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 843 + FL_KEY_SET_IF_MASKED(mask, keys, cnt, 867 844 FLOW_DISSECTOR_KEY_PORTS, tp); 868 - FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 845 + FL_KEY_SET_IF_MASKED(mask, keys, cnt, 869 846 FLOW_DISSECTOR_KEY_IP, ip); 870 - FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 847 + FL_KEY_SET_IF_MASKED(mask, keys, cnt, 871 848 FLOW_DISSECTOR_KEY_TCP, tcp); 872 - FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 849 + FL_KEY_SET_IF_MASKED(mask, keys, cnt, 873 850 FLOW_DISSECTOR_KEY_ICMP, icmp); 874 - FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 851 + FL_KEY_SET_IF_MASKED(mask, keys, cnt, 875 852 FLOW_DISSECTOR_KEY_ARP, arp); 876 - FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 853 + FL_KEY_SET_IF_MASKED(mask, keys, cnt, 877 854 FLOW_DISSECTOR_KEY_MPLS, mpls); 878 - FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 855 + FL_KEY_SET_IF_MASKED(mask, keys, cnt, 879 856 FLOW_DISSECTOR_KEY_VLAN, vlan); 880 - FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 857 + FL_KEY_SET_IF_MASKED(mask, keys, cnt, 881 858 FLOW_DISSECTOR_KEY_CVLAN, cvlan); 882 - FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 859 + FL_KEY_SET_IF_MASKED(mask, keys, cnt, 883 860 FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id); 884 - FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 861 + FL_KEY_SET_IF_MASKED(mask, keys, cnt, 885 862 FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, enc_ipv4); 886 - FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 863 + FL_KEY_SET_IF_MASKED(mask, keys, cnt, 887 864 FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, enc_ipv6); 888 - if (FL_KEY_IS_MASKED(&mask->key, enc_ipv4) || 889 - FL_KEY_IS_MASKED(&mask->key, enc_ipv6)) 865 + if (FL_KEY_IS_MASKED(mask, enc_ipv4) || 866 + FL_KEY_IS_MASKED(mask, enc_ipv6)) 890 867 FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_ENC_CONTROL, 891 868 enc_control); 892 - FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 869 + FL_KEY_SET_IF_MASKED(mask, keys, cnt, 893 870 FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp); 894 - FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 871 + FL_KEY_SET_IF_MASKED(mask, keys, cnt, 895 872 FLOW_DISSECTOR_KEY_ENC_IP, enc_ip); 896 873 897 - skb_flow_dissector_init(&mask->dissector, keys, cnt); 874 + skb_flow_dissector_init(dissector, keys, cnt); 898 875 } 899 876 900 877 static struct fl_flow_mask *fl_create_new_mask(struct cls_fl_head *head, ··· 914 889 if (err) 915 890 goto errout_free; 916 891 917 - fl_init_dissector(newmask); 892 + fl_init_dissector(&newmask->dissector, &newmask->key); 918 893 919 894 INIT_LIST_HEAD_RCU(&newmask->filters); 920 895 ··· 963 938 struct cls_fl_filter *f, struct fl_flow_mask *mask, 964 939 unsigned long base, struct nlattr **tb, 965 940 struct nlattr *est, bool ovr, 941 + struct fl_flow_tmplt *tmplt, 966 942 struct netlink_ext_ack *extack) 967 943 { 968 944 int err; ··· 983 957 984 958 fl_mask_update_range(mask); 985 959 fl_set_masked_key(&f->mkey, &f->key, mask); 960 + 961 + if (!fl_mask_fits_tmplt(tmplt, mask)) { 962 + NL_SET_ERR_MSG_MOD(extack, "Mask does not fit the template"); 963 + return -EINVAL; 964 + } 986 965 987 966 return 0; 988 967 } ··· 1054 1023 } 1055 1024 1056 1025 err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr, 1057 - extack); 1026 + tp->chain->tmplt_priv, extack); 1058 1027 if (err) 1059 1028 goto errout_idr; 1060 1029 ··· 1194 1163 return 0; 1195 1164 } 1196 1165 1166 + static void fl_hw_create_tmplt(struct tcf_chain *chain, 1167 + struct fl_flow_tmplt *tmplt) 1168 + { 1169 + struct tc_cls_flower_offload cls_flower = {}; 1170 + struct tcf_block *block = chain->block; 1171 + struct tcf_exts dummy_exts = { 0, }; 1172 + 1173 + cls_flower.common.chain_index = chain->index; 1174 + cls_flower.command = TC_CLSFLOWER_TMPLT_CREATE; 1175 + cls_flower.cookie = (unsigned long) tmplt; 1176 + cls_flower.dissector = &tmplt->dissector; 1177 + cls_flower.mask = &tmplt->mask; 1178 + cls_flower.key = &tmplt->dummy_key; 1179 + cls_flower.exts = &dummy_exts; 1180 + 1181 + /* We don't care if driver (any of them) fails to handle this 1182 + * call. It serves just as a hint for it. 1183 + */ 1184 + tc_setup_cb_call(block, NULL, TC_SETUP_CLSFLOWER, 1185 + &cls_flower, false); 1186 + } 1187 + 1188 + static void fl_hw_destroy_tmplt(struct tcf_chain *chain, 1189 + struct fl_flow_tmplt *tmplt) 1190 + { 1191 + struct tc_cls_flower_offload cls_flower = {}; 1192 + struct tcf_block *block = chain->block; 1193 + 1194 + cls_flower.common.chain_index = chain->index; 1195 + cls_flower.command = TC_CLSFLOWER_TMPLT_DESTROY; 1196 + cls_flower.cookie = (unsigned long) tmplt; 1197 + 1198 + tc_setup_cb_call(block, NULL, TC_SETUP_CLSFLOWER, 1199 + &cls_flower, false); 1200 + } 1201 + 1202 + static void *fl_tmplt_create(struct net *net, struct tcf_chain *chain, 1203 + struct nlattr **tca, 1204 + struct netlink_ext_ack *extack) 1205 + { 1206 + struct fl_flow_tmplt *tmplt; 1207 + struct nlattr **tb; 1208 + int err; 1209 + 1210 + if (!tca[TCA_OPTIONS]) 1211 + return ERR_PTR(-EINVAL); 1212 + 1213 + tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL); 1214 + if (!tb) 1215 + return ERR_PTR(-ENOBUFS); 1216 + err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS], 1217 + fl_policy, NULL); 1218 + if (err) 1219 + goto errout_tb; 1220 + 1221 + tmplt = kzalloc(sizeof(*tmplt), GFP_KERNEL); 1222 + if (!tmplt) 1223 + goto errout_tb; 1224 + tmplt->chain = chain; 1225 + err = fl_set_key(net, tb, &tmplt->dummy_key, &tmplt->mask, extack); 1226 + if (err) 1227 + goto errout_tmplt; 1228 + kfree(tb); 1229 + 1230 + fl_init_dissector(&tmplt->dissector, &tmplt->mask); 1231 + 1232 + fl_hw_create_tmplt(chain, tmplt); 1233 + 1234 + return tmplt; 1235 + 1236 + errout_tmplt: 1237 + kfree(tmplt); 1238 + errout_tb: 1239 + kfree(tb); 1240 + return ERR_PTR(err); 1241 + } 1242 + 1243 + static void fl_tmplt_destroy(void *tmplt_priv) 1244 + { 1245 + struct fl_flow_tmplt *tmplt = tmplt_priv; 1246 + 1247 + fl_hw_destroy_tmplt(tmplt->chain, tmplt); 1248 + kfree(tmplt); 1249 + } 1250 + 1197 1251 static int fl_dump_key_val(struct sk_buff *skb, 1198 1252 void *val, int val_type, 1199 1253 void *mask, int mask_type, int len) ··· 1412 1296 return nla_put(skb, TCA_FLOWER_KEY_FLAGS_MASK, 4, &_mask); 1413 1297 } 1414 1298 1415 - static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh, 1416 - struct sk_buff *skb, struct tcmsg *t) 1299 + static int fl_dump_key(struct sk_buff *skb, struct net *net, 1300 + struct fl_flow_key *key, struct fl_flow_key *mask) 1417 1301 { 1418 - struct cls_fl_filter *f = fh; 1419 - struct nlattr *nest; 1420 - struct fl_flow_key *key, *mask; 1421 - 1422 - if (!f) 1423 - return skb->len; 1424 - 1425 - t->tcm_handle = f->handle; 1426 - 1427 - nest = nla_nest_start(skb, TCA_OPTIONS); 1428 - if (!nest) 1429 - goto nla_put_failure; 1430 - 1431 - if (f->res.classid && 1432 - nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid)) 1433 - goto nla_put_failure; 1434 - 1435 - key = &f->key; 1436 - mask = &f->mask->key; 1437 - 1438 1302 if (mask->indev_ifindex) { 1439 1303 struct net_device *dev; 1440 1304 ··· 1422 1326 if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name)) 1423 1327 goto nla_put_failure; 1424 1328 } 1425 - 1426 - if (!tc_skip_hw(f->flags)) 1427 - fl_hw_update_stats(tp, f); 1428 1329 1429 1330 if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST, 1430 1331 mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK, ··· 1598 1505 if (fl_dump_key_flags(skb, key->control.flags, mask->control.flags)) 1599 1506 goto nla_put_failure; 1600 1507 1508 + return 0; 1509 + 1510 + nla_put_failure: 1511 + return -EMSGSIZE; 1512 + } 1513 + 1514 + static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh, 1515 + struct sk_buff *skb, struct tcmsg *t) 1516 + { 1517 + struct cls_fl_filter *f = fh; 1518 + struct nlattr *nest; 1519 + struct fl_flow_key *key, *mask; 1520 + 1521 + if (!f) 1522 + return skb->len; 1523 + 1524 + t->tcm_handle = f->handle; 1525 + 1526 + nest = nla_nest_start(skb, TCA_OPTIONS); 1527 + if (!nest) 1528 + goto nla_put_failure; 1529 + 1530 + if (f->res.classid && 1531 + nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid)) 1532 + goto nla_put_failure; 1533 + 1534 + key = &f->key; 1535 + mask = &f->mask->key; 1536 + 1537 + if (fl_dump_key(skb, net, key, mask)) 1538 + goto nla_put_failure; 1539 + 1540 + if (!tc_skip_hw(f->flags)) 1541 + fl_hw_update_stats(tp, f); 1542 + 1601 1543 if (f->flags && nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags)) 1602 1544 goto nla_put_failure; 1603 1545 ··· 1649 1521 nla_put_failure: 1650 1522 nla_nest_cancel(skb, nest); 1651 1523 return -1; 1524 + } 1525 + 1526 + static int fl_tmplt_dump(struct sk_buff *skb, struct net *net, void *tmplt_priv) 1527 + { 1528 + struct fl_flow_tmplt *tmplt = tmplt_priv; 1529 + struct fl_flow_key *key, *mask; 1530 + struct nlattr *nest; 1531 + 1532 + nest = nla_nest_start(skb, TCA_OPTIONS); 1533 + if (!nest) 1534 + goto nla_put_failure; 1535 + 1536 + key = &tmplt->dummy_key; 1537 + mask = &tmplt->mask; 1538 + 1539 + if (fl_dump_key(skb, net, key, mask)) 1540 + goto nla_put_failure; 1541 + 1542 + nla_nest_end(skb, nest); 1543 + 1544 + return skb->len; 1545 + 1546 + nla_put_failure: 1547 + nla_nest_cancel(skb, nest); 1548 + return -EMSGSIZE; 1652 1549 } 1653 1550 1654 1551 static void fl_bind_class(void *fh, u32 classid, unsigned long cl) ··· 1696 1543 .reoffload = fl_reoffload, 1697 1544 .dump = fl_dump, 1698 1545 .bind_class = fl_bind_class, 1546 + .tmplt_create = fl_tmplt_create, 1547 + .tmplt_destroy = fl_tmplt_destroy, 1548 + .tmplt_dump = fl_tmplt_dump, 1699 1549 .owner = THIS_MODULE, 1700 1550 }; 1701 1551
+1 -1
security/selinux/nlmsgtab.c
··· 159 159 switch (sclass) { 160 160 case SECCLASS_NETLINK_ROUTE_SOCKET: 161 161 /* RTM_MAX always point to RTM_SETxxxx, ie RTM_NEWxxx + 3 */ 162 - BUILD_BUG_ON(RTM_MAX != (RTM_NEWCACHEREPORT + 3)); 162 + BUILD_BUG_ON(RTM_MAX != (RTM_NEWCHAIN + 3)); 163 163 err = nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms, 164 164 sizeof(nlmsg_route_perms)); 165 165 break;
+12
tools/testing/selftests/net/forwarding/lib.sh
··· 33 33 echo "SKIP: iproute2 too old; tc is missing JSON support" 34 34 exit 1 35 35 fi 36 + } 36 37 38 + check_tc_shblock_support() 39 + { 37 40 tc filter help 2>&1 | grep block &> /dev/null 38 41 if [[ $? -ne 0 ]]; then 39 42 echo "SKIP: iproute2 too old; tc is missing shared block support" 43 + exit 1 44 + fi 45 + } 46 + 47 + check_tc_chain_support() 48 + { 49 + tc help 2>&1|grep chain &> /dev/null 50 + if [[ $? -ne 0 ]]; then 51 + echo "SKIP: iproute2 too old; tc is missing chain support" 40 52 exit 1 41 53 fi 42 54 }
+64 -1
tools/testing/selftests/net/forwarding/tc_chains.sh
··· 1 1 #!/bin/bash 2 2 # SPDX-License-Identifier: GPL-2.0 3 3 4 - ALL_TESTS="unreachable_chain_test gact_goto_chain_test" 4 + ALL_TESTS="unreachable_chain_test gact_goto_chain_test create_destroy_chain \ 5 + template_filter_fits" 5 6 NUM_NETIFS=2 6 7 source tc_common.sh 7 8 source lib.sh ··· 81 80 log_test "gact goto chain ($tcflags)" 82 81 } 83 82 83 + create_destroy_chain() 84 + { 85 + RET=0 86 + 87 + tc chain add dev $h2 ingress 88 + check_err $? "Failed to create default chain" 89 + 90 + tc chain add dev $h2 ingress chain 1 91 + check_err $? "Failed to create chain 1" 92 + 93 + tc chain del dev $h2 ingress 94 + check_err $? "Failed to destroy default chain" 95 + 96 + tc chain del dev $h2 ingress chain 1 97 + check_err $? "Failed to destroy chain 1" 98 + 99 + log_test "create destroy chain" 100 + } 101 + 102 + template_filter_fits() 103 + { 104 + RET=0 105 + 106 + tc chain add dev $h2 ingress protocol ip \ 107 + flower dst_mac 00:00:00:00:00:00/FF:FF:FF:FF:FF:FF &> /dev/null 108 + tc chain add dev $h2 ingress chain 1 protocol ip \ 109 + flower src_mac 00:00:00:00:00:00/FF:FF:FF:FF:FF:FF &> /dev/null 110 + 111 + tc filter add dev $h2 ingress protocol ip pref 1 handle 1101 \ 112 + flower dst_mac $h2mac action drop 113 + check_err $? "Failed to insert filter which fits template" 114 + 115 + tc filter add dev $h2 ingress protocol ip pref 1 handle 1102 \ 116 + flower src_mac $h2mac action drop &> /dev/null 117 + check_fail $? "Incorrectly succeded to insert filter which does not template" 118 + 119 + tc filter add dev $h2 ingress chain 1 protocol ip pref 1 handle 1101 \ 120 + flower src_mac $h2mac action drop 121 + check_err $? "Failed to insert filter which fits template" 122 + 123 + tc filter add dev $h2 ingress chain 1 protocol ip pref 1 handle 1102 \ 124 + flower dst_mac $h2mac action drop &> /dev/null 125 + check_fail $? "Incorrectly succeded to insert filter which does not template" 126 + 127 + tc filter del dev $h2 ingress chain 1 protocol ip pref 1 handle 1102 \ 128 + flower &> /dev/null 129 + tc filter del dev $h2 ingress chain 1 protocol ip pref 1 handle 1101 \ 130 + flower &> /dev/null 131 + 132 + tc filter del dev $h2 ingress protocol ip pref 1 handle 1102 \ 133 + flower &> /dev/null 134 + tc filter del dev $h2 ingress protocol ip pref 1 handle 1101 \ 135 + flower &> /dev/null 136 + 137 + tc chain del dev $h2 ingress chain 1 138 + tc chain del dev $h2 ingress 139 + 140 + log_test "template filter fits" 141 + } 142 + 84 143 setup_prepare() 85 144 { 86 145 h1=${NETIFS[p1]} ··· 163 102 164 103 vrf_cleanup 165 104 } 105 + 106 + check_tc_chain_support 166 107 167 108 trap cleanup EXIT 168 109
+2
tools/testing/selftests/net/forwarding/tc_shblocks.sh
··· 105 105 ip link set $swp2 address $swp2origmac 106 106 } 107 107 108 + check_tc_shblock_support 109 + 108 110 trap cleanup EXIT 109 111 110 112 setup_prepare