[ovs-dev] [PATCH ovs-dev] netdev-offload-tc: Allow installing arp rules to TC dp.

xiangxia.m.yue at gmail.com xiangxia.m.yue at gmail.com
Thu Jun 4 12:31:08 UTC 2020


From: Tonghao Zhang <xiangxia.m.yue at gmail.com>

This patch allows to install arp rules to tc dp.
In the future, arp will be offloaded to hardware to
be processed. So OvS enable this now.

$ ovs-appctl dpctl/add-flow 'recirc_id(0),in_port(3),eth(),\
  eth_type(0x0806),arp(op=2,tha=00:50:56:e1:4b:ab,tip=10.255.1.116)' 2

$ ovs-appctl dpctl/dump-flows
  ... arp(tip=10.255.1.116,op=2,tha=00:50:56:e1:4b:ab) ...

$ tc filter show dev <ethx> ingress
  ...
  eth_type arp
  arp_tip 10.255.1.116
  arp_op reply
  arp_tha 00:50:56:e1:4b:ab
  not_in_hw
    action order 1: mirred (Egress Redirect to device <ethy>) stolen
    ...

Cc: Simon Horman <simon.horman at netronome.com>
Cc: Paul Blakey <paulb at mellanox.com>
Cc: Roi Dayan <roid at mellanox.com>
Cc: Ben Pfaff <blp at ovn.org>
Cc: William Tu <u9012063 at gmail.com>
Cc: Ilya Maximets <i.maximets at ovn.org>
Signed-off-by: Tonghao Zhang <xiangxia.m.yue at gmail.com>
---
 include/openvswitch/match.h | 11 +++++++
 lib/match.c                 | 32 ++++++++++++++++++
 lib/netdev-offload-tc.c     | 27 +++++++++++++++
 lib/odp-util.c              |  3 +-
 lib/tc.c                    | 66 +++++++++++++++++++++++++++++++++++++
 lib/tc.h                    |  8 +++++
 6 files changed, 146 insertions(+), 1 deletion(-)

diff --git a/include/openvswitch/match.h b/include/openvswitch/match.h
index 3b196c7fa462..9e480318e2b3 100644
--- a/include/openvswitch/match.h
+++ b/include/openvswitch/match.h
@@ -197,6 +197,8 @@ void match_set_tp_dst_masked(struct match *, ovs_be16 port, ovs_be16 mask);
 void match_set_tcp_flags(struct match *, ovs_be16);
 void match_set_tcp_flags_masked(struct match *, ovs_be16 flags, ovs_be16 mask);
 void match_set_nw_proto(struct match *, uint8_t);
+void match_set_nw_proto_masked(struct match *match,
+                               const uint8_t nw_proto, const uint8_t mask);
 void match_set_nw_src(struct match *, ovs_be32);
 void match_set_nw_src_masked(struct match *, ovs_be32 ip, ovs_be32 mask);
 void match_set_nw_dst(struct match *, ovs_be32);
@@ -210,6 +212,9 @@ void match_set_nw_frag(struct match *, uint8_t nw_frag);
 void match_set_nw_frag_masked(struct match *, uint8_t nw_frag, uint8_t mask);
 void match_set_icmp_type(struct match *, uint8_t);
 void match_set_icmp_code(struct match *, uint8_t);
