Skip to content

Commit 89f9ffd

Browse files
vladimirolteandavem330
authored andcommitted
net: mscc: ocelot: deal with problematic MAC_ETYPE VCAP IS2 rules
By default, the VCAP IS2 will produce a single match for each frame, on the most specific classification. Example: a ping packet (ICMP over IPv4 over Ethernet) sent from an IP address of 10.0.0.1 and a MAC address of 96:18:82:00:04:01 will match this rule: tc filter add dev swp0 ingress protocol ipv4 \ flower skip_sw src_ip 10.0.0.1 action drop but not this one: tc filter add dev swp0 ingress \ flower skip_sw src_mac 96:18:82:00:04:01 action drop Currently the driver does not really warn the user in any way about this, and the behavior is rather strange anyway. The current patch is a workaround to force matches on MAC_ETYPE keys (DMAC and SMAC) for all packets irrespective of higher layer protocol. The setting is made at the port level. Of course this breaks all other non-src_mac and non-dst_mac matches, so rule exclusivity checks have been added to the driver, in order to never have rules of both types on any ingress port. The bits that discard higher-level protocol information are set only once a MAC_ETYPE rule is added to a filter block, and only for the ports that are bound to that filter block. Then all further non-MAC_ETYPE rules added to that filter block should be denied by the ports bound to it. Signed-off-by: Vladimir Oltean <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f89370d commit 89f9ffd

File tree

3 files changed

+106
-4
lines changed

3 files changed

+106
-4
lines changed

drivers/net/ethernet/mscc/ocelot_ace.c

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -706,13 +706,114 @@ ocelot_ace_rule_get_rule_index(struct ocelot_acl_block *block, int index)
706706
return NULL;
707707
}
708708

