Skip to content

Commit ca46abd

Browse files
committed
Merge branch 'net-sched-allow-qdiscs-to-share-filter-block-instances'
Jiri Pirko says: ==================== net: sched: allow qdiscs to share filter block instances Currently the filters added to qdiscs are independent. So for example if you have 2 netdevices and you create ingress qdisc on both and you want to add identical filter rules both, you need to add them twice. This patchset makes this easier and mainly saves resources allowing to share all filters within a qdisc - I call it a "filter block". Also this helps to save resources when we do offload to hw for example to expensive TCAM. So back to the example. First, we create 2 qdiscs. Both will share block number 22. "22" is just an identification: $ tc qdisc add dev ens7 ingress_block 22 ingress ^^^^^^^^^^^^^^^^ $ tc qdisc add dev ens8 ingress_block 22 ingress ^^^^^^^^^^^^^^^^ If we don't specify "block" command line option, no shared block would be created: $ tc qdisc add dev ens9 ingress Now if we list the qdiscs, we will see the block index in the output: $ tc qdisc qdisc ingress ffff: dev ens7 parent ffff:fff1 ingress_block 22 qdisc ingress ffff: dev ens8 parent ffff:fff1 ingress_block 22 qdisc ingress ffff: dev ens9 parent ffff:fff1 To make is more visual, the situation looks like this: ens7 ingress qdisc ens7 ingress qdisc | | | | +----------> block 22 <----------+ Unlimited number of qdiscs may share the same block. Note that this patchset introduces block sharing support also for clsact qdisc: $ tc qdisc add dev ens10 ingress_block 23 egress_block 24 clsact $ tc qdisc show dev ens10 qdisc clsact ffff: dev ens10 parent ffff:fff1 ingress_block 23 egress_block 24 We can add filter using the block index: $ tc filter add block 22 protocol ip pref 25 flower dst_ip 192.168.0.0/16 action drop Note we cannot use the qdisc for filter manipulations of shared blocks: $ tc filter add dev ens8 ingress protocol ip pref 1 flower dst_ip 192.168.100.2 action drop Error: This filter block is shared. Please use the block index to manipulate the filters. We will see the same output if we list filters for ingress qdisc of ens7 and ens8, also for the block 22: $ tc filter show block 22 filter block 22 protocol ip pref 25 flower chain 0 filter block 22 protocol ip pref 25 flower chain 0 handle 0x1 ... $ tc filter show dev ens7 ingress filter block 22 protocol ip pref 25 flower chain 0 filter block 22 protocol ip pref 25 flower chain 0 handle 0x1 ... $ tc filter show dev ens8 ingress filter block 22 protocol ip pref 25 flower chain 0 filter block 22 protocol ip pref 25 flower chain 0 handle 0x1 ... --- v10->v11: - patch 2: - fixed error path when register_pernet_subsys fails pointed out by Cong - patch 9: - rebased on top of the current net-next v9->v10: - patch 7: - fixed ifindex magic in the patch description - userspace patches: - added manpages and patch descriptions v8->v9: - patch "net: sched: add rt netlink message type for block get" was removed, userspace check filter existence using qdisc dump v7->v8: - patch 7: - added comment to ifindex block magic - patch 9: - new patch - patch 10: - base this on the patch that introduces qdisc-generic block index attributes parsing/dumping - patch 13: - rebased on top of current net-next v6->v7: - patch 1: - unsquashed shared block patch that was previously squashed by mistake - fixed error path in block create - freeing chain 0 - patch 2: - new patch - splitted from the previous one as it got accidentaly squashed in the rebasing process in the past - converted to idr extended - removed auto-generating of block indexes. Callers have to explicily tell that the block is shared by passing non-zero block index - fixed error path in block get ext - freeing chain 0 - patch 7: - changed extack message for block index handle as suggested by DaveA - added extack message when block index does not exist - the block ifindex magic is in define and change to 0xffffffff as suggested by Jamal - patch 8: - new patch implementing RTM_GETBLOCK in order to query if the block with some index exists - patch 9: - adjust to the core changes and check block index attributes for being 0 v5->v6: - added patch 6 that introduces block handle v4->v5: - patch 5: - add tracking of binding of devs that are unable to offload and check that before block cbs call. v3->v4: - patch 1: - rebased on top of the current net-next - added some extack strings - patch 3: - rebased on top of the current net-next - patch 5: - propagate netdev_ops->ndo_setup_tc error up to tcf_block_offload_bind caller - patch 7: - rebased on top of the current net-next v2->v3: - removed original patch 1, removing tp->q cls_bpf dependency. Fixed by Jakub in the meantime. - patch 1: - rebased on top of the current net-next - patch 5: - new patch - patch 8: - removed "p_" prefix from block index function args - patch 10: - add tc offload feature handling ==================== Acked-by: David Ahern <[email protected]> Signed-off-by: David S. Miller <[email protected]>
2 parents c9a8242 + 4b23258 commit ca46abd