+void match_set_arp_opcode_masked(struct match *match,
+                                 const uint8_t opcode,
+                                 const uint8_t mask);
 void match_set_arp_sha(struct match *, const struct eth_addr);
 void match_set_arp_sha_masked(struct match *,
                               const struct eth_addr arp_sha,
@@ -218,6 +223,12 @@ void match_set_arp_tha(struct match *, const struct eth_addr);
 void match_set_arp_tha_masked(struct match *,
                               const struct eth_addr arp_tha,
                               const struct eth_addr mask);
+void match_set_arp_spa_masked(struct match *match,
+                              const ovs_be32 arp_spa,
+                              const ovs_be32 mask);
+void match_set_arp_tpa_masked(struct match *match,
+                              const ovs_be32 arp_tpa,
+                              const ovs_be32 mask);
 void match_set_ipv6_src(struct match *, const struct in6_addr *);
 void match_set_ipv6_src_masked(struct match *, const struct in6_addr *,
                                const struct in6_addr *);
diff --git a/lib/match.c b/lib/match.c
index 29b25a73bab4..a77554851146 100644
--- a/lib/match.c
+++ b/lib/match.c
@@ -940,6 +940,14 @@ match_set_nw_proto(struct match *match, uint8_t nw_proto)
     match->wc.masks.nw_proto = UINT8_MAX;
 }
 
+void
+match_set_nw_proto_masked(struct match *match,
+                          const uint8_t nw_proto, const uint8_t mask)
+{
+    match->flow.nw_proto = nw_proto;
+    match->wc.masks.nw_proto = mask;
+}
+
 void
 match_set_nw_src(struct match *match, ovs_be32 nw_src)
 {
@@ -1033,6 +1041,30 @@ match_set_icmp_code(struct match *match, uint8_t icmp_code)
     match_set_tp_dst(match, htons(icmp_code));
 }
 
