diff mbox series

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

Message ID 20200604123108.51367-1-xiangxia.m.yue@gmail.com
State Superseded
Headers show
Series [ovs-dev,ovs-dev] netdev-offload-tc: Allow installing arp rules to TC dp. | expand

Commit Message

Tonghao Zhang June 4, 2020, 12:31 p.m. UTC
From: Tonghao Zhang <xiangxia.m.yue@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@netronome.com>
Cc: Paul Blakey <paulb@mellanox.com>
Cc: Roi Dayan <roid@mellanox.com>
Cc: Ben Pfaff <blp@ovn.org>
Cc: William Tu <u9012063@gmail.com>
Cc: Ilya Maximets <i.maximets@ovn.org>
Signed-off-by: Tonghao Zhang <xiangxia.m.yue@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(-)

Comments

Simon Horman June 5, 2020, 8:12 a.m. UTC | #1
On Thu, Jun 04, 2020 at 08:31:08PM +0800, xiangxia.m.yue@gmail.com wrote:
> From: Tonghao Zhang <xiangxia.m.yue@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@netronome.com>
> Cc: Paul Blakey <paulb@mellanox.com>
> Cc: Roi Dayan <roid@mellanox.com>
> Cc: Ben Pfaff <blp@ovn.org>
> Cc: William Tu <u9012063@gmail.com>
> Cc: Ilya Maximets <i.maximets@ovn.org>
> Signed-off-by: Tonghao Zhang <xiangxia.m.yue@gmail.com>

Thanks for your patch, mostly it looks good to me.

Travis-CI flagged a minor problem, as described below.
Could you take a look into it and consider posting v2?

...

> 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);

This appears to cause a build error.

https://travis-ci.org/github/horms2/ovs/jobs/694632844#L2809

lib/odp-util.c:7997:36: error: restricted ovs_be16 degrades to integer
lib/odp-util.c:7996:17: error: incorrect type in assignment (different base types)
lib/odp-util.c:7996:17:    expected restricted ovs_be16 [usertype] arp_op
lib/odp-util.c:7996:17:    got int

Perhaps using OVS_BE16_MAX instead of UINT16_MAX is a good approach here.

Also, there should be a space both before and after ':'.
E.g.

	arp->arp_op = flow->nw_proto == UINT8_MAX ?
		OVS_BE16_MAX : htons(flow->nw_proto);

>      arp->arp_sha = flow->arp_sha;
>      arp->arp_tha = flow->arp_tha;
>  }

...
Tonghao Zhang June 5, 2020, 9:13 a.m. UTC | #2
On Fri, Jun 5, 2020 at 4:12 PM Simon Horman <simon.horman@netronome.com> wrote:
>
> On Thu, Jun 04, 2020 at 08:31:08PM +0800, xiangxia.m.yue@gmail.com wrote:
> > From: Tonghao Zhang <xiangxia.m.yue@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@netronome.com>
> > Cc: Paul Blakey <paulb@mellanox.com>
> > Cc: Roi Dayan <roid@mellanox.com>
> > Cc: Ben Pfaff <blp@ovn.org>
> > Cc: William Tu <u9012063@gmail.com>
> > Cc: Ilya Maximets <i.maximets@ovn.org>
> > Signed-off-by: Tonghao Zhang <xiangxia.m.yue@gmail.com>
>
> Thanks for your patch, mostly it looks good to me.
>
> Travis-CI flagged a minor problem, as described below.
> Could you take a look into it and consider posting v2?
Yes, I tested it on my host, but not found the build error. and run
the "make check"
I will fix it using the Travis-CI. Thanks for your reviews.
> ...
>
> > 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);
>
> This appears to cause a build error.
>
> https://travis-ci.org/github/horms2/ovs/jobs/694632844#L2809
>
> lib/odp-util.c:7997:36: error: restricted ovs_be16 degrades to integer
> lib/odp-util.c:7996:17: error: incorrect type in assignment (different base types)
> lib/odp-util.c:7996:17:    expected restricted ovs_be16 [usertype] arp_op
> lib/odp-util.c:7996:17:    got int
>
> Perhaps using OVS_BE16_MAX instead of UINT16_MAX is a good approach here.
>
> Also, there should be a space both before and after ':'.
> E.g.
>
>         arp->arp_op = flow->nw_proto == UINT8_MAX ?
>                 OVS_BE16_MAX : htons(flow->nw_proto);
>
> >      arp->arp_sha = flow->arp_sha;
> >      arp->arp_tha = flow->arp_tha;
> >  }
>
> ...
0-day Robot June 5, 2020, 10:53 p.m. UTC | #3
Bleep bloop.  Greetings Tonghao Zhang, I am a robot and I have tried out your patch.
Thanks for your contribution.

I encountered some error that I wasn't expecting.  See the details below.


git-am:
error: sha1 information is lacking or useless (lib/netdev-offload-tc.c).
error: could not build fake ancestor
hint: Use 'git am --show-current-patch' to see the failed patch
Patch failed at 0001 netdev-offload-tc: Allow installing arp rules to TC dp.
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".


Please check this out.  If you feel there has been an error, please email aconole@redhat.com

Thanks,
0-day Robot
Tonghao Zhang June 8, 2020, 1:25 a.m. UTC | #4
On Sat, Jun 6, 2020 at 6:55 AM 0-day Robot <robot@bytheb.org> wrote:
>
> Bleep bloop.  Greetings Tonghao Zhang, I am a robot and I have tried out your patch.
> Thanks for your contribution.
>
> I encountered some error that I wasn't expecting.  See the details below.
>
>
> git-am:
> error: sha1 information is lacking or useless (lib/netdev-offload-tc.c).
> error: could not build fake ancestor
> hint: Use 'git am --show-current-patch' to see the failed patch
> Patch failed at 0001 netdev-offload-tc: Allow installing arp rules to TC dp.
> When you have resolved this problem, run "git am --continue".
> If you prefer to skip this patch, run "git am --skip" instead.
> To restore the original branch and stop patching, run "git am --abort".
>
>
> Please check this out.  If you feel there has been an error, please email aconole@redhat.com
v2 has rebased the code
http://patchwork.ozlabs.org/project/openvswitch/patch/20200605131729.21410-1-xiangxia.m.yue@gmail.com/
> Thanks,
> 0-day Robot
diff mbox series

Patch

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;