709+
/* If @on=false, then SNAP, ARP, IP and OAM frames will not match on keys based
710+
* on destination and source MAC addresses, but only on higher-level protocol
711+
* information. The only frame types to match on keys containing MAC addresses
712+
* in this case are non-SNAP, non-ARP, non-IP and non-OAM frames.
713+
*
714+
* If @on=true, then the above frame types (SNAP, ARP, IP and OAM) will match
715+
* on MAC_ETYPE keys such as destination and source MAC on this ingress port.
716+
* However the setting has the side effect of making these frames not matching
717+
* on any _other_ keys than MAC_ETYPE ones.
718+
*/
719+
static void ocelot_match_all_as_mac_etype(struct ocelot *ocelot, int port,
720+
bool on)
721+
{
722+
u32 val = 0;
723+
724+
if (on)
725+
val = ANA_PORT_VCAP_S2_CFG_S2_SNAP_DIS(3) |
726+
ANA_PORT_VCAP_S2_CFG_S2_ARP_DIS(3) |
727+
ANA_PORT_VCAP_S2_CFG_S2_IP_TCPUDP_DIS(3) |
728+
ANA_PORT_VCAP_S2_CFG_S2_IP_OTHER_DIS(3) |
729+
ANA_PORT_VCAP_S2_CFG_S2_OAM_DIS(3);
730+
731+
ocelot_rmw_gix(ocelot, val,
732+
ANA_PORT_VCAP_S2_CFG_S2_SNAP_DIS_M |
733+
ANA_PORT_VCAP_S2_CFG_S2_ARP_DIS_M |
734+
ANA_PORT_VCAP_S2_CFG_S2_IP_TCPUDP_DIS_M |
735+
ANA_PORT_VCAP_S2_CFG_S2_IP_OTHER_DIS_M |
736+
ANA_PORT_VCAP_S2_CFG_S2_OAM_DIS_M,
737+
ANA_PORT_VCAP_S2_CFG, port);
738+
}
739+
740+
static bool ocelot_ace_is_problematic_mac_etype(struct ocelot_ace_rule *ace)
741+
{
742+
if (ace->type != OCELOT_ACE_TYPE_ETYPE)
743+
return false;
744+
if (ether_addr_to_u64(ace->frame.etype.dmac.value) &
745+
ether_addr_to_u64(ace->frame.etype.dmac.mask))
746+
return true;
747+
if (ether_addr_to_u64(ace->frame.etype.smac.value) &
748+
ether_addr_to_u64(ace->frame.etype.smac.mask))
749+
return true;
750+
return false;
751+
}
752+
753+
static bool ocelot_ace_is_problematic_non_mac_etype(struct ocelot_ace_rule *ace)
754+
{
755+
if (ace->type == OCELOT_ACE_TYPE_SNAP)
756+
return true;
757+
if (ace->type == OCELOT_ACE_TYPE_ARP)
758+
return true;
759+
if (ace->type == OCELOT_ACE_TYPE_IPV4)
760+
return true;
761+
if (ace->type == OCELOT_ACE_TYPE_IPV6)
762+
return true;
763+
return false;
764+
}
765+
766+
static bool ocelot_exclusive_mac_etype_ace_rules(struct ocelot *ocelot,
767+
struct ocelot_ace_rule *ace)
768+
{
769+
struct ocelot_acl_block *block = &ocelot->acl_block;
770+
struct ocelot_ace_rule *tmp;
771+
unsigned long port;
772+
int i;
773+
774+
if (ocelot_ace_is_problematic_mac_etype(ace)) {
775+
/* Search for any non-MAC_ETYPE rules on the port */
776+
for (i = 0; i < block->count; i++) {
777+
tmp = ocelot_ace_rule_get_rule_index(block, i);
778+
if (tmp->ingress_port_mask & ace->ingress_port_mask &&
779+
ocelot_ace_is_problematic_non_mac_etype(tmp))
780+
return false;
781+
}
782+
783+
for_each_set_bit(port, &ace->ingress_port_mask,
784+
ocelot->num_phys_ports)
785+
ocelot_match_all_as_mac_etype(ocelot, port, true);
786+
} else if (ocelot_ace_is_problematic_non_mac_etype(ace)) {
787+
/* Search for any MAC_ETYPE rules on the port */
788+
for (i = 0; i < block->count; i++) {
789+
tmp = ocelot_ace_rule_get_rule_index(block, i);
790+
if (tmp->ingress_port_mask & ace->ingress_port_mask &&
791+
ocelot_ace_is_problematic_mac_etype(tmp))
792+
return false;
793+
}
794+
795+
for_each_set_bit(port, &ace->ingress_port_mask,
796+
ocelot->num_phys_ports)
797+
ocelot_match_all_as_mac_etype(ocelot, port, false);
798+
}
799+
800+
return true;
801+
}
802+
709803
int ocelot_ace_rule_offload_add(struct ocelot *ocelot,
710-
struct ocelot_ace_rule *rule)
804+
struct ocelot_ace_rule *rule,
805+
struct netlink_ext_ack *extack)
711806
{
712807
struct ocelot_acl_block *block = &ocelot->acl_block;
713808
struct ocelot_ace_rule *ace;
714809
int i, index;
715810

811+
if (!ocelot_exclusive_mac_etype_ace_rules(ocelot, rule)) {
812+
NL_SET_ERR_MSG_MOD(extack,
813+
"Cannot mix MAC_ETYPE with non-MAC_ETYPE rules");
814+
return -EBUSY;
815+
}
816+
716817
/* Add rule to the linked list */
717818
ocelot_ace_rule_add(ocelot, block, rule);
718819

drivers/net/ethernet/mscc/ocelot_ace.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ struct ocelot_ace_rule {
194194

195195
enum ocelot_ace_action action;
196196
struct ocelot_ace_stats stats;
197-
u16 ingress_port_mask;
197+
unsigned long ingress_port_mask;
198198

199199
enum ocelot_vcap_bit dmac_mc;
200200
enum ocelot_vcap_bit dmac_bc;
@@ -215,7 +215,8 @@ struct ocelot_ace_rule {
215215
};
216216

217217
int ocelot_ace_rule_offload_add(struct ocelot *ocelot,
218-
struct ocelot_ace_rule *rule);
218+
struct ocelot_ace_rule *rule,
219+
struct netlink_ext_ack *extack);
219220
int ocelot_ace_rule_offload_del(struct ocelot *ocelot,
220221
struct ocelot_ace_rule *rule);
221222
int ocelot_ace_rule_stats_update(struct ocelot *ocelot,

drivers/net/ethernet/mscc/ocelot_flower.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
205205
return ret;
206206
}
207207

208-
return ocelot_ace_rule_offload_add(ocelot, ace);
208+
return ocelot_ace_rule_offload_add(ocelot, ace, f->common.extack);
209209
}
210210
EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
211211

0 commit comments

Comments
 (0)