File tree

17 files changed

+1111
-322
lines changed

17 files changed

+1111
-322
lines changed

drivers/net/ethernet/mellanox/mlxsw/spectrum.c

Lines changed: 152 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1747,72 +1747,186 @@ static int mlxsw_sp_setup_tc_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port,
17471747
}
17481748

17491749
static int
1750-
mlxsw_sp_setup_tc_cls_flower(struct mlxsw_sp_port *mlxsw_sp_port,
1751-
struct tc_cls_flower_offload *f,
1752-
bool ingress)
1750+
mlxsw_sp_setup_tc_cls_flower(struct mlxsw_sp_acl_block *acl_block,
1751+
struct tc_cls_flower_offload *f)
17531752
{
1753+
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_acl_block_mlxsw_sp(acl_block);
1754+
17541755
switch (f->command) {
17551756
case TC_CLSFLOWER_REPLACE:
1756-
return mlxsw_sp_flower_replace(mlxsw_sp_port, ingress, f);
1757+
return mlxsw_sp_flower_replace(mlxsw_sp, acl_block, f);
17571758
case TC_CLSFLOWER_DESTROY:
1758-
mlxsw_sp_flower_destroy(mlxsw_sp_port, ingress, f);
1759+
mlxsw_sp_flower_destroy(mlxsw_sp, acl_block, f);
17591760
return 0;
17601761
case TC_CLSFLOWER_STATS:
1761-
return mlxsw_sp_flower_stats(mlxsw_sp_port, ingress, f);
1762+
return mlxsw_sp_flower_stats(mlxsw_sp, acl_block, f);
17621763
default:
17631764
return -EOPNOTSUPP;
17641765
}
17651766
}
17661767

1767-
static int mlxsw_sp_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
1768-
void *cb_priv, bool ingress)
1768+
static int mlxsw_sp_setup_tc_block_cb_matchall(enum tc_setup_type type,
1769+
void *type_data,
1770+
void *cb_priv, bool ingress)
17691771
{
17701772
struct mlxsw_sp_port *mlxsw_sp_port = cb_priv;
17711773

1772-
if (!tc_can_offload(mlxsw_sp_port->dev))
1773-
return -EOPNOTSUPP;
1774-
17751774
switch (type) {
17761775
case TC_SETUP_CLSMATCHALL:
1776+
if (!tc_can_offload(mlxsw_sp_port->dev))
1777+
return -EOPNOTSUPP;
1778+
17771779
return mlxsw_sp_setup_tc_cls_matchall(mlxsw_sp_port, type_data,
17781780
ingress);
17791781
case TC_SETUP_CLSFLOWER:
1780-
return mlxsw_sp_setup_tc_cls_flower(mlxsw_sp_port, type_data,
1781-
ingress);
1782+
return 0;
17821783
default:
17831784
return -EOPNOTSUPP;
17841785
}
17851786
}
17861787

1787-
static int mlxsw_sp_setup_tc_block_cb_ig(enum tc_setup_type type,
1788-
void *type_data, void *cb_priv)
1788+
static int mlxsw_sp_setup_tc_block_cb_matchall_ig(enum tc_setup_type type,
1789+
void *type_data,
1790+
void *cb_priv)
17891791
{
1790-
return mlxsw_sp_setup_tc_block_cb(type, type_data, cb_priv, true);
1792+
return mlxsw_sp_setup_tc_block_cb_matchall(type, type_data,
1793+
cb_priv, true);
17911794
}
17921795

