Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License");
5 : : * you may not use this file except in compliance with the License.
6 : : * You may obtain a copy of the License at:
7 : : *
8 : : * http://www.apache.org/licenses/LICENSE-2.0
9 : : *
10 : : * Unless required by applicable law or agreed to in writing, software
11 : : * distributed under the License is distributed on an "AS IS" BASIS,
12 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : : * See the License for the specific language governing permissions and
14 : : * limitations under the License.
15 : : */
16 : :
17 : : #include <config.h>
18 : : #include "netlink.h"
19 : : #include <errno.h>
20 : : #include <inttypes.h>
21 : : #include <sys/types.h>
22 : : #include <unistd.h>
23 : : #include "coverage.h"
24 : : #include "flow.h"
25 : : #include "netlink-protocol.h"
26 : : #include "openvswitch/ofpbuf.h"
27 : : #include "timeval.h"
28 : : #include "unaligned.h"
29 : : #include "openvswitch/vlog.h"
30 : : #include "util.h"
31 : :
32 : 20190 : VLOG_DEFINE_THIS_MODULE(netlink);
33 : :
34 : : /* A single (bad) Netlink message can in theory dump out many, many log
35 : : * messages, so the burst size is set quite high here to avoid missing useful
36 : : * information. Also, at high logging levels we log *all* Netlink messages. */
37 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 600);
38 : :
39 : : /* Returns the nlmsghdr at the head of 'msg'.
40 : : *
41 : : * 'msg' must be at least as large as a nlmsghdr. */
42 : : struct nlmsghdr *
43 : 155385 : nl_msg_nlmsghdr(const struct ofpbuf *msg)
44 : : {
45 : 155385 : return ofpbuf_at_assert(msg, 0, NLMSG_HDRLEN);
46 : : }
47 : :
48 : : /* Returns the genlmsghdr just past 'msg''s nlmsghdr.
49 : : *
50 : : * Returns a null pointer if 'msg' is not large enough to contain an nlmsghdr
51 : : * and a genlmsghdr. */
52 : : struct genlmsghdr *
53 : 0 : nl_msg_genlmsghdr(const struct ofpbuf *msg)
54 : : {
55 : 0 : return ofpbuf_at(msg, NLMSG_HDRLEN, GENL_HDRLEN);
56 : : }
57 : :
58 : : /* If 'buffer' is a NLMSG_ERROR message, stores 0 in '*errorp' if it is an ACK
59 : : * message, otherwise a positive errno value, and returns true. If 'buffer' is
60 : : * not an NLMSG_ERROR message, returns false.
61 : : *
62 : : * 'msg' must be at least as large as a nlmsghdr. */
63 : : bool
64 : 22724 : nl_msg_nlmsgerr(const struct ofpbuf *msg, int *errorp)
65 : : {
66 [ + + ]: 22724 : if (nl_msg_nlmsghdr(msg)->nlmsg_type == NLMSG_ERROR) {
67 : 1523 : struct nlmsgerr *err = ofpbuf_at(msg, NLMSG_HDRLEN, sizeof *err);
68 : 1523 : int code = EPROTO;
69 [ - + ]: 1523 : if (!err) {
70 [ # # ]: 0 : VLOG_ERR_RL(&rl, "received invalid nlmsgerr (%"PRIu32" bytes < %"PRIuSIZE")",
71 : : msg->size, NLMSG_HDRLEN + sizeof *err);
72 [ + - ][ + - ]: 1523 : } else if (err->error <= 0 && err->error > INT_MIN) {
73 : 1523 : code = -err->error;
74 : : }
75 [ + - ]: 1523 : if (errorp) {
76 : 1523 : *errorp = code;
77 : : }
78 : 1523 : return true;
79 : : } else {
80 : 21201 : return false;
81 : : }
82 : : }
83 : :
84 : : /* Ensures that 'b' has room for at least 'size' bytes plus netlink padding at
85 : : * its tail end, reallocating and copying its data if necessary. */
86 : : void
87 : 19829 : nl_msg_reserve(struct ofpbuf *msg, size_t size)
88 : : {
89 : 19829 : ofpbuf_prealloc_tailroom(msg, NLMSG_ALIGN(size));
90 : 19829 : }
91 : :
92 : : /* Puts a nlmsghdr at the beginning of 'msg', which must be initially empty.
93 : : * Uses the given 'type' and 'flags'. 'expected_payload' should be
94 : : * an estimate of the number of payload bytes to be supplied; if the size of
95 : : * the payload is unknown a value of 0 is acceptable.
96 : : *
97 : : * 'type' is ordinarily an enumerated value specific to the Netlink protocol
98 : : * (e.g. RTM_NEWLINK, for NETLINK_ROUTE protocol). For Generic Netlink, 'type'
99 : : * is the family number obtained via nl_lookup_genl_family().
100 : : *
101 : : * 'flags' is a bit-mask that indicates what kind of request is being made. It
102 : : * is often NLM_F_REQUEST indicating that a request is being made, commonly
103 : : * or'd with NLM_F_ACK to request an acknowledgement.
104 : : *
105 : : * Sets the new nlmsghdr's nlmsg_len, nlmsg_seq, and nlmsg_pid fields to 0 for
106 : : * now. Functions that send Netlink messages will fill these in just before
107 : : * sending the message.
108 : : *
109 : : * nl_msg_put_genlmsghdr() is more convenient for composing a Generic Netlink
110 : : * message. */
111 : : void
112 : 19829 : nl_msg_put_nlmsghdr(struct ofpbuf *msg,
113 : : size_t expected_payload, uint32_t type, uint32_t flags)
114 : : {
115 : : struct nlmsghdr *nlmsghdr;
116 : :
117 [ - + ]: 19829 : ovs_assert(msg->size == 0);
118 : :
119 : 19829 : nl_msg_reserve(msg, NLMSG_HDRLEN + expected_payload);
120 : 19829 : nlmsghdr = nl_msg_put_uninit(msg, NLMSG_HDRLEN);
121 : 19829 : nlmsghdr->nlmsg_len = 0;
122 : 19829 : nlmsghdr->nlmsg_type = type;
123 : 19829 : nlmsghdr->nlmsg_flags = flags;
124 : 19829 : nlmsghdr->nlmsg_seq = 0;
125 : 19829 : nlmsghdr->nlmsg_pid = 0;
126 : 19829 : }
127 : :
128 : : /* Puts a nlmsghdr and genlmsghdr at the beginning of 'msg', which must be
129 : : * initially empty. 'expected_payload' should be an estimate of the number of
130 : : * payload bytes to be supplied; if the size of the payload is unknown a value
131 : : * of 0 is acceptable.
132 : : *
133 : : * 'family' is the family number obtained via nl_lookup_genl_family().
134 : : *
135 : : * 'flags' is a bit-mask that indicates what kind of request is being made. It
136 : : * is often NLM_F_REQUEST indicating that a request is being made, commonly
137 : : * or'd with NLM_F_ACK to request an acknowledgement.
138 : : *
139 : : * 'cmd' is an enumerated value specific to the Generic Netlink family
140 : : * (e.g. CTRL_CMD_NEWFAMILY for the GENL_ID_CTRL family).
141 : : *
142 : : * 'version' is a version number specific to the family and command (often 1).
143 : : *
144 : : * Sets the new nlmsghdr's nlmsg_pid field to 0 for now. nl_sock_send() will
145 : : * fill it in just before sending the message.
146 : : *
147 : : * nl_msg_put_nlmsghdr() should be used to compose Netlink messages that are
148 : : * not Generic Netlink messages. */
149 : : void
150 : 15304 : nl_msg_put_genlmsghdr(struct ofpbuf *msg, size_t expected_payload,
151 : : int family, uint32_t flags, uint8_t cmd, uint8_t version)
152 : : {
153 : : struct genlmsghdr *genlmsghdr;
154 : :
155 : 15304 : nl_msg_put_nlmsghdr(msg, GENL_HDRLEN + expected_payload, family, flags);
156 [ - + ]: 15304 : ovs_assert(msg->size == NLMSG_HDRLEN);
157 : 15304 : genlmsghdr = nl_msg_put_uninit(msg, GENL_HDRLEN);
158 : 15304 : genlmsghdr->cmd = cmd;
159 : 15304 : genlmsghdr->version = version;
160 : 15304 : genlmsghdr->reserved = 0;
161 : 15304 : }
162 : :
163 : : /* Appends the 'size' bytes of data in 'p', plus Netlink padding if needed, to
164 : : * the tail end of 'msg'. Data in 'msg' is reallocated and copied if
165 : : * necessary. */
166 : : void
167 : 801 : nl_msg_put(struct ofpbuf *msg, const void *data, size_t size)
168 : : {
169 : 801 : memcpy(nl_msg_put_uninit(msg, size), data, size);
170 : 801 : }
171 : :
172 : : /* Appends 'size' bytes of data, plus Netlink padding if needed, to the tail
173 : : * end of 'msg', reallocating and copying its data if necessary. Returns a
174 : : * pointer to the first byte of the new data, which is left uninitialized. */
175 : : void *
176 : 683702 : nl_msg_put_uninit(struct ofpbuf *msg, size_t size)
177 : : {
178 : 683702 : size_t pad = PAD_SIZE(size, NLMSG_ALIGNTO);
179 : 683702 : char *p = ofpbuf_put_uninit(msg, size + pad);
180 [ + + ]: 683702 : if (pad) {
181 : 92189 : memset(p + size, 0, pad);
182 : : }
183 : 683702 : return p;
184 : : }
185 : :
186 : : /* Prepends the 'size' bytes of data in 'p', plus Netlink padding if needed, to
187 : : * the head end of 'msg'. Data in 'msg' is reallocated and copied if
188 : : * necessary. */
189 : : void
190 : 0 : nl_msg_push(struct ofpbuf *msg, const void *data, size_t size)
191 : : {
192 : 0 : memcpy(nl_msg_push_uninit(msg, size), data, size);
193 : 0 : }
194 : :
195 : : /* Prepends 'size' bytes of data, plus Netlink padding if needed, to the head
196 : : * end of 'msg', reallocating and copying its data if necessary. Returns a
197 : : * pointer to the first byte of the new data, which is left uninitialized. */
198 : : void *
199 : 0 : nl_msg_push_uninit(struct ofpbuf *msg, size_t size)
200 : : {
201 : 0 : size_t pad = PAD_SIZE(size, NLMSG_ALIGNTO);
202 : 0 : char *p = ofpbuf_push_uninit(msg, size + pad);
203 [ # # ]: 0 : if (pad) {
204 : 0 : memset(p + size, 0, pad);
205 : : }
206 : 0 : return p;
207 : : }
208 : :
209 : : /* Appends a Netlink attribute of the given 'type' and room for 'size' bytes of
210 : : * data as its payload, plus Netlink padding if needed, to the tail end of
211 : : * 'msg', reallocating and copying its data if necessary. Returns a pointer to
212 : : * the first byte of data in the attribute, which is left uninitialized. */
213 : : void *
214 : 647655 : nl_msg_put_unspec_uninit(struct ofpbuf *msg, uint16_t type, size_t size)
215 : : {
216 : 647655 : size_t total_size = NLA_HDRLEN + size;
217 : 647655 : struct nlattr* nla = nl_msg_put_uninit(msg, total_size);
218 [ - + ]: 647655 : ovs_assert(!nl_attr_oversized(size));
219 : 647655 : nla->nla_len = total_size;
220 : 647655 : nla->nla_type = type;
221 : 647655 : return nla + 1;
222 : : }
223 : :
224 : : /* Appends a Netlink attribute of the given 'type' and room for 'size' bytes of
225 : : * data as its payload, plus Netlink padding if needed, to the tail end of
226 : : * 'msg', reallocating and copying its data if necessary. Returns a pointer to
227 : : * the first byte of data in the attribute, which is zeroed. */
228 : : void *
229 : 28446 : nl_msg_put_unspec_zero(struct ofpbuf *msg, uint16_t type, size_t size)
230 : : {
231 : 28446 : void *data = nl_msg_put_unspec_uninit(msg, type, size);
232 : 28446 : memset(data, 0, size);
233 : 28446 : return data;
234 : : }
235 : :
236 : : /* Appends a Netlink attribute of the given 'type' and the 'size' bytes of
237 : : * 'data' as its payload, to the tail end of 'msg', reallocating and copying
238 : : * its data if necessary. Returns a pointer to the first byte of data in the
239 : : * attribute, which is left uninitialized. */
240 : : void
241 : 548495 : nl_msg_put_unspec(struct ofpbuf *msg, uint16_t type,
242 : : const void *data, size_t size)
243 : : {
244 : 548495 : memcpy(nl_msg_put_unspec_uninit(msg, type, size), data, size);
245 : 548495 : }
246 : :
247 : : /* Appends a Netlink attribute of the given 'type' and no payload to 'msg'.
248 : : * (Some Netlink protocols use the presence or absence of an attribute as a
249 : : * Boolean flag.) */
250 : : void
251 : 5245 : nl_msg_put_flag(struct ofpbuf *msg, uint16_t type)
252 : : {
253 : 5245 : nl_msg_put_unspec(msg, type, NULL, 0);
254 : 5245 : }
255 : :
256 : : /* Appends a Netlink attribute of the given 'type' and the given 8-bit 'value'
257 : : * to 'msg'. */
258 : : void
259 : 15097 : nl_msg_put_u8(struct ofpbuf *msg, uint16_t type, uint8_t value)
260 : : {
261 : 15097 : nl_msg_put_unspec(msg, type, &value, sizeof value);
262 : 15097 : }
263 : :
264 : : /* Appends a Netlink attribute of the given 'type' and the given 16-bit host
265 : : * byte order 'value' to 'msg'. */
266 : : void
267 : 28219 : nl_msg_put_u16(struct ofpbuf *msg, uint16_t type, uint16_t value)
268 : : {
269 : 28219 : nl_msg_put_unspec(msg, type, &value, sizeof value);
270 : 28219 : }
271 : :
272 : : /* Appends a Netlink attribute of the given 'type' and the given 32-bit host
273 : : * byte order 'value' to 'msg'. */
274 : : void
275 : 329974 : nl_msg_put_u32(struct ofpbuf *msg, uint16_t type, uint32_t value)
276 : : {
277 : 329974 : nl_msg_put_unspec(msg, type, &value, sizeof value);
278 : 329974 : }
279 : :
280 : : /* Appends a Netlink attribute of the given 'type' and the given 64-bit host
281 : : * byte order 'value' to 'msg'. */
282 : : void
283 : 0 : nl_msg_put_u64(struct ofpbuf *msg, uint16_t type, uint64_t value)
284 : : {
285 : 0 : nl_msg_put_unspec(msg, type, &value, sizeof value);
286 : 0 : }
287 : :
288 : : /* Appends a Netlink attribute of the given 'type' and the given 16-bit network
289 : : * byte order 'value' to 'msg'. */
290 : : void
291 : 31967 : nl_msg_put_be16(struct ofpbuf *msg, uint16_t type, ovs_be16 value)
292 : : {
293 : 31967 : nl_msg_put_unspec(msg, type, &value, sizeof value);
294 : 31967 : }
295 : :
296 : : /* Appends a Netlink attribute of the given 'type' and the given 32-bit network
297 : : * byte order 'value' to 'msg'. */
298 : : void
299 : 4035 : nl_msg_put_be32(struct ofpbuf *msg, uint16_t type, ovs_be32 value)
300 : : {
301 : 4035 : nl_msg_put_unspec(msg, type, &value, sizeof value);
302 : 4035 : }
303 : :
304 : : /* Appends a Netlink attribute of the given 'type' and the given 64-bit network
305 : : * byte order 'value' to 'msg'. */
306 : : void
307 : 2873 : nl_msg_put_be64(struct ofpbuf *msg, uint16_t type, ovs_be64 value)
308 : : {
309 : 2873 : nl_msg_put_unspec(msg, type, &value, sizeof value);
310 : 2873 : }
311 : :
312 : : /* Appends a Netlink attribute of the given 'type' and the given IPv6
313 : : * address order 'value' to 'msg'. */
314 : : void
315 : 13 : nl_msg_put_in6_addr(struct ofpbuf *msg, uint16_t type,
316 : : const struct in6_addr *value)
317 : : {
318 : 13 : nl_msg_put_unspec(msg, type, value, sizeof *value);
319 : 13 : }
320 : :
321 : : /* Appends a Netlink attribute of the given 'type' and the given odp_port_t
322 : : * 'value' to 'msg'. */
323 : : void
324 : 121086 : nl_msg_put_odp_port(struct ofpbuf *msg, uint16_t type, odp_port_t value)
325 : : {
326 : 121086 : nl_msg_put_u32(msg, type, odp_to_u32(value));
327 : 121086 : }
328 : :
329 : : /* Appends a Netlink attribute of the given 'type' with the 'len' characters
330 : : * of 'value', followed by the null byte to 'msg'. */
331 : : void
332 : 2 : nl_msg_put_string__(struct ofpbuf *msg, uint16_t type, const char *value,
333 : : size_t len)
334 : : {
335 : 2 : char *data = nl_msg_put_unspec_uninit(msg, type, len + 1);
336 : :
337 : 2 : memcpy(data, value, len);
338 : 2 : data[len] = '\0';
339 : 2 : }
340 : :
341 : : /* Appends a Netlink attribute of the given 'type' and the given
342 : : * null-terminated string 'value' to 'msg'. */
343 : : void
344 : 6876 : nl_msg_put_string(struct ofpbuf *msg, uint16_t type, const char *value)
345 : : {
346 : 6876 : nl_msg_put_unspec(msg, type, value, strlen(value) + 1);
347 : 6876 : }
348 : :
349 : : /* Prepends a Netlink attribute of the given 'type' and room for 'size' bytes
350 : : * of data as its payload, plus Netlink padding if needed, to the head end of
351 : : * 'msg', reallocating and copying its data if necessary. Returns a pointer to
352 : : * the first byte of data in the attribute, which is left uninitialized. */
353 : : void *
354 : 0 : nl_msg_push_unspec_uninit(struct ofpbuf *msg, uint16_t type, size_t size)
355 : : {
356 : 0 : size_t total_size = NLA_HDRLEN + size;
357 : 0 : struct nlattr* nla = nl_msg_push_uninit(msg, total_size);
358 [ # # ]: 0 : ovs_assert(!nl_attr_oversized(size));
359 : 0 : nla->nla_len = total_size;
360 : 0 : nla->nla_type = type;
361 : 0 : return nla + 1;
362 : : }
363 : :
364 : : /* Prepends a Netlink attribute of the given 'type' and the 'size' bytes of
365 : : * 'data' as its payload, to the head end of 'msg', reallocating and copying
366 : : * its data if necessary. Returns a pointer to the first byte of data in the
367 : : * attribute, which is left uninitialized. */
368 : : void
369 : 0 : nl_msg_push_unspec(struct ofpbuf *msg, uint16_t type,
370 : : const void *data, size_t size)
371 : : {
372 : 0 : memcpy(nl_msg_push_unspec_uninit(msg, type, size), data, size);
373 : 0 : }
374 : :
375 : : /* Prepends a Netlink attribute of the given 'type' and no payload to 'msg'.
376 : : * (Some Netlink protocols use the presence or absence of an attribute as a
377 : : * Boolean flag.) */
378 : : void
379 : 0 : nl_msg_push_flag(struct ofpbuf *msg, uint16_t type)
380 : : {
381 : 0 : nl_msg_push_unspec_uninit(msg, type, 0);
382 : 0 : }
383 : :
384 : : /* Prepends a Netlink attribute of the given 'type' and the given 8-bit 'value'
385 : : * to 'msg'. */
386 : : void
387 : 0 : nl_msg_push_u8(struct ofpbuf *msg, uint16_t type, uint8_t value)
388 : : {
389 : 0 : nl_msg_push_unspec(msg, type, &value, sizeof value);
390 : 0 : }
391 : :
392 : : /* Prepends a Netlink attribute of the given 'type' and the given 16-bit host
393 : : * byte order 'value' to 'msg'. */
394 : : void
395 : 0 : nl_msg_push_u16(struct ofpbuf *msg, uint16_t type, uint16_t value)
396 : : {
397 : 0 : nl_msg_push_unspec(msg, type, &value, sizeof value);
398 : 0 : }
399 : :
400 : : /* Prepends a Netlink attribute of the given 'type' and the given 32-bit host
401 : : * byte order 'value' to 'msg'. */
402 : : void
403 : 0 : nl_msg_push_u32(struct ofpbuf *msg, uint16_t type, uint32_t value)
404 : : {
405 : 0 : nl_msg_push_unspec(msg, type, &value, sizeof value);
406 : 0 : }
407 : :
408 : : /* Prepends a Netlink attribute of the given 'type' and the given 64-bit host
409 : : * byte order 'value' to 'msg'. */
410 : : void
411 : 0 : nl_msg_push_u64(struct ofpbuf *msg, uint16_t type, uint64_t value)
412 : : {
413 : 0 : nl_msg_push_unspec(msg, type, &value, sizeof value);
414 : 0 : }
415 : :
416 : : /* Prepends a Netlink attribute of the given 'type' and the given 16-bit
417 : : * network byte order 'value' to 'msg'. */
418 : : void
419 : 0 : nl_msg_push_be16(struct ofpbuf *msg, uint16_t type, ovs_be16 value)
420 : : {
421 : 0 : nl_msg_push_unspec(msg, type, &value, sizeof value);
422 : 0 : }
423 : :
424 : : /* Prepends a Netlink attribute of the given 'type' and the given 32-bit
425 : : * network byte order 'value' to 'msg'. */
426 : : void
427 : 0 : nl_msg_push_be32(struct ofpbuf *msg, uint16_t type, ovs_be32 value)
428 : : {
429 : 0 : nl_msg_push_unspec(msg, type, &value, sizeof value);
430 : 0 : }
431 : :
432 : : /* Prepends a Netlink attribute of the given 'type' and the given 64-bit
433 : : * network byte order 'value' to 'msg'. */
434 : : void
435 : 0 : nl_msg_push_be64(struct ofpbuf *msg, uint16_t type, ovs_be64 value)
436 : : {
437 : 0 : nl_msg_push_unspec(msg, type, &value, sizeof value);
438 : 0 : }
439 : :
440 : : /* Prepends a Netlink attribute of the given 'type' and the given
441 : : * null-terminated string 'value' to 'msg'. */
442 : : void
443 : 0 : nl_msg_push_string(struct ofpbuf *msg, uint16_t type, const char *value)
444 : : {
445 : 0 : nl_msg_push_unspec(msg, type, value, strlen(value) + 1);
446 : 0 : }
447 : :
448 : : /* Adds the header for nested Netlink attributes to 'msg', with the specified
449 : : * 'type', and returns the header's offset within 'msg'. The caller should add
450 : : * the content for the nested Netlink attribute to 'msg' (e.g. using the other
451 : : * nl_msg_*() functions), and then pass the returned offset to
452 : : * nl_msg_end_nested() to finish up the nested attributes. */
453 : : size_t
454 : 58243 : nl_msg_start_nested(struct ofpbuf *msg, uint16_t type)
455 : : {
456 : 58243 : size_t offset = msg->size;
457 : 58243 : nl_msg_put_unspec(msg, type, NULL, 0);
458 : 58243 : return offset;
459 : : }
460 : :
461 : : /* Finalizes a nested Netlink attribute in 'msg'. 'offset' should be the value
462 : : * returned by nl_msg_start_nested(). */
463 : : void
464 : 58243 : nl_msg_end_nested(struct ofpbuf *msg, size_t offset)
465 : : {
466 : 58243 : struct nlattr *attr = ofpbuf_at_assert(msg, offset, sizeof *attr);
467 : 58243 : attr->nla_len = msg->size - offset;
468 : 58243 : }
469 : :
470 : : /* Appends a nested Netlink attribute of the given 'type', with the 'size'
471 : : * bytes of content starting at 'data', to 'msg'. */
472 : : void
473 : 3 : nl_msg_put_nested(struct ofpbuf *msg,
474 : : uint16_t type, const void *data, size_t size)
475 : : {
476 : 3 : size_t offset = nl_msg_start_nested(msg, type);
477 : 3 : nl_msg_put(msg, data, size);
478 : 3 : nl_msg_end_nested(msg, offset);
479 : 3 : }
480 : :
481 : : /* If 'buffer' begins with a valid "struct nlmsghdr", pulls the header and its
482 : : * payload off 'buffer', stores header and payload in 'msg->data' and
483 : : * 'msg->size', and returns a pointer to the header.
484 : : *
485 : : * If 'buffer' does not begin with a "struct nlmsghdr" or begins with one that
486 : : * is invalid, returns NULL and clears 'buffer' and 'msg'. */
487 : : struct nlmsghdr *
488 : 79864 : nl_msg_next(struct ofpbuf *buffer, struct ofpbuf *msg)
489 : : {
490 [ + - ]: 79864 : if (buffer->size >= sizeof(struct nlmsghdr)) {
491 : 79864 : struct nlmsghdr *nlmsghdr = nl_msg_nlmsghdr(buffer);
492 : 79864 : size_t len = nlmsghdr->nlmsg_len;
493 [ + - ][ + - ]: 79864 : if (len >= sizeof *nlmsghdr && len <= buffer->size) {
494 : 79864 : ofpbuf_use_const(msg, nlmsghdr, len);
495 : 79864 : ofpbuf_pull(buffer, len);
496 : 79864 : return nlmsghdr;
497 : : }
498 : : }
499 : :
500 : 0 : ofpbuf_clear(buffer);
501 : 0 : msg->data = NULL;
502 : 0 : msg->size = 0;
503 : 0 : return NULL;
504 : : }
505 : :
506 : : /* Returns true if a Netlink attribute with a payload that is 'payload_size'
507 : : * bytes long would be oversized, that is, if it's not possible to create an
508 : : * nlattr of that size because its size wouldn't fit in the 16-bit nla_len
509 : : * field. */
510 : : bool
511 : 738340 : nl_attr_oversized(size_t payload_size)
512 : : {
513 : 738340 : return payload_size > UINT16_MAX - NLA_HDRLEN;
514 : : }
515 : :
516 : : /* Attributes. */
517 : :
518 : : /* Returns the bits of 'nla->nla_type' that are significant for determining its
519 : : * type. */
520 : : int
521 : 34650595 : nl_attr_type(const struct nlattr *nla)
522 : : {
523 : 34650595 : return nla->nla_type & NLA_TYPE_MASK;
524 : : }
525 : :
526 : : /* Returns the first byte in the payload of attribute 'nla'. */
527 : : const void *
528 : 765732 : nl_attr_get(const struct nlattr *nla)
529 : : {
530 [ - + ]: 765732 : ovs_assert(nla->nla_len >= NLA_HDRLEN);
531 : 765732 : return nla + 1;
532 : : }
533 : :
534 : : /* Returns the number of bytes in the payload of attribute 'nla'. */
535 : : size_t
536 : 18187342 : nl_attr_get_size(const struct nlattr *nla)
537 : : {
538 [ - + ]: 18187342 : ovs_assert(nla->nla_len >= NLA_HDRLEN);
539 : 18187342 : return nla->nla_len - NLA_HDRLEN;
540 : : }
541 : :
542 : : /* Asserts that 'nla''s payload is at least 'size' bytes long, and returns the
543 : : * first byte of the payload. */
544 : : const void *
545 : 17290299 : nl_attr_get_unspec(const struct nlattr *nla, size_t size)
546 : : {
547 [ - + ]: 17290299 : ovs_assert(nla->nla_len >= NLA_HDRLEN + size);
548 : 17290299 : return nla + 1;
549 : : }
550 : :
551 : : /* Returns true if 'nla' is nonnull. (Some Netlink protocols use the presence
552 : : * or absence of an attribute as a Boolean flag.) */
553 : : bool
554 : 0 : nl_attr_get_flag(const struct nlattr *nla)
555 : : {
556 : 0 : return nla != NULL;
557 : : }
558 : :
559 : : #define NL_ATTR_GET_AS(NLA, TYPE) \
560 : : (*(TYPE*) nl_attr_get_unspec(nla, sizeof(TYPE)))
561 : :
562 : : /* Returns the 8-bit value in 'nla''s payload.
563 : : *
564 : : * Asserts that 'nla''s payload is at least 1 byte long. */
565 : : uint8_t
566 : 87105 : nl_attr_get_u8(const struct nlattr *nla)
567 : : {
568 : 87105 : return NL_ATTR_GET_AS(nla, uint8_t);
569 : : }
570 : :
571 : : /* Returns the 16-bit host byte order value in 'nla''s payload.
572 : : *
573 : : * Asserts that 'nla''s payload is at least 2 bytes long. */
574 : : uint16_t
575 : 146617 : nl_attr_get_u16(const struct nlattr *nla)
576 : : {
577 : 146617 : return NL_ATTR_GET_AS(nla, uint16_t);
578 : : }
579 : :
580 : : /* Returns the 32-bit host byte order value in 'nla''s payload.
581 : : *
582 : : * Asserts that 'nla''s payload is at least 4 bytes long. */
583 : : uint32_t
584 : 16753836 : nl_attr_get_u32(const struct nlattr *nla)
585 : : {
586 : 16753836 : return NL_ATTR_GET_AS(nla, uint32_t);
587 : : }
588 : :
589 : : /* Returns the 64-bit host byte order value in 'nla''s payload.
590 : : *
591 : : * Asserts that 'nla''s payload is at least 8 bytes long. */
592 : : uint64_t
593 : 0 : nl_attr_get_u64(const struct nlattr *nla)
594 : : {
595 : 0 : const ovs_32aligned_u64 *x = nl_attr_get_unspec(nla, sizeof *x);
596 : 0 : return get_32aligned_u64(x);
597 : : }
598 : :
599 : : /* Returns the 16-bit network byte order value in 'nla''s payload.
600 : : *
601 : : * Asserts that 'nla''s payload is at least 2 bytes long. */
602 : : ovs_be16
603 : 174663 : nl_attr_get_be16(const struct nlattr *nla)
604 : : {
605 : 174663 : return NL_ATTR_GET_AS(nla, ovs_be16);
606 : : }
607 : :
608 : : /* Returns the 32-bit network byte order value in 'nla''s payload.
609 : : *
610 : : * Asserts that 'nla''s payload is at least 4 bytes long. */
611 : : ovs_be32
612 : 60169 : nl_attr_get_be32(const struct nlattr *nla)
613 : : {
614 : 60169 : return NL_ATTR_GET_AS(nla, ovs_be32);
615 : : }
616 : :
617 : : /* Returns the 64-bit network byte order value in 'nla''s payload.
618 : : *
619 : : * Asserts that 'nla''s payload is at least 8 bytes long. */
620 : : ovs_be64
621 : 18396 : nl_attr_get_be64(const struct nlattr *nla)
622 : : {
623 : 18396 : const ovs_32aligned_be64 *x = nl_attr_get_unspec(nla, sizeof *x);
624 : 18396 : return get_32aligned_be64(x);
625 : : }
626 : :
627 : : /* Returns the IPv6 address value in 'nla''s payload.
628 : : *
629 : : * Asserts that 'nla''s payload is at least 16 bytes long. */
630 : : struct in6_addr
631 : 38718 : nl_attr_get_in6_addr(const struct nlattr *nla)
632 : : {
633 : 38718 : return NL_ATTR_GET_AS(nla, struct in6_addr);
634 : : }
635 : :
636 : : /* Returns the 32-bit odp_port_t value in 'nla''s payload.
637 : : *
638 : : * Asserts that 'nla''s payload is at least 4 bytes long. */
639 : : odp_port_t
640 : 162938 : nl_attr_get_odp_port(const struct nlattr *nla)
641 : : {
642 : 162938 : return u32_to_odp(nl_attr_get_u32(nla));
643 : : }
644 : :
645 : : /* Returns the null-terminated string value in 'nla''s payload.
646 : : *
647 : : * Asserts that 'nla''s payload contains a null-terminated string. */
648 : : const char *
649 : 11523 : nl_attr_get_string(const struct nlattr *nla)
650 : : {
651 [ - + ]: 11523 : ovs_assert(nla->nla_len > NLA_HDRLEN);
652 [ - + ]: 11523 : ovs_assert(memchr(nl_attr_get(nla), '\0', nla->nla_len - NLA_HDRLEN));
653 : 11523 : return nl_attr_get(nla);
654 : : }
655 : :
656 : : /* Initializes 'nested' to the payload of 'nla'. */
657 : : void
658 : 3658 : nl_attr_get_nested(const struct nlattr *nla, struct ofpbuf *nested)
659 : : {
660 : 3658 : ofpbuf_use_const(nested, nl_attr_get(nla), nl_attr_get_size(nla));
661 : 3658 : }
662 : :
663 : : /* Default minimum payload size for each type of attribute. */
664 : : static size_t
665 : 189259 : min_attr_len(enum nl_attr_type type)
666 : : {
667 [ - + + + : 189259 : switch (type) {
+ + + + +
+ - ]
668 : 0 : case NL_A_NO_ATTR: return 0;
669 : 9775 : case NL_A_UNSPEC: return 0;
670 : 3474 : case NL_A_U8: return 1;
671 : 3273 : case NL_A_U16: return 2;
672 : 110362 : case NL_A_U32: return 4;
673 : 4228 : case NL_A_U64: return 8;
674 : 11523 : case NL_A_STRING: return 1;
675 : 103 : case NL_A_FLAG: return 0;
676 : 38707 : case NL_A_IPV6: return 16;
677 : 7814 : case NL_A_NESTED: return 0;
678 : 0 : case N_NL_ATTR_TYPES: default: OVS_NOT_REACHED();
679 : : }
680 : : }
681 : :
682 : : /* Default maximum payload size for each type of attribute. */
683 : : static size_t
684 : 193718 : max_attr_len(enum nl_attr_type type)
685 : : {
686 [ - + + + : 193718 : switch (type) {
+ + + + +
+ - ]
687 : 0 : case NL_A_NO_ATTR: return SIZE_MAX;
688 : 20454 : case NL_A_UNSPEC: return SIZE_MAX;
689 : 3474 : case NL_A_U8: return 1;
690 : 3273 : case NL_A_U16: return 2;
691 : 110362 : case NL_A_U32: return 4;
692 : 4228 : case NL_A_U64: return 8;
693 : 5303 : case NL_A_STRING: return SIZE_MAX;
694 : 103 : case NL_A_FLAG: return SIZE_MAX;
695 : 38707 : case NL_A_IPV6: return 16;
696 : 7814 : case NL_A_NESTED: return SIZE_MAX;
697 : 0 : case N_NL_ATTR_TYPES: default: OVS_NOT_REACHED();
698 : : }
699 : : }
700 : :
701 : : bool
702 : 211764 : nl_attr_validate(const struct nlattr *nla, const struct nl_policy *policy)
703 : : {
704 : 211764 : uint16_t type = nl_attr_type(nla);
705 : : size_t min_len;
706 : : size_t max_len;
707 : : size_t len;
708 : :
709 [ - + ]: 211764 : if (policy->type == NL_A_NO_ATTR) {
710 : 0 : return true;
711 : : }
712 : :
713 : : /* Figure out min and max length. */
714 : 211764 : min_len = policy->min_len;
715 [ + + ]: 211764 : if (!min_len) {
716 : 189258 : min_len = min_attr_len(policy->type);
717 : : }
718 : 211764 : max_len = policy->max_len;
719 [ + + ]: 211764 : if (!max_len) {
720 : 193717 : max_len = max_attr_len(policy->type);
721 : : }
722 : :
723 : : /* Verify length. */
724 : 211763 : len = nl_attr_get_size(nla);
725 [ + - ][ - + ]: 211763 : if (len < min_len || len > max_len) {
726 [ # # ]: 0 : VLOG_DBG_RL(&rl, "attr %"PRIu16" length %"PRIuSIZE" not in "
727 : : "allowed range %"PRIuSIZE"...%"PRIuSIZE, type, len, min_len, max_len);
728 : 0 : return false;
729 : : }
730 : :
731 : : /* Strings must be null terminated and must not have embedded nulls. */
732 [ + + ]: 211763 : if (policy->type == NL_A_STRING) {
733 [ - + ]: 11525 : if (((char *) nla)[nla->nla_len - 1]) {
734 [ # # ]: 0 : VLOG_DBG_RL(&rl, "attr %"PRIu16" lacks null at end", type);
735 : 0 : return false;
736 : : }
737 [ - + ]: 11525 : if (memchr(nla + 1, '\0', len - 1) != NULL) {
738 [ # # ]: 0 : VLOG_DBG_RL(&rl, "attr %"PRIu16" has bad length", type);
739 : 0 : return false;
740 : : }
741 : : }
742 : :
743 : 211763 : return true;
744 : : }
745 : :
746 : : /* Parses the 'msg' starting at the given 'nla_offset' as a sequence of Netlink
747 : : * attributes. 'policy[i]', for 0 <= i < n_attrs, specifies how the attribute
748 : : * with nla_type == i is parsed; a pointer to attribute i is stored in
749 : : * attrs[i]. Returns true if successful, false on failure.
750 : : *
751 : : * If the Netlink attributes in 'msg' follow a Netlink header and a Generic
752 : : * Netlink header, then 'nla_offset' should be NLMSG_HDRLEN + GENL_HDRLEN. */
753 : : bool
754 : 94250 : nl_policy_parse(const struct ofpbuf *msg, size_t nla_offset,
755 : : const struct nl_policy policy[],
756 : : struct nlattr *attrs[], size_t n_attrs)
757 : : {
758 : : struct nlattr *nla;
759 : : size_t left;
760 : : size_t i;
761 : :
762 : 94250 : memset(attrs, 0, n_attrs * sizeof *attrs);
763 : :
764 [ - + ]: 94250 : if (msg->size < nla_offset) {
765 [ # # ]: 0 : VLOG_DBG_RL(&rl, "missing headers in nl_policy_parse");
766 : 0 : return false;
767 : : }
768 : :
769 [ + + ]: 607781 : NL_ATTR_FOR_EACH (nla, left, ofpbuf_at(msg, nla_offset, 0),
770 : : msg->size - nla_offset)
771 : : {
772 : 513532 : uint16_t type = nl_attr_type(nla);
773 [ + + ][ + + ]: 513532 : if (type < n_attrs && policy[type].type != NL_A_NO_ATTR) {
774 : 211764 : const struct nl_policy *e = &policy[type];
775 [ - + ]: 211764 : if (!nl_attr_validate(nla, e)) {
776 : 0 : return false;
777 : : }
778 [ - + ]: 211763 : if (attrs[type]) {
779 [ # # ]: 0 : VLOG_DBG_RL(&rl, "duplicate attr %"PRIu16, type);
780 : : }
781 : 211763 : attrs[type] = nla;
782 : : }
783 : : }
784 [ - + ]: 94249 : if (left) {
785 [ # # ]: 0 : VLOG_DBG_RL(&rl, "attributes followed by garbage");
786 : 0 : return false;
787 : : }
788 : :
789 [ + + ]: 755943 : for (i = 0; i < n_attrs; i++) {
790 : 661694 : const struct nl_policy *e = &policy[i];
791 [ + + ][ + + ]: 661694 : if (!e->optional && e->type != NL_A_NO_ATTR && !attrs[i]) {
[ - + ]
792 [ # # ]: 0 : VLOG_DBG_RL(&rl, "required attr %"PRIuSIZE" missing", i);
793 : 0 : return false;
794 : : }
795 : : }
796 : 94249 : return true;
797 : : }
798 : :
799 : : /* Parses the Netlink attributes within 'nla'. 'policy[i]', for 0 <= i <
800 : : * n_attrs, specifies how the attribute with nla_type == i is parsed; a pointer
801 : : * to attribute i is stored in attrs[i]. Returns true if successful, false on
802 : : * failure. */
803 : : bool
804 : 3658 : nl_parse_nested(const struct nlattr *nla, const struct nl_policy policy[],
805 : : struct nlattr *attrs[], size_t n_attrs)
806 : : {
807 : : struct ofpbuf buf;
808 : :
809 : 3658 : nl_attr_get_nested(nla, &buf);
810 : 3658 : return nl_policy_parse(&buf, 0, policy, attrs, n_attrs);
811 : : }
812 : :
813 : : const struct nlattr *
814 : 55062 : nl_attr_find__(const struct nlattr *attrs, size_t size, uint16_t type)
815 : : {
816 : : const struct nlattr *nla;
817 : : size_t left;
818 : :
819 [ + + ]: 416026 : NL_ATTR_FOR_EACH (nla, left, attrs, size) {
820 [ + + ]: 403672 : if (nl_attr_type(nla) == type) {
821 : 42708 : return nla;
822 : : }
823 : : }
824 : 12354 : return NULL;
825 : : }
826 : :
827 : : /* Returns the first Netlink attribute within 'buf' with the specified 'type',
828 : : * skipping a header of 'hdr_len' bytes at the beginning of 'buf'.
829 : : *
830 : : * This function does not validate the attribute's length. */
831 : : const struct nlattr *
832 : 425 : nl_attr_find(const struct ofpbuf *buf, size_t hdr_len, uint16_t type)
833 : : {
834 : 425 : return nl_attr_find__(ofpbuf_at(buf, hdr_len, 0), buf->size - hdr_len,
835 : : type);
836 : : }
837 : :
838 : : /* Returns the first Netlink attribute within 'nla' with the specified
839 : : * 'type'.
840 : : *
841 : : * This function does not validate the attribute's length. */
842 : : const struct nlattr *
843 : 14541 : nl_attr_find_nested(const struct nlattr *nla, uint16_t type)
844 : : {
845 : 14541 : return nl_attr_find__(nl_attr_get(nla), nl_attr_get_size(nla), type);
846 : : }
|