+void
+match_set_arp_opcode_masked(struct match *match,
+                            const uint8_t opcode,
+                            const uint8_t mask)
+{
+    match_set_nw_proto_masked(match, opcode, mask);
+}
+
+void
+match_set_arp_spa_masked(struct match *match,
+                         const ovs_be32 arp_spa,
+                         const ovs_be32 mask)
+{
+    match_set_nw_src_masked(match, arp_spa, mask);
+}
+
+void
+match_set_arp_tpa_masked(struct match *match,
+                         const ovs_be32 arp_tpa,
+                         const ovs_be32 mask)
+{
+    match_set_nw_dst_masked(match, arp_tpa, mask);
+}
+
 void
 match_set_arp_sha(struct match *match, const struct eth_addr sha)
 {
diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c
index f7f9c231e3cf..c805e72ff616 100644
--- a/lib/netdev-offload-tc.c
+++ b/lib/netdev-offload-tc.c
@@ -543,6 +543,14 @@ parse_tc_flower_to_match(struct tc_flower *flower,
         match->flow.mpls_lse[0] = key->mpls_lse & mask->mpls_lse;
         match->wc.masks.mpls_lse[0] = mask->mpls_lse;
         match_set_dl_type(match, key->encap_eth_type[0]);
+    } else if (key->eth_type == htons(ETH_TYPE_ARP)){
+        match_set_arp_sha_masked(match, key->arp.sha, mask->arp.sha);
+        match_set_arp_tha_masked(match, key->arp.tha, mask->arp.tha);
+        match_set_arp_spa_masked(match, key->arp.spa, mask->arp.spa);
+        match_set_arp_tpa_masked(match, key->arp.tpa, mask->arp.tpa);
+        match_set_arp_opcode_masked(match, key->arp.opcode,
+                                    mask->arp.opcode);
+        match_set_dl_type(match, key->eth_type);
     } else {
         match_set_dl_type(match, key->eth_type);
     }
@@ -1521,6 +1529,25 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
     mask->dl_type = 0;
     mask->in_port.odp_port = 0;
 
+    if (key->dl_type == htons(ETH_P_ARP)) {
+            flower.key.arp.spa = key->nw_src;
+            flower.key.arp.tpa = key->nw_dst;
+            flower.key.arp.sha = key->arp_sha;
+            flower.key.arp.tha = key->arp_tha;
+            flower.key.arp.opcode = key->nw_proto;
+            flower.mask.arp.spa = mask->nw_src;
+            flower.mask.arp.tpa = mask->nw_dst;
+            flower.mask.arp.sha = mask->arp_sha;
+            flower.mask.arp.tha = mask->arp_tha;
+            flower.mask.arp.opcode = mask->nw_proto;
+
+            mask->nw_src = 0;
+            mask->nw_dst = 0;
+            mask->nw_proto = 0;
+            memset(&mask->arp_sha, 0, sizeof mask->arp_sha);
+            memset(&mask->arp_tha, 0, sizeof mask->arp_tha);
+    }
+
     if (is_ip_any(key)) {
         flower.key.ip_proto = key->nw_proto;
         flower.mask.ip_proto = mask->nw_proto;
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 72601dc6ba2b..c630b830ecd0 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -7993,7 +7993,8 @@ get_arp_key(const struct flow *flow, struct ovs_key_arp *arp)
 
     arp->arp_sip = flow->nw_src;
     arp->arp_tip = flow->nw_dst;
-    arp->arp_op = htons(flow->nw_proto);
+    arp->arp_op = flow->nw_proto == UINT8_MAX ?
+                  UINT16_MAX: htons(flow->nw_proto);
     arp->arp_sha = flow->arp_sha;
     arp->arp_tha = flow->arp_tha;
 }
diff --git a/lib/tc.c b/lib/tc.c
index ac5ecc2b7e6f..2eff3f903aa6 100644
--- a/lib/tc.c
+++ b/lib/tc.c
@@ -313,6 +313,24 @@ static const struct nl_policy tca_flower_policy[] = {
                                       .min_len = ETH_ALEN,
                                       .optional = true, },
     [TCA_FLOWER_KEY_ETH_TYPE] = { .type = NL_A_U16, .optional = false, },
+    [TCA_FLOWER_KEY_ARP_SIP] = { .type = NL_A_U32, .optional = true, },
+    [TCA_FLOWER_KEY_ARP_TIP] = { .type = NL_A_U32, .optional = true, },
+    [TCA_FLOWER_KEY_ARP_SHA] = { .type = NL_A_UNSPEC,
+                                 .min_len = ETH_ALEN,
+                                 .optional = true, },
+    [TCA_FLOWER_KEY_ARP_THA] = { .type = NL_A_UNSPEC,
+                                 .min_len = ETH_ALEN,
+                                 .optional = true, },
+    [TCA_FLOWER_KEY_ARP_OP] = { .type = NL_A_U8, .optional = true, },
+    [TCA_FLOWER_KEY_ARP_SIP_MASK] = { .type = NL_A_U32, .optional = true, },
+    [TCA_FLOWER_KEY_ARP_TIP_MASK] = { .type = NL_A_U32, .optional = true, },
+    [TCA_FLOWER_KEY_ARP_SHA_MASK] = { .type = NL_A_UNSPEC,
+                                      .min_len = ETH_ALEN,
+                                      .optional = true, },
+    [TCA_FLOWER_KEY_ARP_THA_MASK] = { .type = NL_A_UNSPEC,
+                                      .min_len = ETH_ALEN,
+                                      .optional = true, },
+    [TCA_FLOWER_KEY_ARP_OP_MASK] = { .type = NL_A_U8, .optional = true, },
     [TCA_FLOWER_FLAGS] = { .type = NL_A_U32, .optional = false, },
     [TCA_FLOWER_ACT] = { .type = NL_A_NESTED, .optional = false, },
     [TCA_FLOWER_KEY_IP_PROTO] = { .type = NL_A_U8, .optional = true, },
@@ -417,6 +435,45 @@ static const struct nl_policy tca_flower_policy[] = {
                                         .optional = true, },
 };
 