1793-
static int mlxsw_sp_setup_tc_block_cb_eg(enum tc_setup_type type,
1794-
void *type_data, void *cb_priv)
1796+
static int mlxsw_sp_setup_tc_block_cb_matchall_eg(enum tc_setup_type type,
1797+
void *type_data,
1798+
void *cb_priv)
17951799
{
1796-
return mlxsw_sp_setup_tc_block_cb(type, type_data, cb_priv, false);
1800+
return mlxsw_sp_setup_tc_block_cb_matchall(type, type_data,
1801+
cb_priv, false);
1802+
}
1803+
1804+
static int mlxsw_sp_setup_tc_block_cb_flower(enum tc_setup_type type,
1805+
void *type_data, void *cb_priv)
1806+
{
1807+
struct mlxsw_sp_acl_block *acl_block = cb_priv;
1808+
1809+
switch (type) {
1810+
case TC_SETUP_CLSMATCHALL:
1811+
return 0;
1812+
case TC_SETUP_CLSFLOWER:
1813+
if (mlxsw_sp_acl_block_disabled(acl_block))
1814+
return -EOPNOTSUPP;
1815+
1816+
return mlxsw_sp_setup_tc_cls_flower(acl_block, type_data);
1817+
default:
1818+
return -EOPNOTSUPP;
1819+
}
1820+
}
1821+
1822+
static int
1823+
mlxsw_sp_setup_tc_block_flower_bind(struct mlxsw_sp_port *mlxsw_sp_port,
1824+
struct tcf_block *block, bool ingress)
1825+
{
1826+
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1827+
struct mlxsw_sp_acl_block *acl_block;
1828+
struct tcf_block_cb *block_cb;
1829+
int err;
1830+
1831+
block_cb = tcf_block_cb_lookup(block, mlxsw_sp_setup_tc_block_cb_flower,
1832+
mlxsw_sp);
1833+
if (!block_cb) {
1834+
acl_block = mlxsw_sp_acl_block_create(mlxsw_sp, block->net);
1835+
if (!acl_block)
1836+
return -ENOMEM;
1837+
block_cb = __tcf_block_cb_register(block,
1838+
mlxsw_sp_setup_tc_block_cb_flower,
1839+
mlxsw_sp, acl_block);
1840+
if (IS_ERR(block_cb)) {
1841+
err = PTR_ERR(block_cb);
1842+
goto err_cb_register;
1843+
}
1844+
} else {
1845+
acl_block = tcf_block_cb_priv(block_cb);
1846+
}
1847+
tcf_block_cb_incref(block_cb);
1848+
err = mlxsw_sp_acl_block_bind(mlxsw_sp, acl_block,
1849+
mlxsw_sp_port, ingress);
1850+
if (err)
1851+
goto err_block_bind;
1852+
1853+
if (ingress)
1854+
mlxsw_sp_port->ing_acl_block = acl_block;
1855+
else
1856+
mlxsw_sp_port->eg_acl_block = acl_block;
1857+
1858+
return 0;
1859+
1860+
err_block_bind:
1861+
if (!tcf_block_cb_decref(block_cb)) {
1862+
__tcf_block_cb_unregister(block_cb);
1863+
err_cb_register:
1864+
mlxsw_sp_acl_block_destroy(acl_block);
1865+
}
1866+
return err;
1867+
}
1868+
1869+
static void
1870+
mlxsw_sp_setup_tc_block_flower_unbind(struct mlxsw_sp_port *mlxsw_sp_port,
1871+
struct tcf_block *block, bool ingress)
1872+
{
1873+
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1874+
struct mlxsw_sp_acl_block *acl_block;
1875+
struct tcf_block_cb *block_cb;
1876+
int err;
1877+
1878+
block_cb = tcf_block_cb_lookup(block, mlxsw_sp_setup_tc_block_cb_flower,
1879+
mlxsw_sp);
1880+
if (!block_cb)
1881+
return;
1882+
1883+
if (ingress)
1884+
mlxsw_sp_port->ing_acl_block = NULL;
1885+
else
1886+
mlxsw_sp_port->eg_acl_block = NULL;
1887+
1888+
acl_block = tcf_block_cb_priv(block_cb);
1889+
err = mlxsw_sp_acl_block_unbind(mlxsw_sp, acl_block,
1890+
mlxsw_sp_port, ingress);
1891+
if (!err && !tcf_block_cb_decref(block_cb)) {
1892+
__tcf_block_cb_unregister(block_cb);
1893+
mlxsw_sp_acl_block_destroy(acl_block);
1894+
}
17971895
}
17981896

