Merge branch 'mainstream'
[sliver-openvswitch.git] / lib / netlink.c
index 7e7884e..40477ea 100644 (file)
@@ -322,7 +322,7 @@ nl_msg_push_unspec_uninit(struct ofpbuf *msg, uint16_t type, size_t size)
 {
     size_t total_size = NLA_HDRLEN + size;
     struct nlattr* nla = nl_msg_push_uninit(msg, total_size);
-    ovs_assert(NLA_ALIGN(total_size) <= UINT16_MAX);
+    ovs_assert(!nl_attr_oversized(size));
     nla->nla_len = total_size;
     nla->nla_type = type;
     return nla + 1;
@@ -468,6 +468,16 @@ nl_msg_next(struct ofpbuf *buffer, struct ofpbuf *msg)
     msg->size = 0;
     return NULL;
 }
+
+/* Returns true if a Netlink attribute with a payload that is 'payload_size'
+ * bytes long would be oversized, that is, if it's not possible to create an
+ * nlattr of that size because its size wouldn't fit in the 16-bit nla_len
+ * field. */
+bool
+nl_attr_oversized(size_t payload_size)
+{
+    return NL_ATTR_SIZE(payload_size) > UINT16_MAX;
+}
 \f
 /* Attributes. */
 
@@ -607,17 +617,41 @@ nl_attr_get_nested(const struct nlattr *nla, struct ofpbuf *nested)
     ofpbuf_use_const(nested, nl_attr_get(nla), nl_attr_get_size(nla));
 }
 
-/* Default minimum and maximum payload sizes for each type of attribute. */
-static const size_t attr_len_range[][2] = {
-    [0 ... N_NL_ATTR_TYPES - 1] = { 0, SIZE_MAX },
-    [NL_A_U8] = { 1, 1 },
-    [NL_A_U16] = { 2, 2 },
-    [NL_A_U32] = { 4, 4 },
-    [NL_A_U64] = { 8, 8 },
-    [NL_A_STRING] = { 1, SIZE_MAX },
-    [NL_A_FLAG] = { 0, SIZE_MAX },
-    [NL_A_NESTED] = { 0, SIZE_MAX },
-};
+/* Default minimum payload size for each type of attribute. */
+static size_t
+min_attr_len(enum nl_attr_type type)
+{
+    switch (type) {
+    case NL_A_NO_ATTR: return 0;
+    case NL_A_UNSPEC: return 0;
+    case NL_A_U8: return 1;
+    case NL_A_U16: return 2;
+    case NL_A_U32: return 4;
+    case NL_A_U64: return 8;
+    case NL_A_STRING: return 1;
+    case NL_A_FLAG: return 0;
+    case NL_A_NESTED: return 0;
+    case N_NL_ATTR_TYPES: default: NOT_REACHED();
+    }
+}
+
+/* Default maximum payload size for each type of attribute. */
+static size_t
+max_attr_len(enum nl_attr_type type)
+{
+    switch (type) {
+    case NL_A_NO_ATTR: return SIZE_MAX;
+    case NL_A_UNSPEC: return SIZE_MAX;
+    case NL_A_U8: return 1;
+    case NL_A_U16: return 2;
+    case NL_A_U32: return 4;
+    case NL_A_U64: return 8;
+    case NL_A_STRING: return SIZE_MAX;
+    case NL_A_FLAG: return SIZE_MAX;
+    case NL_A_NESTED: return SIZE_MAX;
+    case N_NL_ATTR_TYPES: default: NOT_REACHED();
+    }
+}
 
 bool
 nl_attr_validate(const struct nlattr *nla, const struct nl_policy *policy)
@@ -634,11 +668,11 @@ nl_attr_validate(const struct nlattr *nla, const struct nl_policy *policy)
     /* Figure out min and max length. */
     min_len = policy->min_len;
     if (!min_len) {
-        min_len = attr_len_range[policy->type][0];
+        min_len = min_attr_len(policy->type);
     }
     max_len = policy->max_len;
     if (!max_len) {
-        max_len = attr_len_range[policy->type][1];
+        max_len = max_attr_len(policy->type);
     }
 
     /* Verify length. */
@@ -687,8 +721,7 @@ nl_policy_parse(const struct ofpbuf *msg, size_t nla_offset,
         return false;
     }
 
-    NL_ATTR_FOR_EACH (nla, left,
-                      (struct nlattr *) ((char *) msg->data + nla_offset),
+    NL_ATTR_FOR_EACH (nla, left, ofpbuf_at(msg, nla_offset, 0),
                       msg->size - nla_offset)
     {
         uint16_t type = nl_attr_type(nla);
@@ -753,8 +786,7 @@ nl_attr_find__(const struct nlattr *attrs, size_t size, uint16_t type)
 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,
+    return nl_attr_find__(ofpbuf_at(buf, hdr_len, 0), buf->size - hdr_len,
                           type);
 }