Prepare Open vSwitch 1.1.2 release.
[sliver-openvswitch.git] / lib / netlink.c
index 39d703a..ec35849 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
 #include "netlink-protocol.h"
 #include "ofpbuf.h"
 #include "timeval.h"
+#include "unaligned.h"
 #include "vlog.h"
 
 VLOG_DEFINE_THIS_MODULE(netlink);
@@ -243,30 +244,54 @@ nl_msg_put_u8(struct ofpbuf *msg, uint16_t type, uint8_t value)
     nl_msg_put_unspec(msg, type, &value, sizeof value);
 }
 
-/* Appends a Netlink attribute of the given 'type' and the given 16-bit 'value'
- * to 'msg'. */
+/* Appends a Netlink attribute of the given 'type' and the given 16-bit host
+ * byte order 'value' to 'msg'. */
 void
 nl_msg_put_u16(struct ofpbuf *msg, uint16_t type, uint16_t value)
 {
     nl_msg_put_unspec(msg, type, &value, sizeof value);
 }
 
-/* Appends a Netlink attribute of the given 'type' and the given 32-bit 'value'
- * to 'msg'. */
+/* Appends a Netlink attribute of the given 'type' and the given 32-bit host
+ * byte order 'value' to 'msg'. */
 void
 nl_msg_put_u32(struct ofpbuf *msg, uint16_t type, uint32_t value)
 {
     nl_msg_put_unspec(msg, type, &value, sizeof value);
 }
 
-/* Appends a Netlink attribute of the given 'type' and the given 64-bit 'value'
- * to 'msg'. */
+/* Appends a Netlink attribute of the given 'type' and the given 64-bit host
+ * byte order 'value' to 'msg'. */
 void
 nl_msg_put_u64(struct ofpbuf *msg, uint16_t type, uint64_t value)
 {
     nl_msg_put_unspec(msg, type, &value, sizeof value);
 }
 
+/* Appends a Netlink attribute of the given 'type' and the given 16-bit network
+ * byte order 'value' to 'msg'. */
+void
+nl_msg_put_be16(struct ofpbuf *msg, uint16_t type, ovs_be16 value)
+{
+    nl_msg_put_unspec(msg, type, &value, sizeof value);
+}
+
+/* Appends a Netlink attribute of the given 'type' and the given 32-bit network
+ * byte order 'value' to 'msg'. */
+void
+nl_msg_put_be32(struct ofpbuf *msg, uint16_t type, ovs_be32 value)
+{
+    nl_msg_put_unspec(msg, type, &value, sizeof value);
+}
+
+/* Appends a Netlink attribute of the given 'type' and the given 64-bit network
+ * byte order 'value' to 'msg'. */
+void
+nl_msg_put_be64(struct ofpbuf *msg, uint16_t type, ovs_be64 value)
+{
+    nl_msg_put_unspec(msg, type, &value, sizeof value);
+}
+
 /* Appends a Netlink attribute of the given 'type' and the given
  * null-terminated string 'value' to 'msg'. */
 void
@@ -334,6 +359,14 @@ nl_msg_next(struct ofpbuf *buffer, struct ofpbuf *msg)
 \f
 /* Attributes. */
 
+/* Returns the bits of 'nla->nla_type' that are significant for determining its
+ * type. */
+int
+nl_attr_type(const struct nlattr *nla)
+{
+    return nla->nla_type & NLA_TYPE_MASK;
+}
+
 /* Returns the first byte in the payload of attribute 'nla'. */
 const void *
 nl_attr_get(const struct nlattr *nla)
@@ -379,7 +412,7 @@ nl_attr_get_u8(const struct nlattr *nla)
     return NL_ATTR_GET_AS(nla, uint8_t);
 }
 
-/* Returns the 16-bit value in 'nla''s payload.
+/* Returns the 16-bit host byte order value in 'nla''s payload.
  *
  * Asserts that 'nla''s payload is at least 2 bytes long. */
 uint16_t
@@ -388,7 +421,7 @@ nl_attr_get_u16(const struct nlattr *nla)
     return NL_ATTR_GET_AS(nla, uint16_t);
 }
 
-/* Returns the 32-bit value in 'nla''s payload.
+/* Returns the 32-bit host byte order value in 'nla''s payload.
  *
  * Asserts that 'nla''s payload is at least 4 bytes long. */
 uint32_t
@@ -397,13 +430,42 @@ nl_attr_get_u32(const struct nlattr *nla)
     return NL_ATTR_GET_AS(nla, uint32_t);
 }
 
-/* Returns the 64-bit value in 'nla''s payload.
+/* Returns the 64-bit host byte order value in 'nla''s payload.
  *
  * Asserts that 'nla''s payload is at least 8 bytes long. */
 uint64_t
 nl_attr_get_u64(const struct nlattr *nla)
 {
-    return NL_ATTR_GET_AS(nla, uint64_t);
+    const ovs_32aligned_u64 *x = nl_attr_get_unspec(nla, sizeof *x);
+    return get_32aligned_u64(x);
+}
+
+/* Returns the 16-bit network byte order value in 'nla''s payload.
+ *
+ * Asserts that 'nla''s payload is at least 2 bytes long. */
+ovs_be16
+nl_attr_get_be16(const struct nlattr *nla)
+{
+    return NL_ATTR_GET_AS(nla, ovs_be16);
+}
+
+/* Returns the 32-bit network byte order value in 'nla''s payload.
+ *
+ * Asserts that 'nla''s payload is at least 4 bytes long. */
+ovs_be32
+nl_attr_get_be32(const struct nlattr *nla)
+{
+    return NL_ATTR_GET_AS(nla, ovs_be32);
+}
+
+/* Returns the 64-bit network byte order value in 'nla''s payload.
+ *
+ * Asserts that 'nla''s payload is at least 8 bytes long. */
+ovs_be64
+nl_attr_get_be64(const struct nlattr *nla)
+{
+    const ovs_32aligned_be64 *x = nl_attr_get_unspec(nla, sizeof *x);
+    return get_32aligned_be64(x);
 }
 
 /* Returns the null-terminated string value in 'nla''s payload.
@@ -488,12 +550,12 @@ nl_policy_parse(const struct ofpbuf *msg, size_t nla_offset,
         if (aligned_len > (char*)tail - (char*)p) {
             VLOG_DBG_RL(&rl, "%zu: attr %"PRIu16" aligned data len (%zu) "
                         "> bytes left (%tu)",
-                        offset, nla->nla_type, aligned_len,
+                        offset, nl_attr_type(nla), aligned_len,
                         (char*)tail - (char*)p);
             return false;
         }
 
-        type = nla->nla_type;
+        type = nl_attr_type(nla);
         if (type < n_attrs && policy[type].type != NL_A_NO_ATTR) {
             const struct nl_policy *e = &policy[type];
             size_t min_len, max_len;
@@ -523,6 +585,9 @@ nl_policy_parse(const struct ofpbuf *msg, size_t nla_offset,
                 assert(n_required > 0);
                 --n_required;
             }
+            if (attrs[type]) {
+                VLOG_DBG_RL(&rl, "%zu: duplicate attr %"PRIu16, offset, type);
+            }
             attrs[type] = nla;
         } else {
             /* Skip attribute type that we don't care about. */
@@ -549,3 +614,39 @@ nl_parse_nested(const struct nlattr *nla, const struct nl_policy policy[],
     nl_attr_get_nested(nla, &buf);
     return nl_policy_parse(&buf, 0, policy, attrs, n_attrs);
 }
+
+static const struct nlattr *
+nl_attr_find__(const struct nlattr *attrs, size_t size, uint16_t type)
+{
+    const struct nlattr *nla;
+    size_t left;
+
+    NL_ATTR_FOR_EACH (nla, left, attrs, size) {
+        if (nl_attr_type (nla) == type) {
+            return nla;
+        }
+    }
+    return NULL;
+}
+
+/* Returns the first Netlink attribute within 'buf' with the specified 'type',
+ * skipping a header of 'hdr_len' bytes at the beginning of 'buf'.
+ *
+ * This function does not validate the attribute's length. */
+const struct nlattr *
+nl_attr_find(const struct ofpbuf *buf, size_t hdr_len, uint16_t type)
+{
+    const uint8_t *start = (const uint8_t *) buf->data + hdr_len;
+    return nl_attr_find__((const struct nlattr *) start, buf->size - hdr_len,
+                          type);
+}
+
+/* Returns the first Netlink attribute within 'nla' with the specified
+ * 'type'.
+ *
+ * This function does not validate the attribute's length. */
+const struct nlattr *
+nl_attr_find_nested(const struct nlattr *nla, uint16_t type)
+{
+    return nl_attr_find__(nl_attr_get(nla), nl_attr_get_size(nla), type);
+}