2010-10-21 11:31:43 -07:00
|
|
|
|
/*
|
2014-08-04 11:11:40 -07:00
|
|
|
|
* Copyright (c) 2010, 2011, 2013, 2014 Nicira, Inc.
|
2010-10-21 11:31:43 -07:00
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at:
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef OPENVSWITCH_TYPES_H
|
|
|
|
|
#define OPENVSWITCH_TYPES_H 1
|
|
|
|
|
|
2011-02-05 13:14:47 -08:00
|
|
|
|
#include <sys/types.h>
|
2010-10-21 11:31:43 -07:00
|
|
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
|
|
#ifdef __CHECKER__
|
|
|
|
|
#define OVS_BITWISE __attribute__((bitwise))
|
2010-11-10 14:39:54 -08:00
|
|
|
|
#define OVS_FORCE __attribute__((force))
|
2010-10-21 11:31:43 -07:00
|
|
|
|
#else
|
|
|
|
|
#define OVS_BITWISE
|
2010-11-10 14:39:54 -08:00
|
|
|
|
#define OVS_FORCE
|
2010-10-21 11:31:43 -07:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* The ovs_be<N> types indicate that an object is in big-endian, not
|
2014-08-04 11:11:40 -07:00
|
|
|
|
* native-endian, byte order. They are otherwise equivalent to uint<N>_t. */
|
|
|
|
|
typedef uint16_t OVS_BITWISE ovs_be16;
|
|
|
|
|
typedef uint32_t OVS_BITWISE ovs_be32;
|
|
|
|
|
typedef uint64_t OVS_BITWISE ovs_be64;
|
2013-06-27 15:27:15 -07:00
|
|
|
|
|
|
|
|
|
#define OVS_BE16_MAX ((OVS_FORCE ovs_be16) 0xffff)
|
|
|
|
|
#define OVS_BE32_MAX ((OVS_FORCE ovs_be32) 0xffffffff)
|
|
|
|
|
#define OVS_BE64_MAX ((OVS_FORCE ovs_be64) 0xffffffffffffffffULL)
|
2011-02-05 13:14:47 -08:00
|
|
|
|
|
packets: Do not assume that IPv4, TCP, or ARP headers are 32-bit aligned.
Ethernet headers are 14 bytes long, so when the beginning of such a header
is 32-bit aligned, the following data is misaligned. The usual trick to
fix that is to start the Ethernet header on an odd-numbered 16-bit
boundary. That trick works OK for Open vSwitch, but there are two
problems:
- OVS doesn't use that trick everywhere. Maybe it should, but it's
difficult to make sure that it does consistently because the CPUs
most commonly used with OVS don't care about misalignment, so we
only find problems when porting.
- Some protocols (GRE, VXLAN) don't use that trick, so in such a case
one can properly align the inner or outer L3/L4/L7 but not both. (OVS
userspace doesn't directly deal with such protocols yet, so this is
just future-proofing.)
- OpenFlow uses the alignment trick in a few places but not all of them.
This commit starts the adoption of what I hope will be a more robust way
to avoid misalignment problems and the resulting bus errors on RISC
architectures. Instead of trying to ensure that 32-bit quantities are
always aligned, we always read them as if they were misaligned. To ensure
that they are read this way, we change their types from 32-bit types to
pairs of 16-bit types. (I don't know of any protocols that offset the
next header by an odd number of bytes, so a 16-bit alignment assumption
seems OK.)
The same would be necessary for 64-bit types in protocol headers, but we
don't yet have any protocol definitions with 64-bit types.
IPv6 protocol headers need the same treatment, but for those we rely on
structs provided by system headers, so I'll leave them for an upcoming
patch.
Signed-off-by: Ben Pfaff <blp@nicira.com>
2013-08-15 10:47:39 -07:00
|
|
|
|
/* These types help with a few funny situations:
|
|
|
|
|
*
|
|
|
|
|
* - The Ethernet header is 14 bytes long, which misaligns everything after
|
|
|
|
|
* that. One can put 2 "shim" bytes before the Ethernet header, but this
|
|
|
|
|
* helps only if there is exactly one Ethernet header. If there are two,
|
|
|
|
|
* as with GRE and VXLAN (and if the inner header doesn't use this
|
|
|
|
|
* trick--GRE and VXLAN don't) then you have the choice of aligning the
|
|
|
|
|
* inner data or the outer data. So it seems better to treat 32-bit fields
|
|
|
|
|
* in protocol headers as aligned only on 16-bit boundaries.
|
|
|
|
|
*
|
|
|
|
|
* - ARP headers contain misaligned 32-bit fields.
|
|
|
|
|
*
|
|
|
|
|
* - Netlink and OpenFlow contain 64-bit values that are only guaranteed to
|
|
|
|
|
* be aligned on 32-bit boundaries.
|
2011-02-05 13:14:47 -08:00
|
|
|
|
*
|
|
|
|
|
* lib/unaligned.h has helper functions for accessing these. */
|
|
|
|
|
|
packets: Do not assume that IPv4, TCP, or ARP headers are 32-bit aligned.
Ethernet headers are 14 bytes long, so when the beginning of such a header
is 32-bit aligned, the following data is misaligned. The usual trick to
fix that is to start the Ethernet header on an odd-numbered 16-bit
boundary. That trick works OK for Open vSwitch, but there are two
problems:
- OVS doesn't use that trick everywhere. Maybe it should, but it's
difficult to make sure that it does consistently because the CPUs
most commonly used with OVS don't care about misalignment, so we
only find problems when porting.
- Some protocols (GRE, VXLAN) don't use that trick, so in such a case
one can properly align the inner or outer L3/L4/L7 but not both. (OVS
userspace doesn't directly deal with such protocols yet, so this is
just future-proofing.)
- OpenFlow uses the alignment trick in a few places but not all of them.
This commit starts the adoption of what I hope will be a more robust way
to avoid misalignment problems and the resulting bus errors on RISC
architectures. Instead of trying to ensure that 32-bit quantities are
always aligned, we always read them as if they were misaligned. To ensure
that they are read this way, we change their types from 32-bit types to
pairs of 16-bit types. (I don't know of any protocols that offset the
next header by an odd number of bytes, so a 16-bit alignment assumption
seems OK.)
The same would be necessary for 64-bit types in protocol headers, but we
don't yet have any protocol definitions with 64-bit types.
IPv6 protocol headers need the same treatment, but for those we rely on
structs provided by system headers, so I'll leave them for an upcoming
patch.
Signed-off-by: Ben Pfaff <blp@nicira.com>
2013-08-15 10:47:39 -07:00
|
|
|
|
/* A 32-bit value, in host byte order, that is only aligned on a 16-bit
|
|
|
|
|
* boundary. */
|
|
|
|
|
typedef struct {
|
|
|
|
|
#ifdef WORDS_BIGENDIAN
|
|
|
|
|
uint16_t hi, lo;
|
|
|
|
|
#else
|
|
|
|
|
uint16_t lo, hi;
|
|
|
|
|
#endif
|
|
|
|
|
} ovs_16aligned_u32;
|
|
|
|
|
|
|
|
|
|
/* A 32-bit value, in network byte order, that is only aligned on a 16-bit
|
|
|
|
|
* boundary. */
|
|
|
|
|
typedef struct {
|
|
|
|
|
ovs_be16 hi, lo;
|
|
|
|
|
} ovs_16aligned_be32;
|
|
|
|
|
|
2011-02-05 13:14:47 -08:00
|
|
|
|
/* A 64-bit value, in host byte order, that is only aligned on a 32-bit
|
|
|
|
|
* boundary. */
|
|
|
|
|
typedef struct {
|
|
|
|
|
#ifdef WORDS_BIGENDIAN
|
2012-03-23 11:43:54 -07:00
|
|
|
|
uint32_t hi, lo;
|
2011-02-05 13:14:47 -08:00
|
|
|
|
#else
|
2012-03-23 11:43:54 -07:00
|
|
|
|
uint32_t lo, hi;
|
2011-02-05 13:14:47 -08:00
|
|
|
|
#endif
|
|
|
|
|
} ovs_32aligned_u64;
|
|
|
|
|
|
2014-08-12 11:12:12 +12:00
|
|
|
|
typedef union {
|
|
|
|
|
uint32_t u32[4];
|
|
|
|
|
struct {
|
2015-09-22 23:24:11 -07:00
|
|
|
|
#ifdef WORDS_BIGENDIAN
|
|
|
|
|
uint64_t hi, lo;
|
|
|
|
|
#else
|
2014-08-12 11:12:12 +12:00
|
|
|
|
uint64_t lo, hi;
|
2015-09-22 23:24:11 -07:00
|
|
|
|
#endif
|
2014-08-12 11:12:12 +12:00
|
|
|
|
} u64;
|
|
|
|
|
} ovs_u128;
|
|
|
|
|
|
2015-09-22 23:24:11 -07:00
|
|
|
|
typedef union {
|
|
|
|
|
ovs_be32 be32[4];
|
|
|
|
|
struct {
|
|
|
|
|
ovs_be64 hi, lo;
|
|
|
|
|
} be64;
|
|
|
|
|
} ovs_be128;
|
|
|
|
|
|
2015-12-21 15:56:40 -08:00
|
|
|
|
/* MSVC2015 doesn't support designated initializers when compiling C++,
|
|
|
|
|
* and doesn't support ternary operators with non-designated initializers.
|
|
|
|
|
* So we use these static definitions rather than using initializer macros. */
|
|
|
|
|
static const ovs_u128 OVS_U128_MAX = { { UINT32_MAX, UINT32_MAX,
|
|
|
|
|
UINT32_MAX, UINT32_MAX } };
|
|
|
|
|
static const ovs_be128 OVS_BE128_MAX = { { OVS_BE32_MAX, OVS_BE32_MAX,
|
|
|
|
|
OVS_BE32_MAX, OVS_BE32_MAX } };
|
2015-09-22 23:24:11 -07:00
|
|
|
|
|
2011-02-05 13:14:47 -08:00
|
|
|
|
/* A 64-bit value, in network byte order, that is only aligned on a 32-bit
|
|
|
|
|
* boundary. */
|
|
|
|
|
typedef struct {
|
2012-03-23 11:43:54 -07:00
|
|
|
|
ovs_be32 hi, lo;
|
2011-02-05 13:14:47 -08:00
|
|
|
|
} ovs_32aligned_be64;
|
2010-10-21 11:31:43 -07:00
|
|
|
|
|
2013-06-19 16:58:44 -07:00
|
|
|
|
/* ofp_port_t represents the port number of a OpenFlow switch.
|
|
|
|
|
* odp_port_t represents the port number on the datapath.
|
|
|
|
|
* ofp11_port_t represents the OpenFlow-1.1 port number. */
|
|
|
|
|
typedef uint16_t OVS_BITWISE ofp_port_t;
|
|
|
|
|
typedef uint32_t OVS_BITWISE odp_port_t;
|
|
|
|
|
typedef uint32_t OVS_BITWISE ofp11_port_t;
|
|
|
|
|
|
|
|
|
|
/* Macro functions that cast int types to ofp/odp/ofp11 types. */
|
|
|
|
|
#define OFP_PORT_C(X) ((OVS_FORCE ofp_port_t) (X))
|
|
|
|
|
#define ODP_PORT_C(X) ((OVS_FORCE odp_port_t) (X))
|
|
|
|
|
#define OFP11_PORT_C(X) ((OVS_FORCE ofp11_port_t) (X))
|
|
|
|
|
|
2015-12-01 15:02:45 +09:00
|
|
|
|
/* Using this struct instead of a bare array makes an ethernet address field
|
2015-08-28 14:55:11 -07:00
|
|
|
|
* assignable. The size of the array is also part of the type, so it is easier
|
|
|
|
|
* to deal with. */
|
|
|
|
|
struct eth_addr {
|
|
|
|
|
union {
|
|
|
|
|
uint8_t ea[6];
|
|
|
|
|
ovs_be16 be16[3];
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2010-10-21 11:31:43 -07:00
|
|
|
|
#endif /* openvswitch/types.h */
|