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

net: mscc: ocelot: offload per-flow mirroring using tc-mirred and VCAP IS2

Per-flow mirroring with the VCAP IS2 TCAM (in itself handled as an
offload for tc-flower) is done by setting the MIRROR_ENA bit from the
action vector of the filter. The packet is mirrored to the port mask
configured in the ANA:ANA:MIRRORPORTS register (the same port mask as
the destinations for port-based mirroring).

Functionality was tested with:

tc qdisc add dev swp3 clsact
tc filter add dev swp3 ingress protocol ip \
flower skip_sw ip_proto icmp \
action mirred egress mirror dev swp1

and pinging through swp3, while seeing that the ICMP replies are
mirrored towards swp1.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Vladimir Oltean and committed by
Jakub Kicinski
f2a0e216 c3d427ea

+42 -3
+3 -3
drivers/net/ethernet/mscc/ocelot.c
··· 3023 3023 } 3024 3024 EXPORT_SYMBOL_GPL(ocelot_port_del_dscp_prio); 3025 3025 3026 - static struct ocelot_mirror *ocelot_mirror_get(struct ocelot *ocelot, int to, 3027 - struct netlink_ext_ack *extack) 3026 + struct ocelot_mirror *ocelot_mirror_get(struct ocelot *ocelot, int to, 3027 + struct netlink_ext_ack *extack) 3028 3028 { 3029 3029 struct ocelot_mirror *m = ocelot->mirror; 3030 3030 ··· 3053 3053 return m; 3054 3054 } 3055 3055 3056 - static void ocelot_mirror_put(struct ocelot *ocelot) 3056 + void ocelot_mirror_put(struct ocelot *ocelot) 3057 3057 { 3058 3058 struct ocelot_mirror *m = ocelot->mirror; 3059 3059
+4
drivers/net/ethernet/mscc/ocelot.h
··· 112 112 void (*populate)(struct ocelot_vcap_filter *f)); 113 113 int ocelot_trap_del(struct ocelot *ocelot, int port, unsigned long cookie); 114 114 115 + struct ocelot_mirror *ocelot_mirror_get(struct ocelot *ocelot, int to, 116 + struct netlink_ext_ack *extack); 117 + void ocelot_mirror_put(struct ocelot *ocelot); 118 + 115 119 extern struct notifier_block ocelot_netdevice_nb; 116 120 extern struct notifier_block ocelot_switchdev_nb; 117 121 extern struct notifier_block ocelot_switchdev_blocking_nb;
+21
drivers/net/ethernet/mscc/ocelot_flower.c
··· 359 359 filter->action.port_mask = BIT(egress_port); 360 360 filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 361 361 break; 362 + case FLOW_ACTION_MIRRED: 363 + if (filter->block_id != VCAP_IS2) { 364 + NL_SET_ERR_MSG_MOD(extack, 365 + "Mirror action can only be offloaded to VCAP IS2"); 366 + return -EOPNOTSUPP; 367 + } 368 + if (filter->goto_target != -1) { 369 + NL_SET_ERR_MSG_MOD(extack, 370 + "Last action must be GOTO"); 371 + return -EOPNOTSUPP; 372 + } 373 + egress_port = ocelot->ops->netdev_to_port(a->dev); 374 + if (egress_port < 0) { 375 + NL_SET_ERR_MSG_MOD(extack, 376 + "Destination not an ocelot port"); 377 + return -EOPNOTSUPP; 378 + } 379 + filter->egress_port.value = egress_port; 380 + filter->action.mirror_ena = true; 381 + filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 382 + break; 362 383 case FLOW_ACTION_VLAN_POP: 363 384 if (filter->block_id != VCAP_IS1) { 364 385 NL_SET_ERR_MSG_MOD(extack,
+12
drivers/net/ethernet/mscc/ocelot_vcap.c
··· 335 335 336 336 vcap_action_set(vcap, data, VCAP_IS2_ACT_MASK_MODE, a->mask_mode); 337 337 vcap_action_set(vcap, data, VCAP_IS2_ACT_PORT_MASK, a->port_mask); 338 + vcap_action_set(vcap, data, VCAP_IS2_ACT_MIRROR_ENA, a->mirror_ena); 338 339 vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_ENA, a->police_ena); 339 340 vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_IDX, a->pol_ix); 340 341 vcap_action_set(vcap, data, VCAP_IS2_ACT_CPU_QU_NUM, a->cpu_qu_num); ··· 961 960 struct ocelot_vcap_filter *filter, 962 961 struct netlink_ext_ack *extack) 963 962 { 963 + struct ocelot_mirror *m; 964 964 int ret; 965 + 966 + if (filter->block_id == VCAP_IS2 && filter->action.mirror_ena) { 967 + m = ocelot_mirror_get(ocelot, filter->egress_port.value, 968 + extack); 969 + if (IS_ERR(m)) 970 + return PTR_ERR(m); 971 + } 965 972 966 973 if (filter->block_id == VCAP_IS2 && filter->action.police_ena) { 967 974 ret = ocelot_vcap_policer_add(ocelot, filter->action.pol_ix, ··· 987 978 { 988 979 if (filter->block_id == VCAP_IS2 && filter->action.police_ena) 989 980 ocelot_vcap_policer_del(ocelot, filter->action.pol_ix); 981 + 982 + if (filter->block_id == VCAP_IS2 && filter->action.mirror_ena) 983 + ocelot_mirror_put(ocelot); 990 984 } 991 985 992 986 static int ocelot_vcap_filter_add_to_block(struct ocelot *ocelot,
+2
include/soc/mscc/ocelot_vcap.h
··· 654 654 enum ocelot_mask_mode mask_mode; 655 655 unsigned long port_mask; 656 656 bool police_ena; 657 + bool mirror_ena; 657 658 struct ocelot_policer pol; 658 659 u32 pol_ix; 659 660 }; ··· 698 697 unsigned long ingress_port_mask; 699 698 /* For VCAP ES0 */ 700 699 struct ocelot_vcap_port ingress_port; 700 + /* For VCAP IS2 mirrors and ES0 */ 701 701 struct ocelot_vcap_port egress_port; 702 702 703 703 enum ocelot_vcap_bit dmac_mc;