X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fnetlink.c;h=7529534ba401f7eaa183c23d8402793ac6c2db99;hb=dfbf7f354416264a0b84b09bf882ac0932e78c8b;hp=f1234ad4840dad8db21f3899a65415314f9bd50c;hpb=7c6244783982509fddd62b3296bc627943bb7a1a;p=openvswitch diff --git a/lib/netlink.c b/lib/netlink.c index f1234ad4..7529534b 100644 --- a/lib/netlink.c +++ b/lib/netlink.c @@ -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); @@ -200,6 +201,29 @@ nl_msg_put_uninit(struct ofpbuf *msg, size_t size) return p; } +/* Prepends the 'size' bytes of data in 'p', plus Netlink padding if needed, to + * the head end of 'msg'. Data in 'msg' is reallocated and copied if + * necessary. */ +void +nl_msg_push(struct ofpbuf *msg, const void *data, size_t size) +{ + memcpy(nl_msg_push_uninit(msg, size), data, size); +} + +/* Prepends 'size' bytes of data, plus Netlink padding if needed, to the head + * end of 'msg', reallocating and copying its data if necessary. Returns a + * pointer to the first byte of the new data, which is left uninitialized. */ +void * +nl_msg_push_uninit(struct ofpbuf *msg, size_t size) +{ + size_t pad = NLMSG_ALIGN(size) - size; + char *p = ofpbuf_push_uninit(msg, size + pad); + if (pad) { + memset(p + size, 0, pad); + } + return p; +} + /* 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 @@ -299,6 +323,105 @@ nl_msg_put_string(struct ofpbuf *msg, uint16_t type, const char *value) nl_msg_put_unspec(msg, type, value, strlen(value) + 1); } +/* Prepends a Netlink attribute of the given 'type' and room for 'size' bytes + * of data as its payload, plus Netlink padding if needed, to the head end of + * 'msg', reallocating and copying its data if necessary. Returns a pointer to + * the first byte of data in the attribute, which is left uninitialized. */ +void * +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); + assert(NLA_ALIGN(total_size) <= UINT16_MAX); + nla->nla_len = total_size; + nla->nla_type = type; + return nla + 1; +} + +/* Prepends a Netlink attribute of the given 'type' and the 'size' bytes of + * 'data' as its payload, to the head end of 'msg', reallocating and copying + * its data if necessary. Returns a pointer to the first byte of data in the + * attribute, which is left uninitialized. */ +void +nl_msg_push_unspec(struct ofpbuf *msg, uint16_t type, + const void *data, size_t size) +{ + memcpy(nl_msg_push_unspec_uninit(msg, type, size), data, size); +} + +/* Prepends a Netlink attribute of the given 'type' and no payload to 'msg'. + * (Some Netlink protocols use the presence or absence of an attribute as a + * Boolean flag.) */ +void +nl_msg_push_flag(struct ofpbuf *msg, uint16_t type) +{ + nl_msg_push_unspec(msg, type, NULL, 0); +} + +/* Prepends a Netlink attribute of the given 'type' and the given 8-bit 'value' + * to 'msg'. */ +void +nl_msg_push_u8(struct ofpbuf *msg, uint16_t type, uint8_t value) +{ + nl_msg_push_unspec(msg, type, &value, sizeof value); +} + +/* Prepends a Netlink attribute of the given 'type' and the given 16-bit host + * byte order 'value' to 'msg'. */ +void +nl_msg_push_u16(struct ofpbuf *msg, uint16_t type, uint16_t value) +{ + nl_msg_push_unspec(msg, type, &value, sizeof value); +} + +/* Prepends a Netlink attribute of the given 'type' and the given 32-bit host + * byte order 'value' to 'msg'. */ +void +nl_msg_push_u32(struct ofpbuf *msg, uint16_t type, uint32_t value) +{ + nl_msg_push_unspec(msg, type, &value, sizeof value); +} + +/* Prepends a Netlink attribute of the given 'type' and the given 64-bit host + * byte order 'value' to 'msg'. */ +void +nl_msg_push_u64(struct ofpbuf *msg, uint16_t type, uint64_t value) +{ + nl_msg_push_unspec(msg, type, &value, sizeof value); +} + +/* Prepends a Netlink attribute of the given 'type' and the given 16-bit + * network byte order 'value' to 'msg'. */ +void +nl_msg_push_be16(struct ofpbuf *msg, uint16_t type, ovs_be16 value) +{ + nl_msg_push_unspec(msg, type, &value, sizeof value); +} + +/* Prepends a Netlink attribute of the given 'type' and the given 32-bit + * network byte order 'value' to 'msg'. */ +void +nl_msg_push_be32(struct ofpbuf *msg, uint16_t type, ovs_be32 value) +{ + nl_msg_push_unspec(msg, type, &value, sizeof value); +} + +/* Prepends a Netlink attribute of the given 'type' and the given 64-bit + * network byte order 'value' to 'msg'. */ +void +nl_msg_push_be64(struct ofpbuf *msg, uint16_t type, ovs_be64 value) +{ + nl_msg_push_unspec(msg, type, &value, sizeof value); +} + +/* Prepends a Netlink attribute of the given 'type' and the given + * null-terminated string 'value' to 'msg'. */ +void +nl_msg_push_string(struct ofpbuf *msg, uint16_t type, const char *value) +{ + nl_msg_push_unspec(msg, type, value, strlen(value) + 1); +} + /* Adds the header for nested Netlink attributes to 'msg', with the specified * 'type', and returns the header's offset within 'msg'. The caller should add * the content for the nested Netlink attribute to 'msg' (e.g. using the other @@ -435,7 +558,8 @@ nl_attr_get_u32(const struct nlattr *nla) 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. @@ -462,7 +586,8 @@ nl_attr_get_be32(const struct nlattr *nla) ovs_be64 nl_attr_get_be64(const struct nlattr *nla) { - return NL_ATTR_GET_AS(nla, ovs_be64); + 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. @@ -582,6 +707,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. */ @@ -608,3 +736,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); } + +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); +}