Open vSwitch userspace uses special types to indicate that a particular object may not be naturally aligned. Netlink is one source of such problems: in Netlink, 64-bit integers are often aligned only on 32-bit boundaries. Now that the header file for Open vSwitch datapath Netlink definitions has diverged somewhat from the upstream Linux kernel version, it makes sense to use ovs_32aligned_u64 locally to make it harder to accidentally access a misaligned 64-bit member.
Signed-off-by: Ben Pfaff <b...@nicira.com> --- datapath/linux/compat/include/linux/openvswitch.h | 2 +- include/odp-netlink-internal.h | 54 +++++++++++---------- lib/dpif-linux.c | 43 ++++++++-------- lib/netdev-linux.c | 32 ++++++------ 4 files changed, 69 insertions(+), 62 deletions(-) diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h index d912884..9c2d9db 100644 --- a/datapath/linux/compat/include/linux/openvswitch.h +++ b/datapath/linux/compat/include/linux/openvswitch.h @@ -23,7 +23,7 @@ typedef __be16 ovs_be16; typedef __be32 ovs_be32; -typedef __be64 ovs_be64; +typedef __u64 ovs_32aligned_u64; #define ODP_NETLINK_INTERNAL_OK #include "odp-netlink-internal.h" diff --git a/include/odp-netlink-internal.h b/include/odp-netlink-internal.h index 754ecaf..b87282c 100644 --- a/include/odp-netlink-internal.h +++ b/include/odp-netlink-internal.h @@ -55,13 +55,17 @@ * This header is not self-contained. It must be "#include"d with the * following types already defined: * - * - uint8_t, uint16_t, uint32_t, uint64_t: Unsigned integer types in - * native byte order. + * - uint8_t, uint16_t, uint32_t: Unsigned integer types in native byte + * order. * - * - ovs_be16, ovs_be32, ovs_be64: Unsigned integer types in big-endian - * byte order. (These will ordinarily typedefs to the corresponding - * native types. Separate type names enable static checkers such as - * "sparse" to report misuses.) + * - ovs_be16, ovs_be32: Unsigned integer types in big-endian byte order. + * (These will ordinarily typedefs to the corresponding native types. + * Separate type names enable static checkers such as "sparse" to report + * misuses.) + * + * - ovs_32aligned_u64: An unsigned 64-bit integer type. Data in Netlink, + * even 64-bit data, may only be aligned on a 32-bit boundary, so this + * type name emphasizes that. */ #ifndef ODP_NETLINK_INTERNAL_OK @@ -137,29 +141,29 @@ enum ovs_datapath_attr { /* All 64-bit integers within Netlink messages are 4-byte aligned only. */ struct ovs_dp_stats { - uint64_t n_hit; /* Number of flow table matches. */ - uint64_t n_missed; /* Number of flow table misses. */ - uint64_t n_lost; /* Number of misses not sent to userspace. */ - uint64_t n_flows; /* Number of flows present */ + ovs_32aligned_u64 n_hit; /* Number of flow table matches. */ + ovs_32aligned_u64 n_missed; /* Number of flow table misses. */ + ovs_32aligned_u64 n_lost; /* Number of misses not sent to userspace. */ + ovs_32aligned_u64 n_flows; /* Number of flows present */ }; struct ovs_dp_megaflow_stats { - uint64_t n_mask_hit; /* Number of masks used for flow lookups. */ - uint32_t n_masks; /* Number of masks for the datapath. */ - uint32_t pad0; /* Pad for future expension. */ - uint64_t pad1; /* Pad for future expension. */ - uint64_t pad2; /* Pad for future expension. */ + ovs_32aligned_u64 n_mask_hit; /* # of masks used for flow lookups. */ + uint32_t n_masks; /* Number of masks for the datapath. */ + uint32_t pad0; /* Pad for future expension. */ + ovs_32aligned_u64 pad1; /* Pad for future expension. */ + ovs_32aligned_u64 pad2; /* Pad for future expension. */ }; struct ovs_vport_stats { - uint64_t rx_packets; /* total packets received */ - uint64_t tx_packets; /* total packets transmitted */ - uint64_t rx_bytes; /* total bytes received */ - uint64_t tx_bytes; /* total bytes transmitted */ - uint64_t rx_errors; /* bad packets received */ - uint64_t tx_errors; /* packet transmit problems */ - uint64_t rx_dropped; /* no space in linux buffers */ - uint64_t tx_dropped; /* no space available in linux */ + ovs_32aligned_u64 rx_packets; /* total packets received */ + ovs_32aligned_u64 tx_packets; /* total packets transmitted */ + ovs_32aligned_u64 rx_bytes; /* total bytes received */ + ovs_32aligned_u64 tx_bytes; /* total bytes transmitted */ + ovs_32aligned_u64 rx_errors; /* bad packets received */ + ovs_32aligned_u64 tx_errors; /* packet transmit problems */ + ovs_32aligned_u64 rx_dropped; /* no space in linux buffers */ + ovs_32aligned_u64 tx_dropped; /* no space available in linux */ }; /* Allow last Netlink attribute to be unaligned */ @@ -317,8 +321,8 @@ enum ovs_flow_cmd { }; struct ovs_flow_stats { - uint64_t n_packets; /* Number of matched packets. */ - uint64_t n_bytes; /* Number of matched bytes. */ + ovs_32aligned_u64 n_packets; /* Number of matched packets. */ + ovs_32aligned_u64 n_bytes; /* Number of matched bytes. */ }; enum ovs_key_attr { diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c index afe9340..f179474 100644 --- a/lib/dpif-linux.c +++ b/lib/dpif-linux.c @@ -73,8 +73,8 @@ struct dpif_linux_dp { const char *name; /* OVS_DP_ATTR_NAME. */ const uint32_t *upcall_pid; /* OVS_DP_ATTR_UPCALL_PID. */ uint32_t user_features; /* OVS_DP_ATTR_USER_FEATURES */ - struct ovs_dp_stats stats; /* OVS_DP_ATTR_STATS. */ - struct ovs_dp_megaflow_stats megaflow_stats; + const struct ovs_dp_stats *stats; /* OVS_DP_ATTR_STATS. */ + const struct ovs_dp_megaflow_stats *megaflow_stats; /* OVS_DP_ATTR_MEGAFLOW_STATS.*/ }; @@ -554,12 +554,23 @@ dpif_linux_get_stats(const struct dpif *dpif_, struct dpif_dp_stats *stats) error = dpif_linux_dp_get(dpif_, &dp, &buf); if (!error) { - stats->n_hit = dp.stats.n_hit; - stats->n_missed = dp.stats.n_missed; - stats->n_lost = dp.stats.n_lost; - stats->n_flows = dp.stats.n_flows; - stats->n_masks = dp.megaflow_stats.n_masks; - stats->n_mask_hit = dp.megaflow_stats.n_mask_hit; + memset(stats, 0, sizeof *stats); + + if (dp.stats) { + stats->n_hit = get_32aligned_u64(&dp.stats->n_hit); + stats->n_missed = get_32aligned_u64(&dp.stats->n_missed); + stats->n_lost = get_32aligned_u64(&dp.stats->n_lost); + stats->n_flows = get_32aligned_u64(&dp.stats->n_flows); + } + + if (dp.megaflow_stats) { + stats->n_masks = dp.megaflow_stats->n_masks; + stats->n_mask_hit = get_32aligned_u64( + &dp.megaflow_stats->n_mask_hit); + } else { + stats->n_masks = UINT32_MAX; + stats->n_mask_hit = UINT64_MAX; + } ofpbuf_delete(buf); } return error; @@ -2186,17 +2197,11 @@ dpif_linux_dp_from_ofpbuf(struct dpif_linux_dp *dp, const struct ofpbuf *buf) dp->dp_ifindex = ovs_header->dp_ifindex; dp->name = nl_attr_get_string(a[OVS_DP_ATTR_NAME]); if (a[OVS_DP_ATTR_STATS]) { - /* Can't use structure assignment because Netlink doesn't ensure - * sufficient alignment for 64-bit members. */ - memcpy(&dp->stats, nl_attr_get(a[OVS_DP_ATTR_STATS]), - sizeof dp->stats); + dp->stats = nl_attr_get(a[OVS_DP_ATTR_STATS]); } if (a[OVS_DP_ATTR_MEGAFLOW_STATS]) { - /* Can't use structure assignment because Netlink doesn't ensure - * sufficient alignment for 64-bit members. */ - memcpy(&dp->megaflow_stats, nl_attr_get(a[OVS_DP_ATTR_MEGAFLOW_STATS]), - sizeof dp->megaflow_stats); + dp->megaflow_stats = nl_attr_get(a[OVS_DP_ATTR_MEGAFLOW_STATS]); } return 0; @@ -2235,8 +2240,6 @@ static void dpif_linux_dp_init(struct dpif_linux_dp *dp) { memset(dp, 0, sizeof *dp); - dp->megaflow_stats.n_masks = UINT32_MAX; - dp->megaflow_stats.n_mask_hit = UINT64_MAX; } static void @@ -2456,8 +2459,8 @@ dpif_linux_flow_get_stats(const struct dpif_linux_flow *flow, struct dpif_flow_stats *stats) { if (flow->stats) { - stats->n_packets = get_unaligned_u64(&flow->stats->n_packets); - stats->n_bytes = get_unaligned_u64(&flow->stats->n_bytes); + stats->n_packets = get_32aligned_u64(&flow->stats->n_packets); + stats->n_bytes = get_32aligned_u64(&flow->stats->n_bytes); } else { stats->n_packets = 0; stats->n_bytes = 0; diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 840022d..5587911 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -1480,14 +1480,14 @@ static void netdev_stats_from_ovs_vport_stats(struct netdev_stats *dst, const struct ovs_vport_stats *src) { - dst->rx_packets = get_unaligned_u64(&src->rx_packets); - dst->tx_packets = get_unaligned_u64(&src->tx_packets); - dst->rx_bytes = get_unaligned_u64(&src->rx_bytes); - dst->tx_bytes = get_unaligned_u64(&src->tx_bytes); - dst->rx_errors = get_unaligned_u64(&src->rx_errors); - dst->tx_errors = get_unaligned_u64(&src->tx_errors); - dst->rx_dropped = get_unaligned_u64(&src->rx_dropped); - dst->tx_dropped = get_unaligned_u64(&src->tx_dropped); + dst->rx_packets = get_32aligned_u64(&src->rx_packets); + dst->tx_packets = get_32aligned_u64(&src->tx_packets); + dst->rx_bytes = get_32aligned_u64(&src->rx_bytes); + dst->tx_bytes = get_32aligned_u64(&src->tx_bytes); + dst->rx_errors = get_32aligned_u64(&src->rx_errors); + dst->tx_errors = get_32aligned_u64(&src->tx_errors); + dst->rx_dropped = get_32aligned_u64(&src->rx_dropped); + dst->tx_dropped = get_32aligned_u64(&src->tx_dropped); dst->multicast = 0; dst->collisions = 0; dst->rx_length_errors = 0; @@ -1682,14 +1682,14 @@ netdev_internal_set_stats(struct netdev *netdev, struct dpif_linux_vport vport; int err; - vport_stats.rx_packets = stats->rx_packets; - vport_stats.tx_packets = stats->tx_packets; - vport_stats.rx_bytes = stats->rx_bytes; - vport_stats.tx_bytes = stats->tx_bytes; - vport_stats.rx_errors = stats->rx_errors; - vport_stats.tx_errors = stats->tx_errors; - vport_stats.rx_dropped = stats->rx_dropped; - vport_stats.tx_dropped = stats->tx_dropped; + put_32aligned_u64(&vport_stats.rx_packets, stats->rx_packets); + put_32aligned_u64(&vport_stats.tx_packets, stats->tx_packets); + put_32aligned_u64(&vport_stats.rx_bytes, stats->rx_bytes); + put_32aligned_u64(&vport_stats.tx_bytes, stats->tx_bytes); + put_32aligned_u64(&vport_stats.rx_errors, stats->rx_errors); + put_32aligned_u64(&vport_stats.tx_errors, stats->tx_errors); + put_32aligned_u64(&vport_stats.rx_dropped, stats->rx_dropped); + put_32aligned_u64(&vport_stats.tx_dropped, stats->tx_dropped); dpif_linux_vport_init(&vport); vport.cmd = OVS_VPORT_CMD_SET; -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev