diff mbox

[ovs-dev] packets: Remove unnecessary "packed" annotations.

Message ID 20170525205206.1700-1-blp@ovn.org
State Accepted
Headers show

Commit Message

Ben Pfaff May 25, 2017, 8:52 p.m. UTC
I know of two reasons to mark a structure as "packed".  The first is
because the structure must match some defined interface and therefore
compiler-inserted padding between or after members would cause its layout
to diverge from that interface.  This is not a problem in a structure that
follows the general alignment rules that are seen in ABIs for all the
architectures that OVS cares about: basically, that a struct member needs
to be aligned on a boundary that is a multiple of the member's size.

The second reason is because instances of the struct tend to be at
misaligned addresses.

struct eth_header and struct vlan_eth_header are normally aligned on
16-bit boundaries (at least), and they contain only 16-bit members, so
there's no need to pack them.  This commit removes the packed annotation.

This commit also removes the packed annotation from struct llc_header.
Since that struct only contains 8-bit members, I don't know of any benefit
to packing it, period.

This commit also removes a few more packed annotations that are much less
important.

When these packed annotations were removed, it caused a few warnings
related to casts from 'uint8_t *' to more strictly aligned pointer types,
related to struct ovs_action_push_tnl.  That's because that struct had a
trailing member used to store packet headers, that was declared as
a uint8_t[].  Before, when this was cast to 'struct eth_header *', there
was no change in alignment since eth_header was packed; now that
eth_header is not packed, the compiler considers it suspicious.  This
commit avoids that problem by changing the member from uint8_t[] to
uint32_t[], which assures the compiler that it is properly aligned.

CC: Joe Stringer <joe@ovn.org>
Signed-off-by: Ben Pfaff <blp@ovn.org>
---
 datapath/linux/compat/include/linux/openvswitch.h | 2 +-
 lib/packets.h                                     | 9 +++------
 lib/stp.c                                         | 8 +++-----
 ofproto/bundles.h                                 | 4 ++--
 4 files changed, 9 insertions(+), 14 deletions(-)

Comments

Joe Stringer May 26, 2017, 9:04 p.m. UTC | #1
On 25 May 2017 at 13:52, Ben Pfaff <blp@ovn.org> wrote:
> I know of two reasons to mark a structure as "packed".  The first is
> because the structure must match some defined interface and therefore
> compiler-inserted padding between or after members would cause its layout
> to diverge from that interface.  This is not a problem in a structure that
> follows the general alignment rules that are seen in ABIs for all the
> architectures that OVS cares about: basically, that a struct member needs
> to be aligned on a boundary that is a multiple of the member's size.
>
> The second reason is because instances of the struct tend to be at
> misaligned addresses.
>
> struct eth_header and struct vlan_eth_header are normally aligned on
> 16-bit boundaries (at least), and they contain only 16-bit members, so
> there's no need to pack them.  This commit removes the packed annotation.
>
> This commit also removes the packed annotation from struct llc_header.
> Since that struct only contains 8-bit members, I don't know of any benefit
> to packing it, period.
>
> This commit also removes a few more packed annotations that are much less
> important.
>
> When these packed annotations were removed, it caused a few warnings
> related to casts from 'uint8_t *' to more strictly aligned pointer types,
> related to struct ovs_action_push_tnl.  That's because that struct had a
> trailing member used to store packet headers, that was declared as
> a uint8_t[].  Before, when this was cast to 'struct eth_header *', there
> was no change in alignment since eth_header was packed; now that
> eth_header is not packed, the compiler considers it suspicious.  This
> commit avoids that problem by changing the member from uint8_t[] to
> uint32_t[], which assures the compiler that it is properly aligned.
>
> CC: Joe Stringer <joe@ovn.org>
> Signed-off-by: Ben Pfaff <blp@ovn.org>
> ---

Thanks for the patch, this fixes the primary issue I observed and
looking at the "pahole" output on vswitchd compiled by clang, it looks
mostly correct on my x86-64 dev box. Assuming you're not concerned by
the below feedback:
Acked-by: Joe Stringer <joe@ovn.org>

