typedef __be32 ovs_be32;
typedef __be64 ovs_be64;
\f
-/* Netlink and OpenFlow both contain 64-bit values that are only guaranteed to
- * be aligned on 32-bit boundaries. These types help.
+/* 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.
*
* lib/unaligned.h has helper functions for accessing these. */
+/* 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;
+
/* A 64-bit value, in host byte order, that is only aligned on a 32-bit
* boundary. */
typedef struct {
#include "random.h"
#include "smap.h"
#include "timeval.h"
+#include "unaligned.h"
#include "unixctl.h"
#include "util.h"
#include "vlog.h"
ip->ip_ttl = MAXTTL;
ip->ip_tos = IPTOS_LOWDELAY | IPTOS_THROUGHPUT;
ip->ip_proto = IPPROTO_UDP;
- ip->ip_src = htonl(0xA9FE0100); /* 169.254.1.0 Link Local. */
- ip->ip_dst = htonl(0xA9FE0101); /* 169.254.1.1 Link Local. */
+ /* Use link local addresses: */
+ put_16aligned_be32(&ip->ip_src, htonl(0xA9FE0100)); /* 169.254.1.0. */
+ put_16aligned_be32(&ip->ip_dst, htonl(0xA9FE0101)); /* 169.254.1.1. */
ip->ip_csum = csum(ip, sizeof *ip);
udp = ofpbuf_put_zeros(p, sizeof *udp);
if (nh) {
packet->l4 = b.data;
- flow->nw_src = get_unaligned_be32(&nh->ip_src);
- flow->nw_dst = get_unaligned_be32(&nh->ip_dst);
+ flow->nw_src = get_16aligned_be32(&nh->ip_src);
+ flow->nw_dst = get_16aligned_be32(&nh->ip_dst);
flow->nw_proto = nh->ip_proto;
flow->nw_tos = nh->ip_tos;
flow->nw_proto = ntohs(arp->ar_op);
}
- flow->nw_src = arp->ar_spa;
- flow->nw_dst = arp->ar_tpa;
+ flow->nw_src = get_16aligned_be32(&arp->ar_spa);
+ flow->nw_dst = get_16aligned_be32(&arp->ar_tpa);
memcpy(flow->arp_sha, arp->ar_sha, ETH_ADDR_LEN);
memcpy(flow->arp_tha, arp->ar_tha, ETH_ADDR_LEN);
}
ip->ip_tos = flow->nw_tos;
ip->ip_ttl = flow->nw_ttl;
ip->ip_proto = flow->nw_proto;
- ip->ip_src = flow->nw_src;
- ip->ip_dst = flow->nw_dst;
+ put_16aligned_be32(&ip->ip_src, flow->nw_src);
+ put_16aligned_be32(&ip->ip_dst, flow->nw_dst);
if (flow->nw_frag & FLOW_NW_FRAG_ANY) {
ip->ip_frag_off |= htons(IP_MORE_FRAGMENTS);
if (flow->nw_proto == ARP_OP_REQUEST ||
flow->nw_proto == ARP_OP_REPLY) {
- arp->ar_spa = flow->nw_src;
- arp->ar_tpa = flow->nw_dst;
+ put_16aligned_be32(&arp->ar_spa, flow->nw_src);
+ put_16aligned_be32(&arp->ar_tpa, flow->nw_dst);
memcpy(arp->ar_sha, flow->arp_sha, ETH_ADDR_LEN);
memcpy(arp->ar_tha, flow->arp_tha, ETH_ADDR_LEN);
}
#include "dynamic-string.h"
#include "ofpbuf.h"
#include "ovs-thread.h"
+#include "unaligned.h"
const struct in6_addr in6addr_exact = IN6ADDR_EXACT_INIT;
arp->ar_pln = sizeof arp->ar_spa;
arp->ar_op = htons(ARP_OP_RARP);
memcpy(arp->ar_sha, eth_src, ETH_ADDR_LEN);
- arp->ar_spa = htonl(0);
+ put_16aligned_be32(&arp->ar_spa, htonl(0));
memcpy(arp->ar_tha, eth_src, ETH_ADDR_LEN);
- arp->ar_tpa = htonl(0);
+ put_16aligned_be32(&arp->ar_tpa, htonl(0));
}
/* Insert VLAN header according to given TCI. Packet passed must be Ethernet
}
static void
-packet_set_ipv4_addr(struct ofpbuf *packet, ovs_be32 *addr, ovs_be32 new_addr)
+packet_set_ipv4_addr(struct ofpbuf *packet,
+ ovs_16aligned_be32 *addr, ovs_be32 new_addr)
{
struct ip_header *nh = packet->l3;
+ ovs_be32 old_addr = get_16aligned_be32(addr);
if (nh->ip_proto == IPPROTO_TCP && packet->l7) {
struct tcp_header *th = packet->l4;
- th->tcp_csum = recalc_csum32(th->tcp_csum, *addr, new_addr);
+ th->tcp_csum = recalc_csum32(th->tcp_csum, old_addr, new_addr);
} else if (nh->ip_proto == IPPROTO_UDP && packet->l7) {
struct udp_header *uh = packet->l4;
if (uh->udp_csum) {
- uh->udp_csum = recalc_csum32(uh->udp_csum, *addr, new_addr);
+ uh->udp_csum = recalc_csum32(uh->udp_csum, old_addr, new_addr);
if (!uh->udp_csum) {
uh->udp_csum = htons(0xffff);
}
}
}
- nh->ip_csum = recalc_csum32(nh->ip_csum, *addr, new_addr);
- *addr = new_addr;
+ nh->ip_csum = recalc_csum32(nh->ip_csum, old_addr, new_addr);
+ put_16aligned_be32(addr, new_addr);
}
/* Returns true, if packet contains at least one routing header where
{
struct ip_header *nh = packet->l3;
- if (nh->ip_src != src) {
+ if (get_16aligned_be32(&nh->ip_src) != src) {
packet_set_ipv4_addr(packet, &nh->ip_src, src);
}
- if (nh->ip_dst != dst) {
+ if (get_16aligned_be32(&nh->ip_dst) != dst) {
packet_set_ipv4_addr(packet, &nh->ip_dst, dst);
}
uint8_t ip_ttl;
uint8_t ip_proto;
ovs_be16 ip_csum;
- ovs_be32 ip_src;
- ovs_be32 ip_dst;
+ ovs_16aligned_be32 ip_src;
+ ovs_16aligned_be32 ip_dst;
};
BUILD_ASSERT_DECL(IP_HEADER_LEN == sizeof(struct ip_header));
ovs_be16 empty;
ovs_be16 mtu;
} frag;
- ovs_be32 gateway;
+ ovs_16aligned_be32 gateway;
} icmp_fields;
uint8_t icmp_data[0];
};
struct tcp_header {
ovs_be16 tcp_src;
ovs_be16 tcp_dst;
- ovs_be32 tcp_seq;
- ovs_be32 tcp_ack;
+ ovs_16aligned_be32 tcp_seq;
+ ovs_16aligned_be32 tcp_ack;
ovs_be16 tcp_ctl;
ovs_be16 tcp_winsz;
ovs_be16 tcp_csum;
#define ARP_OP_RARP 3
#define ARP_ETH_HEADER_LEN 28
-OVS_PACKED(
struct arp_eth_header {
/* Generic members. */
ovs_be16 ar_hrd; /* Hardware type. */
/* Ethernet+IPv4 specific members. */
uint8_t ar_sha[ETH_ADDR_LEN]; /* Sender hardware address. */
- ovs_be32 ar_spa; /* Sender protocol address. */
+ ovs_16aligned_be32 ar_spa; /* Sender protocol address. */
uint8_t ar_tha[ETH_ADDR_LEN]; /* Target hardware address. */
- ovs_be32 ar_tpa; /* Target protocol address. */
-});
+ ovs_16aligned_be32 ar_tpa; /* Target protocol address. */
+};
BUILD_ASSERT_DECL(ARP_ETH_HEADER_LEN == sizeof(struct arp_eth_header));
/* The IPv6 flow label is in the lower 20 bits of the first 32-bit word. */
put_unaligned_u64__(p, x);
}
\f
+/* Returns the value in 'x'. */
+static inline uint32_t
+get_16aligned_u32(const ovs_16aligned_u32 *x)
+{
+ return ((uint32_t) x->hi << 16) | x->lo;
+}
+
+/* Stores 'value' in 'x'. */
+static inline void
+put_16aligned_u32(ovs_16aligned_u32 *x, uint32_t value)
+{
+ x->hi = value >> 16;
+ x->lo = value;
+}
+
/* Returns the value in 'x'. */
static inline uint64_t
get_32aligned_u64(const ovs_32aligned_u64 *x)
}
#ifndef __CHECKER__
+/* Returns the value of 'x'. */
+static inline ovs_be32
+get_16aligned_be32(const ovs_16aligned_be32 *x)
+{
+#ifdef WORDS_BIGENDIAN
+ return ((ovs_be32) x->hi << 16) | x->lo;
+#else
+ return ((ovs_be32) x->lo << 16) | x->hi;
+#endif
+}
+
+/* Stores network byte order 'value' into 'x'. */
+static inline void
+put_16aligned_be32(ovs_16aligned_be32 *x, ovs_be32 value)
+{
+#if WORDS_BIGENDIAN
+ x->hi = value >> 16;
+ x->lo = value;
+#else
+ x->hi = value;
+ x->lo = value >> 16;
+#endif
+}
+
/* Returns the value of 'x'. */
static inline ovs_be64
get_32aligned_be64(const ovs_32aligned_be64 *x)
#else /* __CHECKER__ */
/* Making sparse happy with these functions also makes them unreadable, so
* don't bother to show it their implementations. */
+ovs_be32 get_16aligned_be32(const ovs_16aligned_be32 *);
+void put_16aligned_be32(ovs_16aligned_be32 *, ovs_be32);
ovs_be64 get_32aligned_be64(const ovs_32aligned_be64 *);
void put_32aligned_be64(ovs_32aligned_be64 *, ovs_be64);
#endif