+static void
+nl_parse_flower_arp(struct nlattr **attrs, struct tc_flower *flower)
+{
+    const struct eth_addr *eth;
+
+    if (attrs[TCA_FLOWER_KEY_ARP_SIP_MASK]) {
+        flower->key.arp.spa =
+            nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ARP_SIP]);
+        flower->mask.arp.spa =
+            nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ARP_SIP_MASK]);
+    }
+    if (attrs[TCA_FLOWER_KEY_ARP_TIP_MASK]) {
+        flower->key.arp.tpa =
+            nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ARP_TIP]);
+        flower->mask.arp.tpa =
+            nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ARP_TIP_MASK]);
+    }
+    if (attrs[TCA_FLOWER_KEY_ARP_SHA_MASK]) {
+        eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ARP_SHA], ETH_ALEN);
+        memcpy(&flower->key.arp.sha, eth, sizeof flower->key.arp.sha);
+
+        eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ARP_SHA_MASK], ETH_ALEN);
+        memcpy(&flower->mask.arp.sha, eth, sizeof flower->mask.arp.sha);
+    }
+    if (attrs[TCA_FLOWER_KEY_ARP_THA_MASK]) {
+        eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ARP_THA], ETH_ALEN);
+        memcpy(&flower->key.arp.tha, eth, sizeof flower->key.arp.tha);
+
+        eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ARP_THA_MASK], ETH_ALEN);
+        memcpy(&flower->mask.arp.tha, eth, sizeof flower->mask.arp.tha);
+    }
+    if (attrs[TCA_FLOWER_KEY_ARP_OP_MASK]) {
+        flower->key.arp.opcode =
+            nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ARP_OP]);
+        flower->mask.arp.opcode =
+            nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ARP_OP_MASK]);
+    }
+}
+
 static void
 nl_parse_flower_eth(struct nlattr **attrs, struct tc_flower *flower)
 {
@@ -1735,6 +1792,7 @@ nl_parse_flower_options(struct nlattr *nl_options, struct tc_flower *flower)
     }
 
     nl_parse_flower_eth(attrs, flower);
+    nl_parse_flower_arp(attrs, flower);
     nl_parse_flower_mpls(attrs, flower);
     nl_parse_flower_vlan(attrs, flower);
     nl_parse_flower_ip(attrs, flower);
@@ -2712,6 +2770,14 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)
     FLOWER_PUT_MASKED_VALUE(dst_mac, TCA_FLOWER_KEY_ETH_DST);
     FLOWER_PUT_MASKED_VALUE(src_mac, TCA_FLOWER_KEY_ETH_SRC);
 
+    if (host_eth_type == ETH_P_ARP) {
+        FLOWER_PUT_MASKED_VALUE(arp.spa, TCA_FLOWER_KEY_ARP_SIP);
+        FLOWER_PUT_MASKED_VALUE(arp.tpa, TCA_FLOWER_KEY_ARP_TIP);
+        FLOWER_PUT_MASKED_VALUE(arp.sha, TCA_FLOWER_KEY_ARP_SHA);
+        FLOWER_PUT_MASKED_VALUE(arp.tha, TCA_FLOWER_KEY_ARP_THA);
+        FLOWER_PUT_MASKED_VALUE(arp.opcode, TCA_FLOWER_KEY_ARP_OP);
+    }
+
     if (host_eth_type == ETH_P_IP || host_eth_type == ETH_P_IPV6) {
         FLOWER_PUT_MASKED_VALUE(ip_ttl, TCA_FLOWER_KEY_IP_TTL);
         FLOWER_PUT_MASKED_VALUE(ip_tos, TCA_FLOWER_KEY_IP_TOS);
diff --git a/lib/tc.h b/lib/tc.h
index 24a4994fd17e..27e3e2a26a6e 100644
--- a/lib/tc.h
+++ b/lib/tc.h
@@ -121,6 +121,14 @@ struct tc_flower_key {
     uint32_t ct_mark;
     ovs_u128 ct_label;
 
+    struct {
+        ovs_be32 spa;
+        ovs_be32 tpa;
+        struct eth_addr sha;
+        struct eth_addr tha;
+        uint8_t opcode;
+    } arp;
+
     struct {
         ovs_be32 ipv4_src;
         ovs_be32 ipv4_dst;
-- 
2.26.1



More information about the dev mailing list