>  datapath/linux/compat/include/linux/openvswitch.h | 2 +-
>  lib/packets.h                                     | 9 +++------
>  lib/stp.c                                         | 8 +++-----
>  ofproto/bundles.h                                 | 4 ++--
>  4 files changed, 9 insertions(+), 14 deletions(-)
>
> diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
> index d22102e224a7..55ec6c13fbd2 100644
> --- a/datapath/linux/compat/include/linux/openvswitch.h
> +++ b/datapath/linux/compat/include/linux/openvswitch.h
> @@ -715,7 +715,7 @@ struct ovs_action_push_tnl {
>         uint32_t out_port;
>         uint32_t header_len;
>         uint32_t tnl_type;     /* For logging. */
> -       uint8_t  header[TNL_PUSH_HEADER_SIZE];
> +       uint32_t header[TNL_PUSH_HEADER_SIZE / 4];
>  };
>  #endif
>

Would you mind submitting this hunk upstream to net-next?

<snip>

> diff --git a/ofproto/bundles.h b/ofproto/bundles.h
> index dd64700aa348..b63681708d3b 100644
> --- a/ofproto/bundles.h
> +++ b/ofproto/bundles.h
> @@ -1,7 +1,7 @@
>  /*
>   * Copyright (c) 2013, 2014 Alexandru Copot <alex.mihai.c@gmail.com>, with support from IXIA.
>   * Copyright (c) 2013, 2014 Daniel Baluta <dbaluta@ixiacom.com>
> - * Copyright (c) 2014, 2015, 2016 Nicira, Inc.
> + * Copyright (c) 2014, 2015, 2016, 2017 Nicira, Inc.
>   *
>   * Licensed under the Apache License, Version 2.0 (the "License");
>   * you may not use this file except in compliance with the License.
> @@ -49,7 +49,7 @@ struct ofp_bundle_entry {
>      };
>  };
>
> -enum OVS_PACKED_ENUM bundle_state {
> +enum bundle_state {
>      BS_OPEN,
>      BS_CLOSED
>  };

This hunk actually appears to influence the layout of "struct
ofp_bundle" which increases the size by 8 bytes on my system. That
said, it still appears to be 2 cachelines long in both cases and I
don't know whether we are specifically trying to tailor the size of
this structure (eg, for performance reasons).
Ben Pfaff May 26, 2017, 10:14 p.m. UTC | #2
On Fri, May 26, 2017 at 02:04:23PM -0700, Joe Stringer wrote:
> On 25 May 2017 at 13:52, Ben Pfaff <blp@ovn.org> wrote:
> > I know of two reasons to mark a structure as "packed".  The first is
> > because the structure must match some defined interface and therefore
> > compiler-inserted padding between or after members would cause its layout
> > to diverge from that interface.  This is not a problem in a structure that
> > follows the general alignment rules that are seen in ABIs for all the
> > architectures that OVS cares about: basically, that a struct member needs
> > to be aligned on a boundary that is a multiple of the member's size.
> >
> > The second reason is because instances of the struct tend to be at
> > misaligned addresses.
> >
> > struct eth_header and struct vlan_eth_header are normally aligned on
> > 16-bit boundaries (at least), and they contain only 16-bit members, so
> > there's no need to pack them.  This commit removes the packed annotation.
> >
> > This commit also removes the packed annotation from struct llc_header.
> > Since that struct only contains 8-bit members, I don't know of any benefit
> > to packing it, period.
> >
> > This commit also removes a few more packed annotations that are much less
> > important.
> >
> > When these packed annotations were removed, it caused a few warnings
> > related to casts from 'uint8_t *' to more strictly aligned pointer types,
> > related to struct ovs_action_push_tnl.  That's because that struct had a
> > trailing member used to store packet headers, that was declared as
> > a uint8_t[].  Before, when this was cast to 'struct eth_header *', there
> > was no change in alignment since eth_header was packed; now that
> > eth_header is not packed, the compiler considers it suspicious.  This
> > commit avoids that problem by changing the member from uint8_t[] to
> > uint32_t[], which assures the compiler that it is properly aligned.
> >
> > CC: Joe Stringer <joe@ovn.org>
> > Signed-off-by: Ben Pfaff <blp@ovn.org>
> > ---
> 
> Thanks for the patch, this fixes the primary issue I observed and
> looking at the "pahole" output on vswitchd compiled by clang, it looks
> mostly correct on my x86-64 dev box. Assuming you're not concerned by
> the below feedback:
> Acked-by: Joe Stringer <joe@ovn.org>

Thanks.

> >  datapath/linux/compat/include/linux/openvswitch.h | 2 +-
> >  lib/packets.h                                     | 9 +++------
> >  lib/stp.c                                         | 8 +++-----
> >  ofproto/bundles.h                                 | 4 ++--
> >  4 files changed, 9 insertions(+), 14 deletions(-)
> >
> > diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
> > index d22102e224a7..55ec6c13fbd2 100644
> > --- a/datapath/linux/compat/include/linux/openvswitch.h
> > +++ b/datapath/linux/compat/include/linux/openvswitch.h
> > @@ -715,7 +715,7 @@ struct ovs_action_push_tnl {
> >         uint32_t out_port;
> >         uint32_t header_len;
> >         uint32_t tnl_type;     /* For logging. */
> > -       uint8_t  header[TNL_PUSH_HEADER_SIZE];
> > +       uint32_t header[TNL_PUSH_HEADER_SIZE / 4];
> >  };
> >  #endif
> >
> 
> Would you mind submitting this hunk upstream to net-next?

