diff options
author | David S. Miller <davem@davemloft.net> | 2020-04-22 11:40:52 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2020-04-22 11:40:52 -0700 |
commit | a3b6e8fd27233e54e34e10aaedea4cba217183c5 (patch) | |
tree | 70dcc676be67e4eb2447140695bfd1faf35de6d2 | |
parent | 44dd5efc97dae0dc09ea9316597826c8b0fd1578 (diff) | |
parent | 4faa2e06433fbba16a13a21e1380ee4d246b95fc (diff) |
Merge branch 'Ocelot-MAC_ETYPE-tc-flower-key-improvements'
Vladimir Oltean says:
====================
Ocelot MAC_ETYPE tc-flower key improvements
As discussed in the comments surrounding this patch:
https://patchwork.ozlabs.org/project/netdev/patch/20200417190308.32598-1-olteanv@gmail.com/
the restrictions imposed on non-MAC_ETYPE rules were harsher than they
needed to be. IP, IPv6, ARP rules can still be added concurrently with
src_mac and dst_mac rules, as long as those MAC address rules do not ask
for an offending EtherType.
For that to actually be supported, we need to parse the EtherType from
the flower classification rule first.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/mscc/ocelot_ace.c | 18 | ||||
-rw-r--r-- | drivers/net/ethernet/mscc/ocelot_flower.c | 27 |
2 files changed, 33 insertions, 12 deletions
diff --git a/drivers/net/ethernet/mscc/ocelot_ace.c b/drivers/net/ethernet/mscc/ocelot_ace.c index 8a2f7d13ef6d..dfd82a3baab2 100644 --- a/drivers/net/ethernet/mscc/ocelot_ace.c +++ b/drivers/net/ethernet/mscc/ocelot_ace.c @@ -739,14 +739,24 @@ static void ocelot_match_all_as_mac_etype(struct ocelot *ocelot, int port, static bool ocelot_ace_is_problematic_mac_etype(struct ocelot_ace_rule *ace) { + u16 proto, mask; + if (ace->type != OCELOT_ACE_TYPE_ETYPE) return false; - if (ether_addr_to_u64(ace->frame.etype.dmac.value) & - ether_addr_to_u64(ace->frame.etype.dmac.mask)) + + proto = ntohs(*(u16 *)ace->frame.etype.etype.value); + mask = ntohs(*(u16 *)ace->frame.etype.etype.mask); + + /* ETH_P_ALL match, so all protocols below are included */ + if (mask == 0) return true; - if (ether_addr_to_u64(ace->frame.etype.smac.value) & - ether_addr_to_u64(ace->frame.etype.smac.mask)) + if (proto == ETH_P_ARP) return true; + if (proto == ETH_P_IP) + return true; + if (proto == ETH_P_IPV6) + return true; + return false; } diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c index 954cb67eeaa2..5ce172e22b43 100644 --- a/drivers/net/ethernet/mscc/ocelot_flower.c +++ b/drivers/net/ethernet/mscc/ocelot_flower.c @@ -51,6 +51,8 @@ static int ocelot_flower_parse(struct flow_cls_offload *f, { struct flow_rule *rule = flow_cls_offload_flow_rule(f); struct flow_dissector *dissector = rule->match.dissector; + u16 proto = ntohs(f->common.protocol); + bool match_protocol = true; if (dissector->used_keys & ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) | @@ -71,7 +73,6 @@ static int ocelot_flower_parse(struct flow_cls_offload *f, if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { struct flow_match_eth_addrs match; - u16 proto = ntohs(f->common.protocol); /* The hw support mac matches only for MAC_ETYPE key, * therefore if other matches(port, tcp flags, etc) are added @@ -86,11 +87,6 @@ static int ocelot_flower_parse(struct flow_cls_offload *f, BIT(FLOW_DISSECTOR_KEY_CONTROL))) return -EOPNOTSUPP; - if (proto == ETH_P_IP || - proto == ETH_P_IPV6 || - proto == ETH_P_ARP) - return -EOPNOTSUPP; - flow_rule_match_eth_addrs(rule, &match); ace->type = OCELOT_ACE_TYPE_ETYPE; ether_addr_copy(ace->frame.etype.dmac.value, @@ -114,6 +110,7 @@ static int ocelot_flower_parse(struct flow_cls_offload *f, match.key->ip_proto; ace->frame.ipv4.proto.mask[0] = match.mask->ip_proto; + match_protocol = false; } if (ntohs(match.key->n_proto) == ETH_P_IPV6) { ace->type = OCELOT_ACE_TYPE_IPV6; @@ -121,11 +118,12 @@ static int ocelot_flower_parse(struct flow_cls_offload *f, match.key->ip_proto; ace->frame.ipv6.proto.mask[0] = match.mask->ip_proto; + match_protocol = false; } } if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) && - ntohs(f->common.protocol) == ETH_P_IP) { + proto == ETH_P_IP) { struct flow_match_ipv4_addrs match; u8 *tmp; @@ -141,10 +139,11 @@ static int ocelot_flower_parse(struct flow_cls_offload *f, tmp = &ace->frame.ipv4.dip.mask.addr[0]; memcpy(tmp, &match.mask->dst, 4); + match_protocol = false; } if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) && - ntohs(f->common.protocol) == ETH_P_IPV6) { + proto == ETH_P_IPV6) { return -EOPNOTSUPP; } @@ -156,6 +155,7 @@ static int ocelot_flower_parse(struct flow_cls_offload *f, ace->frame.ipv4.sport.mask = ntohs(match.mask->src); ace->frame.ipv4.dport.value = ntohs(match.key->dst); ace->frame.ipv4.dport.mask = ntohs(match.mask->dst); + match_protocol = false; } if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) { @@ -167,9 +167,20 @@ static int ocelot_flower_parse(struct flow_cls_offload *f, ace->vlan.vid.mask = match.mask->vlan_id; ace->vlan.pcp.value[0] = match.key->vlan_priority; ace->vlan.pcp.mask[0] = match.mask->vlan_priority; + match_protocol = false; } finished_key_parsing: + if (match_protocol && proto != ETH_P_ALL) { + /* TODO: support SNAP, LLC etc */ + if (proto < ETH_P_802_3_MIN) + return -EOPNOTSUPP; + ace->type = OCELOT_ACE_TYPE_ETYPE; + *(u16 *)ace->frame.etype.etype.value = htons(proto); + *(u16 *)ace->frame.etype.etype.mask = 0xffff; + } + /* else, a rule of type OCELOT_ACE_TYPE_ANY is implicitly added */ + ace->prio = f->common.prio; ace->id = f->cookie; return ocelot_flower_parse_action(f, ace); |