17991897
static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
18001898
struct tc_block_offload *f)
18011899
{
18021900
tc_setup_cb_t *cb;
1901+
bool ingress;
1902+
int err;
18031903

1804-
if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
1805-
cb = mlxsw_sp_setup_tc_block_cb_ig;
1806-
else if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
1807-
cb = mlxsw_sp_setup_tc_block_cb_eg;
1808-
else
1904+
if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
1905+
cb = mlxsw_sp_setup_tc_block_cb_matchall_ig;
1906+
ingress = true;
1907+
} else if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
1908+
cb = mlxsw_sp_setup_tc_block_cb_matchall_eg;
1909+
ingress = false;
1910+
} else {
18091911
return -EOPNOTSUPP;
1912+
}
18101913

18111914
switch (f->command) {
18121915
case TC_BLOCK_BIND:
1813-
return tcf_block_cb_register(f->block, cb, mlxsw_sp_port,
1814-
mlxsw_sp_port);
1916+
err = tcf_block_cb_register(f->block, cb, mlxsw_sp_port,
1917+
mlxsw_sp_port);
1918+
if (err)
1919+
return err;
1920+
err = mlxsw_sp_setup_tc_block_flower_bind(mlxsw_sp_port,
1921+
f->block, ingress);
1922+
if (err) {
1923+
tcf_block_cb_unregister(f->block, cb, mlxsw_sp_port);
1924+
return err;
1925+
}
1926+
return 0;
18151927
case TC_BLOCK_UNBIND:
1928+
mlxsw_sp_setup_tc_block_flower_unbind(mlxsw_sp_port,
1929+
f->block, ingress);
18161930
tcf_block_cb_unregister(f->block, cb, mlxsw_sp_port);
18171931
return 0;
18181932
default:
@@ -1842,10 +1956,18 @@ static int mlxsw_sp_feature_hw_tc(struct net_device *dev, bool enable)
18421956
{
18431957
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
18441958

1845-
if (!enable && (mlxsw_sp_port->acl_rule_count ||
1846-
!list_empty(&mlxsw_sp_port->mall_tc_list))) {
1847-
netdev_err(dev, "Active offloaded tc filters, can't turn hw_tc_offload off\n");
1848-
return -EINVAL;
1959+
if (!enable) {
1960+
if (mlxsw_sp_acl_block_rule_count(mlxsw_sp_port->ing_acl_block) ||
1961+
mlxsw_sp_acl_block_rule_count(mlxsw_sp_port->eg_acl_block) ||
1962+
!list_empty(&mlxsw_sp_port->mall_tc_list)) {
1963+
netdev_err(dev, "Active offloaded tc filters, can't turn hw_tc_offload off\n");
1964+
return -EINVAL;
1965+
}
1966+
mlxsw_sp_acl_block_disable_inc(mlxsw_sp_port->ing_acl_block);
1967+
mlxsw_sp_acl_block_disable_inc(mlxsw_sp_port->eg_acl_block);
1968+
} else {
1969+
mlxsw_sp_acl_block_disable_dec(mlxsw_sp_port->ing_acl_block);
1970+
mlxsw_sp_acl_block_disable_dec(mlxsw_sp_port->eg_acl_block);
18491971
}
18501972
return 0;
18511973
}

drivers/net/ethernet/mellanox/mlxsw/spectrum.h

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,8 @@ struct mlxsw_sp_port {
260260
struct list_head vlans_list;
261261
struct mlxsw_sp_qdisc *root_qdisc;
262262
unsigned acl_rule_count;
263+
struct mlxsw_sp_acl_block *ing_acl_block;
264+
struct mlxsw_sp_acl_block *eg_acl_block;
263265
};
264266

265267
static inline bool
@@ -468,8 +470,11 @@ struct mlxsw_sp_acl_profile_ops {
468470
void *priv, void *ruleset_priv);
469471
void (*ruleset_del)(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv);
470472
int (*ruleset_bind)(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv,
471-
struct net_device *dev, bool ingress);
472-
void (*ruleset_unbind)(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv);
473+
struct mlxsw_sp_port *mlxsw_sp_port,
474+
bool ingress);
475+
void (*ruleset_unbind)(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv,
476+
struct mlxsw_sp_port *mlxsw_sp_port,
477+
bool ingress);
473478
u16 (*ruleset_group_id)(void *ruleset_priv);
474479
size_t rule_priv_size;
475480
int (*rule_add)(struct mlxsw_sp *mlxsw_sp,
@@ -489,17 +494,34 @@ struct mlxsw_sp_acl_ops {
489494
enum mlxsw_sp_acl_profile profile);
490495
};
491496

497+
struct mlxsw_sp_acl_block;
492498
struct mlxsw_sp_acl_ruleset;
493499

494500
/* spectrum_acl.c */
495501
struct mlxsw_afk *mlxsw_sp_acl_afk(struct mlxsw_sp_acl *acl);
502+
struct mlxsw_sp *mlxsw_sp_acl_block_mlxsw_sp(struct mlxsw_sp_acl_block *block);
503+
unsigned int mlxsw_sp_acl_block_rule_count(struct mlxsw_sp_acl_block *block);
504+
void mlxsw_sp_acl_block_disable_inc(struct mlxsw_sp_acl_block *block);
505+
void mlxsw_sp_acl_block_disable_dec(struct mlxsw_sp_acl_block *block);
506+
bool mlxsw_sp_acl_block_disabled(struct mlxsw_sp_acl_block *block);
507+
struct mlxsw_sp_acl_block *mlxsw_sp_acl_block_create(struct mlxsw_sp *mlxsw_sp,
508+
struct net *net);
509+
void mlxsw_sp_acl_block_destroy(struct mlxsw_sp_acl_block *block);
510+
int mlxsw_sp_acl_block_bind(struct mlxsw_sp *mlxsw_sp,
511+
struct mlxsw_sp_acl_block *block,
512+
struct mlxsw_sp_port *mlxsw_sp_port,
513+
bool ingress);
514+
int mlxsw_sp_acl_block_unbind(struct mlxsw_sp *mlxsw_sp,
515+
struct mlxsw_sp_acl_block *block,
516+
struct mlxsw_sp_port *mlxsw_sp_port,
517+
bool ingress);
496518
struct mlxsw_sp_acl_ruleset *
497-
mlxsw_sp_acl_ruleset_lookup(struct mlxsw_sp *mlxsw_sp, struct net_device *dev,
498-
bool ingress, u32 chain_index,
519+
mlxsw_sp_acl_ruleset_lookup(struct mlxsw_sp *mlxsw_sp,
520+
struct mlxsw_sp_acl_block *block, u32 chain_index,
499521
enum mlxsw_sp_acl_profile profile);
500522
struct mlxsw_sp_acl_ruleset *
501-
mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp, struct net_device *dev,
502-
bool ingress, u32 chain_index,
523+
mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp,
524+
struct mlxsw_sp_acl_block *block, u32 chain_index,
503525
enum mlxsw_sp_acl_profile profile);
504526
void mlxsw_sp_acl_ruleset_put(struct mlxsw_sp *mlxsw_sp,
505527
struct mlxsw_sp_acl_ruleset *ruleset);
@@ -566,11 +588,14 @@ void mlxsw_sp_acl_fini(struct mlxsw_sp *mlxsw_sp);
566588
extern const struct mlxsw_sp_acl_ops mlxsw_sp_acl_tcam_ops;
567589

568590
/* spectrum_flower.c */
569-
int mlxsw_sp_flower_replace(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
591+
int mlxsw_sp_flower_replace(struct mlxsw_sp *mlxsw_sp,
592+
struct mlxsw_sp_acl_block *block,
570593
struct tc_cls_flower_offload *f);
571-
void mlxsw_sp_flower_destroy(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
594+
void mlxsw_sp_flower_destroy(struct mlxsw_sp *mlxsw_sp,
595+
struct mlxsw_sp_acl_block *block,
572596
struct tc_cls_flower_offload *f);
573-
int mlxsw_sp_flower_stats(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
597+
int mlxsw_sp_flower_stats(struct mlxsw_sp *mlxsw_sp,
598+
struct mlxsw_sp_acl_block *block,
574599
struct tc_cls_flower_offload *f);
575600

576601
/* spectrum_qdisc.c */

0 commit comments

Comments
 (0)