It's inside #ifndef __KERNEL__.

> > -enum OVS_PACKED_ENUM bundle_state {
> > +enum bundle_state {
> >      BS_OPEN,
> >      BS_CLOSED
> >  };
> 
> This hunk actually appears to influence the layout of "struct
> ofp_bundle" which increases the size by 8 bytes on my system. That
> said, it still appears to be 2 cachelines long in both cases and I
> don't know whether we are specifically trying to tailor the size of
> this structure (eg, for performance reasons).

I assumed that this was just cargo-culting from some other use of
OVS_PACKED_ENUM.  I don't see how OpenFlow bundles are performance or
size sensitive.
Ben Pfaff May 30, 2017, 3:26 p.m. UTC | #3
On Fri, May 26, 2017 at 03:14:45PM -0700, Ben Pfaff wrote:
> On Fri, May 26, 2017 at 02:04:23PM -0700, Joe Stringer wrote:
> > On 25 May 2017 at 13:52, Ben Pfaff <blp@ovn.org> wrote:
> > > I know of two reasons to mark a structure as "packed".  The first is
> > > because the structure must match some defined interface and therefore
> > > compiler-inserted padding between or after members would cause its layout
> > > to diverge from that interface.  This is not a problem in a structure that
> > > follows the general alignment rules that are seen in ABIs for all the
> > > architectures that OVS cares about: basically, that a struct member needs
> > > to be aligned on a boundary that is a multiple of the member's size.
> > >
> > > The second reason is because instances of the struct tend to be at
> > > misaligned addresses.
> > >
> > > struct eth_header and struct vlan_eth_header are normally aligned on
> > > 16-bit boundaries (at least), and they contain only 16-bit members, so
> > > there's no need to pack them.  This commit removes the packed annotation.
> > >
> > > This commit also removes the packed annotation from struct llc_header.
> > > Since that struct only contains 8-bit members, I don't know of any benefit
> > > to packing it, period.
> > >
> > > This commit also removes a few more packed annotations that are much less
> > > important.
> > >
> > > When these packed annotations were removed, it caused a few warnings
> > > related to casts from 'uint8_t *' to more strictly aligned pointer types,
> > > related to struct ovs_action_push_tnl.  That's because that struct had a
> > > trailing member used to store packet headers, that was declared as
> > > a uint8_t[].  Before, when this was cast to 'struct eth_header *', there
> > > was no change in alignment since eth_header was packed; now that
> > > eth_header is not packed, the compiler considers it suspicious.  This
> > > commit avoids that problem by changing the member from uint8_t[] to
> > > uint32_t[], which assures the compiler that it is properly aligned.
> > >
> > > CC: Joe Stringer <joe@ovn.org>
> > > Signed-off-by: Ben Pfaff <blp@ovn.org>
> > > ---
> > 
> > Thanks for the patch, this fixes the primary issue I observed and
> > looking at the "pahole" output on vswitchd compiled by clang, it looks
> > mostly correct on my x86-64 dev box. Assuming you're not concerned by
> > the below feedback:
> > Acked-by: Joe Stringer <joe@ovn.org>
> 
> Thanks.
> 
> > >  datapath/linux/compat/include/linux/openvswitch.h | 2 +-
> > >  lib/packets.h                                     | 9 +++------
> > >  lib/stp.c                                         | 8 +++-----
> > >  ofproto/bundles.h                                 | 4 ++--
> > >  4 files changed, 9 insertions(+), 14 deletions(-)
> > >
> > > diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
> > > index d22102e224a7..55ec6c13fbd2 100644
> > > --- a/datapath/linux/compat/include/linux/openvswitch.h
> > > +++ b/datapath/linux/compat/include/linux/openvswitch.h
> > > @@ -715,7 +715,7 @@ struct ovs_action_push_tnl {
> > >         uint32_t out_port;
> > >         uint32_t header_len;
> > >         uint32_t tnl_type;     /* For logging. */
> > > -       uint8_t  header[TNL_PUSH_HEADER_SIZE];
> > > +       uint32_t header[TNL_PUSH_HEADER_SIZE / 4];
> > >  };
> > >  #endif
> > >
> > 
> > Would you mind submitting this hunk upstream to net-next?
> 
> It's inside #ifndef __KERNEL__.
> 
> > > -enum OVS_PACKED_ENUM bundle_state {
> > > +enum bundle_state {
> > >      BS_OPEN,
> > >      BS_CLOSED
> > >  };
> > 
> > This hunk actually appears to influence the layout of "struct
> > ofp_bundle" which increases the size by 8 bytes on my system. That
> > said, it still appears to be 2 cachelines long in both cases and I
> > don't know whether we are specifically trying to tailor the size of
> > this structure (eg, for performance reasons).
> 
> I assumed that this was just cargo-culting from some other use of
> OVS_PACKED_ENUM.  I don't see how OpenFlow bundles are performance or
> size sensitive.

I decided to apply this.  I'm happy to revisit it if you have any
concerns.  Thanks again!
Joe Stringer May 30, 2017, 4:10 p.m. UTC | #4
On 26/05/2017 15:14, "Ben Pfaff" <blp@ovn.org> wrote:

On Fri, May 26, 2017 at 02:04:23PM -0700, Joe Stringer wrote:
> On 25 May 2017 at 13:52, Ben Pfaff <blp@ovn.org> wrote:
> > I know of two reasons to mark a structure as "packed".  The first is
> > because the structure must match some defined interface and therefore
> > compiler-inserted padding between or after members would cause its
layout
> > to diverge from that interface.  This is not a problem in a structure
that
> > follows the general alignment rules that are seen in ABIs for all the
> > architectures that OVS cares about: basically, that a struct member
needs
> > to be aligned on a boundary that is a multiple of the member's size.
> >
> > The second reason is because instances of the struct tend to be at
> > misaligned addresses.
> >
> > struct eth_header and struct vlan_eth_header are normally aligned on
> > 16-bit boundaries (at least), and they contain only 16-bit members, so
> > there's no need to pack them.  This commit removes the packed
annotation.
> >
> > This commit also removes the packed annotation from struct llc_header.
> > Since that struct only contains 8-bit members, I don't know of any
benefit
> > to packing it, period.
> >
> > This commit also removes a few more packed annotations that are much
less
> > important.
> >
> > When these packed annotations were removed, it caused a few warnings
> > related to casts from 'uint8_t *' to more strictly aligned pointer
types,
> > related to struct ovs_action_push_tnl.  That's because that struct had a
> > trailing member used to store packet headers, that was declared as
> > a uint8_t[].  Before, when this was cast to 'struct eth_header *', there
> > was no change in alignment since eth_header was packed; now that
> > eth_header is not packed, the compiler considers it suspicious.  This
> > commit avoids that problem by changing the member from uint8_t[] to
> > uint32_t[], which assures the compiler that it is properly aligned.
> >
> > CC: Joe Stringer <joe@ovn.org>
> > Signed-off-by: Ben Pfaff <blp@ovn.org>
> > ---
>
> Thanks for the patch, this fixes the primary issue I observed and
> looking at the "pahole" output on vswitchd compiled by clang, it looks
> mostly correct on my x86-64 dev box. Assuming you're not concerned by
> the below feedback:
> Acked-by: Joe Stringer <joe@ovn.org>

Thanks.

> >  datapath/linux/compat/include/linux/openvswitch.h | 2 +-
> >  lib/packets.h                                     | 9 +++------
> >  lib/stp.c                                         | 8 +++-----
> >  ofproto/bundles.h                                 | 4 ++--
> >  4 files changed, 9 insertions(+), 14 deletions(-)
> >
> > diff --git a/datapath/linux/compat/include/linux/openvswitch.h
b/datapath/linux/compat/include/linux/openvswitch.h
> > index d22102e224a7..55ec6c13fbd2 100644
> > --- a/datapath/linux/compat/include/linux/openvswitch.h
> > +++ b/datapath/linux/compat/include/linux/openvswitch.h
> > @@ -715,7 +715,7 @@ struct ovs_action_push_tnl {
> >         uint32_t out_port;
> >         uint32_t header_len;
> >         uint32_t tnl_type;     /* For logging. */
> > -       uint8_t  header[TNL_PUSH_HEADER_SIZE];
> > +       uint32_t header[TNL_PUSH_HEADER_SIZE / 4];
> >  };
> >  #endif
> >
>
> Would you mind submitting this hunk upstream to net-next?

It's inside #ifndef __KERNEL__.


Ah, requested that by reflex due to the file. Never mind.


> > -enum OVS_PACKED_ENUM bundle_state {
> > +enum bundle_state {
> >      BS_OPEN,
> >      BS_CLOSED
> >  };
>
> This hunk actually appears to influence the layout of "struct
> ofp_bundle" which increases the size by 8 bytes on my system. That
> said, it still appears to be 2 cachelines long in both cases and I
> don't know whether we are specifically trying to tailor the size of
> this structure (eg, for performance reasons).

I assumed that this was just cargo-culting from some other use of
OVS_PACKED_ENUM.  I don't see how OpenFlow bundles are performance or
size sensitive.


Agreed.
diff mbox

Patch

diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
index d22102e224a7..55ec6c13fbd2 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -715,7 +715,7 @@  struct ovs_action_push_tnl {
 	uint32_t out_port;
 	uint32_t header_len;
 	uint32_t tnl_type;     /* For logging. */
-	uint8_t  header[TNL_PUSH_HEADER_SIZE];
+	uint32_t header[TNL_PUSH_HEADER_SIZE / 4];
 };
 #endif
 
diff --git a/lib/packets.h b/lib/packets.h
index 7dbf6dd0b415..65ab8e8b5699 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -395,12 +395,11 @@  static inline bool eth_type_vlan(ovs_be16 eth_type)
 #define ETH_TOTAL_MIN (ETH_HEADER_LEN + ETH_PAYLOAD_MIN)
 #define ETH_TOTAL_MAX (ETH_HEADER_LEN + ETH_PAYLOAD_MAX)
 #define ETH_VLAN_TOTAL_MAX (ETH_HEADER_LEN + VLAN_HEADER_LEN + ETH_PAYLOAD_MAX)
-OVS_PACKED(
 struct eth_header {
     struct eth_addr eth_dst;
     struct eth_addr eth_src;
     ovs_be16 eth_type;
-});
+};
 BUILD_ASSERT_DECL(ETH_HEADER_LEN == sizeof(struct eth_header));
 
 void push_eth(struct dp_packet *packet, const struct eth_addr *dst,
@@ -412,12 +411,11 @@  void pop_eth(struct dp_packet *packet);
 #define LLC_CNTL_SNAP 3
 
 #define LLC_HEADER_LEN 3
-OVS_PACKED(
 struct llc_header {
     uint8_t llc_dsap;
     uint8_t llc_ssap;
     uint8_t llc_cntl;
-});
+};
 BUILD_ASSERT_DECL(LLC_HEADER_LEN == sizeof(struct llc_header));
 
 /* LLC field values used for STP frames. */
@@ -484,14 +482,13 @@  struct vlan_header {
 BUILD_ASSERT_DECL(VLAN_HEADER_LEN == sizeof(struct vlan_header));
 
 #define VLAN_ETH_HEADER_LEN (ETH_HEADER_LEN + VLAN_HEADER_LEN)
-OVS_PACKED(
 struct vlan_eth_header {
     struct eth_addr veth_dst;
     struct eth_addr veth_src;
     ovs_be16 veth_type;         /* Always htons(ETH_TYPE_VLAN). */
     ovs_be16 veth_tci;          /* Lowest 12 bits are VLAN ID. */
     ovs_be16 veth_next_type;
-});
+};
 BUILD_ASSERT_DECL(VLAN_ETH_HEADER_LEN == sizeof(struct vlan_eth_header));
 
 /* MPLS related definitions */
diff --git a/lib/stp.c b/lib/stp.c
index 952d3ce434c3..d83d42521498 100644
--- a/lib/stp.c
+++ b/lib/stp.c
@@ -1,5 +1,5 @@ 
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016, 2017 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -45,12 +45,11 @@  static struct vlog_rate_limit stp_rl = VLOG_RATE_LIMIT_INIT(60, 60);
 #define STP_TYPE_CONFIG 0x00
 #define STP_TYPE_TCN 0x80
 
-OVS_PACKED(
 struct stp_bpdu_header {
     ovs_be16 protocol_id;       /* STP_PROTOCOL_ID. */
     uint8_t protocol_version;   /* STP_PROTOCOL_VERSION. */
     uint8_t bpdu_type;          /* One of STP_TYPE_*. */
-});
+};
 BUILD_ASSERT_DECL(sizeof(struct stp_bpdu_header) == 4);
 
 enum stp_config_bpdu_flags {
@@ -73,10 +72,9 @@  struct stp_config_bpdu {
 });
 BUILD_ASSERT_DECL(sizeof(struct stp_config_bpdu) == 35);
 
-OVS_PACKED(
 struct stp_tcn_bpdu {
     struct stp_bpdu_header header; /* Type STP_TYPE_TCN. */
-});
+};
 BUILD_ASSERT_DECL(sizeof(struct stp_tcn_bpdu) == 4);
 
 struct stp_timer {
diff --git a/ofproto/bundles.h b/ofproto/bundles.h
index dd64700aa348..b63681708d3b 100644
--- a/ofproto/bundles.h
+++ b/ofproto/bundles.h
@@ -1,7 +1,7 @@ 
 /*
  * Copyright (c) 2013, 2014 Alexandru Copot <alex.mihai.c@gmail.com>, with support from IXIA.
  * Copyright (c) 2013, 2014 Daniel Baluta <dbaluta@ixiacom.com>
- * Copyright (c) 2014, 2015, 2016 Nicira, Inc.
+ * Copyright (c) 2014, 2015, 2016, 2017 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -49,7 +49,7 @@  struct ofp_bundle_entry {
     };
 };
 
-enum OVS_PACKED_ENUM bundle_state {
+enum bundle_state {
     BS_OPEN,
     BS_CLOSED
 };