X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fnetlink.c;h=ada429e9ff39f9a389296364ba95f2309adf2219;hb=5de43a606c949dbb74272d5b09627ddd5f64b06b;hp=c8e5905abc59c5b0746441ac597e77a81989648f;hpb=d1673b006d53fdea72c0744e835362ed1917f879;p=sliver-openvswitch.git diff --git a/lib/netlink.c b/lib/netlink.c index c8e5905ab..ada429e9f 100644 --- a/lib/netlink.c +++ b/lib/netlink.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc. + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ #include #include #include "coverage.h" +#include "flow.h" #include "netlink-protocol.h" #include "ofpbuf.h" #include "timeval.h" @@ -65,7 +66,7 @@ nl_msg_nlmsgerr(const struct ofpbuf *msg, int *errorp) struct nlmsgerr *err = ofpbuf_at(msg, NLMSG_HDRLEN, sizeof *err); int code = EPROTO; if (!err) { - VLOG_ERR_RL(&rl, "received invalid nlmsgerr (%zd bytes < %zd)", + VLOG_ERR_RL(&rl, "received invalid nlmsgerr (%"PRIuSIZE"d bytes < %"PRIuSIZE"d)", msg->size, NLMSG_HDRLEN + sizeof *err); } else if (err->error <= 0 && err->error > INT_MIN) { code = -err->error; @@ -219,6 +220,18 @@ nl_msg_put_unspec_uninit(struct ofpbuf *msg, uint16_t type, size_t size) return nla + 1; } +/* Appends a Netlink attribute of the given 'type' and room for 'size' bytes of + * data as its payload, plus Netlink padding if needed, to the tail end of + * 'msg', reallocating and copying its data if necessary. Returns a pointer to + * the first byte of data in the attribute, which is zeroed. */ +void * +nl_msg_put_unspec_zero(struct ofpbuf *msg, uint16_t type, size_t size) +{ + void *data = nl_msg_put_unspec_uninit(msg, type, size); + memset(data, 0, size); + return data; +} + /* Appends a Netlink attribute of the given 'type' and the 'size' bytes of * 'data' as its payload, to the tail end of 'msg', reallocating and copying * its data if necessary. Returns a pointer to the first byte of data in the @@ -295,6 +308,15 @@ 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 odp_port_t + * 'value' to 'msg'. */ +void +nl_msg_put_odp_port(struct ofpbuf *msg, uint16_t type, odp_port_t value) +{ + nl_msg_put_u32(msg, type, odp_to_u32(value)); +} + + /* Appends a Netlink attribute of the given 'type' and the given * null-terminated string 'value' to 'msg'. */ void @@ -312,7 +334,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; @@ -458,6 +480,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; +} /* Attributes. */ @@ -570,6 +602,15 @@ nl_attr_get_be64(const struct nlattr *nla) return get_32aligned_be64(x); } +/* Returns the 32-bit odp_port_t value in 'nla''s payload. + * + * Asserts that 'nla''s payload is at least 4 bytes long. */ +odp_port_t +nl_attr_get_odp_port(const struct nlattr *nla) +{ + return u32_to_odp(nl_attr_get_u32(nla)); +} + /* Returns the null-terminated string value in 'nla''s payload. * * Asserts that 'nla''s payload contains a null-terminated string. */ @@ -588,17 +629,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: OVS_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: OVS_NOT_REACHED(); + } +} bool nl_attr_validate(const struct nlattr *nla, const struct nl_policy *policy) @@ -615,18 +680,18 @@ 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. */ len = nl_attr_get_size(nla); if (len < min_len || len > max_len) { - VLOG_DBG_RL(&rl, "attr %"PRIu16" length %zu not in " - "allowed range %zu...%zu", type, len, min_len, max_len); + VLOG_DBG_RL(&rl, "attr %"PRIu16" length %"PRIuSIZE" not in " + "allowed range %"PRIuSIZE"...%"PRIuSIZE, type, len, min_len, max_len); return false; } @@ -668,8 +733,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); @@ -692,7 +756,7 @@ nl_policy_parse(const struct ofpbuf *msg, size_t nla_offset, for (i = 0; i < n_attrs; i++) { const struct nl_policy *e = &policy[i]; if (!e->optional && e->type != NL_A_NO_ATTR && !attrs[i]) { - VLOG_DBG_RL(&rl, "required attr %zu missing", i); + VLOG_DBG_RL(&rl, "required attr %"PRIuSIZE" missing", i); return false; } } @@ -734,8 +798,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); }