ofp-util: Work on decoding OF1.1 flow_mods.
[openvswitch] / lib / unaligned.h
index ef08f4e22a9db3a1794668a07091c0f4c51560bb..2654a2763fd5494575b0243e0431d461d5f5bac7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Nicira Networks.
+ * Copyright (c) 2010, 2011 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include <stdint.h>
 #include "byte-order.h"
 #include "openvswitch/types.h"
+#include "type-props.h"
+#include "util.h"
 
 /* Public API. */
 static inline uint16_t get_unaligned_u16(const uint16_t *);
 static inline uint32_t get_unaligned_u32(const uint32_t *);
-static inline uint64_t get_unaligned_u64(const uint64_t *);
 static inline void put_unaligned_u16(uint16_t *, uint16_t);
 static inline void put_unaligned_u32(uint32_t *, uint32_t);
 static inline void put_unaligned_u64(uint64_t *, uint64_t);
@@ -62,7 +63,7 @@ put_unaligned_##ABBREV(TYPE *p, TYPE x)         \
 
 GCC_UNALIGNED_ACCESSORS(uint16_t, u16);
 GCC_UNALIGNED_ACCESSORS(uint32_t, u32);
-GCC_UNALIGNED_ACCESSORS(uint64_t, u64);
+GCC_UNALIGNED_ACCESSORS(uint64_t, u64__); /* Special case: see below. */
 
 GCC_UNALIGNED_ACCESSORS(ovs_be16, be16);
 GCC_UNALIGNED_ACCESSORS(ovs_be32, be32);
@@ -102,7 +103,7 @@ static inline void put_unaligned_u32(uint32_t *p_, uint32_t x_)
     p[3] = x;
 }
 
-static inline uint64_t get_unaligned_u64(const uint64_t *p_)
+static inline uint64_t get_unaligned_u64__(const uint64_t *p_)
 {
     const uint8_t *p = (const uint8_t *) p_;
     return ntohll(((uint64_t) p[0] << 56)
@@ -115,7 +116,7 @@ static inline uint64_t get_unaligned_u64(const uint64_t *p_)
                   | p[7]);
 }
 
-static inline void put_unaligned_u64(uint64_t *p_, uint64_t x_)
+static inline void put_unaligned_u64__(uint64_t *p_, uint64_t x_)
 {
     uint8_t *p = (uint8_t *) p_;
     uint64_t x = ntohll(x_);
@@ -141,4 +142,82 @@ static inline void put_unaligned_u64(uint64_t *p_, uint64_t x_)
 #define put_unaligned_be64 put_unaligned_u64
 #endif
 
+/* uint64_t get_unaligned_u64(uint64_t *p);
+ *
+ * Returns the value of the possibly misaligned uint64_t at 'p'.  'p' may
+ * actually be any type that points to a 64-bit integer.  That is, on Unix-like
+ * 32-bit ABIs, it may point to an "unsigned long long int", and on Unix-like
+ * 64-bit ABIs, it may point to an "unsigned long int" or an "unsigned long
+ * long int".
+ *
+ * This is special-cased because on some Linux targets, the kernel __u64 is
+ * unsigned long long int and the userspace uint64_t is unsigned long int, so
+ * that any single function prototype would fail to accept one or the other.
+ *
+ * Below, "sizeof (*(P) % 1)" verifies that *P has an integer type, since
+ * operands to % must be integers.
+ */
+#define get_unaligned_u64(P)                                \
+    (BUILD_ASSERT(sizeof *(P) == 8),                        \
+     BUILD_ASSERT_GCCONLY(!TYPE_IS_SIGNED(typeof(*(P)))),   \
+     (void) sizeof (*(P) % 1),                              \
+     get_unaligned_u64__((const uint64_t *) (P)))
+
+/* Stores 'x' at possibly misaligned address 'p'.
+ *
+ * put_unaligned_u64() could be overloaded in the same way as
+ * get_unaligned_u64(), but so far it has not proven necessary.
+ */
+static inline void
+put_unaligned_u64(uint64_t *p, uint64_t x)
+{
+    put_unaligned_u64__(p, x);
+}
+\f
+/* Returns the value in 'x'. */
+static inline uint64_t
+get_32aligned_u64(const ovs_32aligned_u64 *x)
+{
+    return ((uint64_t) x->hi << 32) | x->lo;
+}
+
+/* Stores 'value' in 'x'. */
+static inline void
+put_32aligned_u64(ovs_32aligned_u64 *x, uint64_t value)
+{
+    x->hi = value >> 32;
+    x->lo = value;
+}
+
+#ifndef __CHECKER__
+/* Returns the value of 'x'. */
+static inline ovs_be64
+get_32aligned_be64(const ovs_32aligned_be64 *x)
+{
+#ifdef WORDS_BIGENDIAN
+    return ((ovs_be64) x->hi << 32) | x->lo;
+#else
+    return ((ovs_be64) x->lo << 32) | x->hi;
+#endif
+}
+
+/* Stores network byte order 'value' into 'x'. */
+static inline void
+put_32aligned_be64(ovs_32aligned_be64 *x, ovs_be64 value)
+{
+#if WORDS_BIGENDIAN
+    x->hi = value >> 32;
+    x->lo = value;
+#else
+    x->hi = value;
+    x->lo = value >> 32;
+#endif
+}
+#else  /* __CHECKER__ */
+/* Making sparse happy with these functions also makes them unreadable, so
+ * don't bother to show it their implementations. */
+ovs_be64 get_32aligned_be64(const ovs_32aligned_be64 *);
+void put_32aligned_be64(ovs_32aligned_be64 *, ovs_be64);
+#endif
+
 #endif /* unaligned.h */