diff options
author | David S. Miller <davem@davemloft.net> | 2016-04-21 14:22:14 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-04-21 14:22:14 -0400 |
commit | c57107c7f59fe438f8c5bb0ce50af857505276b8 (patch) | |
tree | 515f5e73913a81246590ea7cb1b7a08f5c349eda | |
parent | 732912d727cd6deb3c1a05a8baa74b8ce8d510ac (diff) | |
parent | 3d6b66c1d1a8d348928996ca333730f258fbb838 (diff) |
Merge branch 'nlattr_align'
Nicolas Dichtel says:
====================
libnl: enhance API to ease 64bit alignment for attribute
Here is a proposal to add more helpers in the libnetlink to manage 64-bit
alignment issues.
Note that this series was only tested on x86 by tweeking
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS and adding some traces.
The first patch adds helpers for 64bit alignment and other patches
use them.
We could also add helpers for nla_put_u64() and its variants if needed.
v1 -> v2:
- remove patch #1
- split patch #2 (now #1 and #2)
- add nla_need_padding_for_64bit()
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/netlink.h | 39 | ||||
-rw-r--r-- | include/uapi/linux/rtnetlink.h | 1 | ||||
-rw-r--r-- | lib/nlattr.c | 99 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 22 | ||||
-rw-r--r-- | net/ipv4/ipmr.c | 4 | ||||
-rw-r--r-- | net/ipv6/ip6mr.c | 4 |
6 files changed, 140 insertions, 29 deletions
diff --git a/include/net/netlink.h b/include/net/netlink.h index 3c1fd92a52c8..6f51a8a06498 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h | |||
@@ -244,13 +244,21 @@ int nla_memcpy(void *dest, const struct nlattr *src, int count); | |||
244 | int nla_memcmp(const struct nlattr *nla, const void *data, size_t size); | 244 | int nla_memcmp(const struct nlattr *nla, const void *data, size_t size); |
245 | int nla_strcmp(const struct nlattr *nla, const char *str); | 245 | int nla_strcmp(const struct nlattr *nla, const char *str); |
246 | struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen); | 246 | struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen); |
247 | struct nlattr *__nla_reserve_64bit(struct sk_buff *skb, int attrtype, | ||
248 | int attrlen, int padattr); | ||
247 | void *__nla_reserve_nohdr(struct sk_buff *skb, int attrlen); | 249 | void *__nla_reserve_nohdr(struct sk_buff *skb, int attrlen); |
248 | struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen); | 250 | struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen); |
251 | struct nlattr *nla_reserve_64bit(struct sk_buff *skb, int attrtype, | ||
252 | int attrlen, int padattr); | ||
249 | void *nla_reserve_nohdr(struct sk_buff *skb, int attrlen); | 253 | void *nla_reserve_nohdr(struct sk_buff *skb, int attrlen); |
250 | void __nla_put(struct sk_buff *skb, int attrtype, int attrlen, | 254 | void __nla_put(struct sk_buff *skb, int attrtype, int attrlen, |
251 | const void *data); | 255 | const void *data); |
256 | void __nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen, | ||
257 | const void *data, int padattr); | ||
252 | void __nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data); | 258 | void __nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data); |
253 | int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data); | 259 | int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data); |
260 | int nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen, | ||
261 | const void *data, int padattr); | ||
254 | int nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data); | 262 | int nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data); |
255 | int nla_append(struct sk_buff *skb, int attrlen, const void *data); | 263 | int nla_append(struct sk_buff *skb, int attrlen, const void *data); |
256 | 264 | ||
@@ -1231,6 +1239,27 @@ static inline int nla_validate_nested(const struct nlattr *start, int maxtype, | |||
1231 | } | 1239 | } |
1232 | 1240 | ||
1233 | /** | 1241 | /** |
1242 | * nla_need_padding_for_64bit - test 64-bit alignment of the next attribute | ||
1243 | * @skb: socket buffer the message is stored in | ||
1244 | * | ||
1245 | * Return true if padding is needed to align the next attribute (nla_data()) to | ||
1246 | * a 64-bit aligned area. | ||
1247 | */ | ||
1248 | static inline bool nla_need_padding_for_64bit(struct sk_buff *skb) | ||
1249 | { | ||
1250 | #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS | ||
1251 | /* The nlattr header is 4 bytes in size, that's why we test | ||
1252 | * if the skb->data _is_ aligned. A NOP attribute, plus | ||
1253 | * nlattr header for next attribute, will make nla_data() | ||
1254 | * 8-byte aligned. | ||
1255 | */ | ||
1256 | if (IS_ALIGNED((unsigned long)skb_tail_pointer(skb), 8)) | ||
1257 | return true; | ||
1258 | #endif | ||
1259 | return false; | ||
1260 | } | ||
1261 | |||
1262 | /** | ||
1234 | * nla_align_64bit - 64-bit align the nla_data() of next attribute | 1263 | * nla_align_64bit - 64-bit align the nla_data() of next attribute |
1235 | * @skb: socket buffer the message is stored in | 1264 | * @skb: socket buffer the message is stored in |
1236 | * @padattr: attribute type for the padding | 1265 | * @padattr: attribute type for the padding |
@@ -1244,16 +1273,10 @@ static inline int nla_validate_nested(const struct nlattr *start, int maxtype, | |||
1244 | */ | 1273 | */ |
1245 | static inline int nla_align_64bit(struct sk_buff *skb, int padattr) | 1274 | static inline int nla_align_64bit(struct sk_buff *skb, int padattr) |
1246 | { | 1275 | { |
1247 | #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS | 1276 | if (nla_need_padding_for_64bit(skb) && |
1248 | /* The nlattr header is 4 bytes in size, that's why we test | ||
1249 | * if the skb->data _is_ aligned. This NOP attribute, plus | ||
1250 | * nlattr header for next attribute, will make nla_data() | ||
1251 | * 8-byte aligned. | ||
1252 | */ | ||
1253 | if (IS_ALIGNED((unsigned long)skb_tail_pointer(skb), 8) && | ||
1254 | !nla_reserve(skb, padattr, 0)) | 1277 | !nla_reserve(skb, padattr, 0)) |
1255 | return -EMSGSIZE; | 1278 | return -EMSGSIZE; |
1256 | #endif | 1279 | |
1257 | return 0; | 1280 | return 0; |
1258 | } | 1281 | } |
1259 | 1282 | ||
diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index cc885c4e9065..a94e0b69c769 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h | |||
@@ -317,6 +317,7 @@ enum rtattr_type_t { | |||
317 | RTA_ENCAP_TYPE, | 317 | RTA_ENCAP_TYPE, |
318 | RTA_ENCAP, | 318 | RTA_ENCAP, |
319 | RTA_EXPIRES, | 319 | RTA_EXPIRES, |
320 | RTA_PAD, | ||
320 | __RTA_MAX | 321 | __RTA_MAX |
321 | }; | 322 | }; |
322 | 323 | ||
diff --git a/lib/nlattr.c b/lib/nlattr.c index f5907d23272d..2b82f1e2ebc2 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c | |||
@@ -355,6 +355,29 @@ struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen) | |||
355 | EXPORT_SYMBOL(__nla_reserve); | 355 | EXPORT_SYMBOL(__nla_reserve); |
356 | 356 | ||
357 | /** | 357 | /** |
358 | * __nla_reserve_64bit - reserve room for attribute on the skb and align it | ||
359 | * @skb: socket buffer to reserve room on | ||
360 | * @attrtype: attribute type | ||
361 | * @attrlen: length of attribute payload | ||
362 | * | ||
363 | * Adds a netlink attribute header to a socket buffer and reserves | ||
364 | * room for the payload but does not copy it. It also ensure that this | ||
365 | * attribute will be 64-bit aign. | ||
366 | * | ||
367 | * The caller is responsible to ensure that the skb provides enough | ||
368 | * tailroom for the attribute header and payload. | ||
369 | */ | ||
370 | struct nlattr *__nla_reserve_64bit(struct sk_buff *skb, int attrtype, | ||
371 | int attrlen, int padattr) | ||
372 | { | ||
373 | if (nla_need_padding_for_64bit(skb)) | ||
374 | nla_align_64bit(skb, padattr); | ||
375 | |||
376 | return __nla_reserve(skb, attrtype, attrlen); | ||
377 | } | ||
378 | EXPORT_SYMBOL(__nla_reserve_64bit); | ||
379 | |||
380 | /** | ||
358 | * __nla_reserve_nohdr - reserve room for attribute without header | 381 | * __nla_reserve_nohdr - reserve room for attribute without header |
359 | * @skb: socket buffer to reserve room on | 382 | * @skb: socket buffer to reserve room on |
360 | * @attrlen: length of attribute payload | 383 | * @attrlen: length of attribute payload |
@@ -397,6 +420,35 @@ struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen) | |||
397 | EXPORT_SYMBOL(nla_reserve); | 420 | EXPORT_SYMBOL(nla_reserve); |
398 | 421 | ||
399 | /** | 422 | /** |
423 | * nla_reserve_64bit - reserve room for attribute on the skb and align it | ||
424 | * @skb: socket buffer to reserve room on | ||
425 | * @attrtype: attribute type | ||
426 | * @attrlen: length of attribute payload | ||
427 | * | ||
428 | * Adds a netlink attribute header to a socket buffer and reserves | ||
429 | * room for the payload but does not copy it. It also ensure that this | ||
430 | * attribute will be 64-bit aign. | ||
431 | * | ||
432 | * Returns NULL if the tailroom of the skb is insufficient to store | ||
433 | * the attribute header and payload. | ||
434 | */ | ||
435 | struct nlattr *nla_reserve_64bit(struct sk_buff *skb, int attrtype, int attrlen, | ||
436 | int padattr) | ||
437 | { | ||
438 | size_t len; | ||
439 | |||
440 | if (nla_need_padding_for_64bit(skb)) | ||
441 | len = nla_total_size_64bit(attrlen); | ||
442 | else | ||
443 | len = nla_total_size(attrlen); | ||
444 | if (unlikely(skb_tailroom(skb) < len)) | ||
445 | return NULL; | ||
446 | |||
447 | return __nla_reserve_64bit(skb, attrtype, attrlen, padattr); | ||
448 | } | ||
449 | EXPORT_SYMBOL(nla_reserve_64bit); | ||
450 | |||
451 | /** | ||
400 | * nla_reserve_nohdr - reserve room for attribute without header | 452 | * nla_reserve_nohdr - reserve room for attribute without header |
401 | * @skb: socket buffer to reserve room on | 453 | * @skb: socket buffer to reserve room on |
402 | * @attrlen: length of attribute payload | 454 | * @attrlen: length of attribute payload |
@@ -436,6 +488,26 @@ void __nla_put(struct sk_buff *skb, int attrtype, int attrlen, | |||
436 | EXPORT_SYMBOL(__nla_put); | 488 | EXPORT_SYMBOL(__nla_put); |
437 | 489 | ||
438 | /** | 490 | /** |
491 | * __nla_put_64bit - Add a netlink attribute to a socket buffer and align it | ||
492 | * @skb: socket buffer to add attribute to | ||
493 | * @attrtype: attribute type | ||
494 | * @attrlen: length of attribute payload | ||
495 | * @data: head of attribute payload | ||
496 | * | ||
497 | * The caller is responsible to ensure that the skb provides enough | ||
498 | * tailroom for the attribute header and payload. | ||
499 | */ | ||
500 | void __nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen, | ||
501 | const void *data, int padattr) | ||
502 | { | ||
503 | struct nlattr *nla; | ||
504 | |||
505 | nla = __nla_reserve_64bit(skb, attrtype, attrlen, padattr); | ||
506 | memcpy(nla_data(nla), data, attrlen); | ||
507 | } | ||
508 | EXPORT_SYMBOL(__nla_put_64bit); | ||
509 | |||
510 | /** | ||
439 | * __nla_put_nohdr - Add a netlink attribute without header | 511 | * __nla_put_nohdr - Add a netlink attribute without header |
440 | * @skb: socket buffer to add attribute to | 512 | * @skb: socket buffer to add attribute to |
441 | * @attrlen: length of attribute payload | 513 | * @attrlen: length of attribute payload |
@@ -474,6 +546,33 @@ int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data) | |||
474 | EXPORT_SYMBOL(nla_put); | 546 | EXPORT_SYMBOL(nla_put); |
475 | 547 | ||
476 | /** | 548 | /** |
549 | * nla_put_64bit - Add a netlink attribute to a socket buffer and align it | ||
550 | * @skb: socket buffer to add attribute to | ||
551 | * @attrtype: attribute type | ||
552 | * @attrlen: length of attribute payload | ||
553 | * @data: head of attribute payload | ||
554 | * | ||
555 | * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store | ||
556 | * the attribute header and payload. | ||
557 | */ | ||
558 | int nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen, | ||
559 | const void *data, int padattr) | ||
560 | { | ||
561 | size_t len; | ||
562 | |||
563 | if (nla_need_padding_for_64bit(skb)) | ||
564 | len = nla_total_size_64bit(attrlen); | ||
565 | else | ||
566 | len = nla_total_size(attrlen); | ||
567 | if (unlikely(skb_tailroom(skb) < len)) | ||
568 | return -EMSGSIZE; | ||
569 | |||
570 | __nla_put_64bit(skb, attrtype, attrlen, data, padattr); | ||
571 | return 0; | ||
572 | } | ||
573 | EXPORT_SYMBOL(nla_put_64bit); | ||
574 | |||
575 | /** | ||
477 | * nla_put_nohdr - Add a netlink attribute without header | 576 | * nla_put_nohdr - Add a netlink attribute without header |
478 | * @skb: socket buffer to add attribute to | 577 | * @skb: socket buffer to add attribute to |
479 | * @attrlen: length of attribute payload | 578 | * @attrlen: length of attribute payload |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 4a47a9aceb1d..5ec059d52823 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -1051,14 +1051,9 @@ static noinline_for_stack int rtnl_fill_stats(struct sk_buff *skb, | |||
1051 | { | 1051 | { |
1052 | struct rtnl_link_stats64 *sp; | 1052 | struct rtnl_link_stats64 *sp; |
1053 | struct nlattr *attr; | 1053 | struct nlattr *attr; |
1054 | int err; | ||
1055 | |||
1056 | err = nla_align_64bit(skb, IFLA_PAD); | ||
1057 | if (err) | ||
1058 | return err; | ||
1059 | 1054 | ||
1060 | attr = nla_reserve(skb, IFLA_STATS64, | 1055 | attr = nla_reserve_64bit(skb, IFLA_STATS64, |
1061 | sizeof(struct rtnl_link_stats64)); | 1056 | sizeof(struct rtnl_link_stats64), IFLA_PAD); |
1062 | if (!attr) | 1057 | if (!attr) |
1063 | return -EMSGSIZE; | 1058 | return -EMSGSIZE; |
1064 | 1059 | ||
@@ -3469,17 +3464,10 @@ static int rtnl_fill_statsinfo(struct sk_buff *skb, struct net_device *dev, | |||
3469 | 3464 | ||
3470 | if (filter_mask & IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_64)) { | 3465 | if (filter_mask & IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_64)) { |
3471 | struct rtnl_link_stats64 *sp; | 3466 | struct rtnl_link_stats64 *sp; |
3472 | int err; | ||
3473 | |||
3474 | /* if necessary, add a zero length NOP attribute so that | ||
3475 | * IFLA_STATS_LINK_64 will be 64-bit aligned | ||
3476 | */ | ||
3477 | err = nla_align_64bit(skb, IFLA_STATS_UNSPEC); | ||
3478 | if (err) | ||
3479 | goto nla_put_failure; | ||
3480 | 3467 | ||
3481 | attr = nla_reserve(skb, IFLA_STATS_LINK_64, | 3468 | attr = nla_reserve_64bit(skb, IFLA_STATS_LINK_64, |
3482 | sizeof(struct rtnl_link_stats64)); | 3469 | sizeof(struct rtnl_link_stats64), |
3470 | IFLA_STATS_UNSPEC); | ||
3483 | if (!attr) | 3471 | if (!attr) |
3484 | goto nla_put_failure; | 3472 | goto nla_put_failure; |
3485 | 3473 | ||
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 395e2814a46d..21a38e296fe2 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c | |||
@@ -2104,7 +2104,7 @@ static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb, | |||
2104 | mfcs.mfcs_packets = c->mfc_un.res.pkt; | 2104 | mfcs.mfcs_packets = c->mfc_un.res.pkt; |
2105 | mfcs.mfcs_bytes = c->mfc_un.res.bytes; | 2105 | mfcs.mfcs_bytes = c->mfc_un.res.bytes; |
2106 | mfcs.mfcs_wrong_if = c->mfc_un.res.wrong_if; | 2106 | mfcs.mfcs_wrong_if = c->mfc_un.res.wrong_if; |
2107 | if (nla_put(skb, RTA_MFC_STATS, sizeof(mfcs), &mfcs) < 0) | 2107 | if (nla_put_64bit(skb, RTA_MFC_STATS, sizeof(mfcs), &mfcs, RTA_PAD) < 0) |
2108 | return -EMSGSIZE; | 2108 | return -EMSGSIZE; |
2109 | 2109 | ||
2110 | rtm->rtm_type = RTN_MULTICAST; | 2110 | rtm->rtm_type = RTN_MULTICAST; |
@@ -2237,7 +2237,7 @@ static size_t mroute_msgsize(bool unresolved, int maxvif) | |||
2237 | + nla_total_size(0) /* RTA_MULTIPATH */ | 2237 | + nla_total_size(0) /* RTA_MULTIPATH */ |
2238 | + maxvif * NLA_ALIGN(sizeof(struct rtnexthop)) | 2238 | + maxvif * NLA_ALIGN(sizeof(struct rtnexthop)) |
2239 | /* RTA_MFC_STATS */ | 2239 | /* RTA_MFC_STATS */ |
2240 | + nla_total_size(sizeof(struct rta_mfc_stats)) | 2240 | + nla_total_size_64bit(sizeof(struct rta_mfc_stats)) |
2241 | ; | 2241 | ; |
2242 | 2242 | ||
2243 | return len; | 2243 | return len; |
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index a10e77103c88..bf678324fd52 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
@@ -2268,7 +2268,7 @@ static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, | |||
2268 | mfcs.mfcs_packets = c->mfc_un.res.pkt; | 2268 | mfcs.mfcs_packets = c->mfc_un.res.pkt; |
2269 | mfcs.mfcs_bytes = c->mfc_un.res.bytes; | 2269 | mfcs.mfcs_bytes = c->mfc_un.res.bytes; |
2270 | mfcs.mfcs_wrong_if = c->mfc_un.res.wrong_if; | 2270 | mfcs.mfcs_wrong_if = c->mfc_un.res.wrong_if; |
2271 | if (nla_put(skb, RTA_MFC_STATS, sizeof(mfcs), &mfcs) < 0) | 2271 | if (nla_put_64bit(skb, RTA_MFC_STATS, sizeof(mfcs), &mfcs, RTA_PAD) < 0) |
2272 | return -EMSGSIZE; | 2272 | return -EMSGSIZE; |
2273 | 2273 | ||
2274 | rtm->rtm_type = RTN_MULTICAST; | 2274 | rtm->rtm_type = RTN_MULTICAST; |
@@ -2411,7 +2411,7 @@ static int mr6_msgsize(bool unresolved, int maxvif) | |||
2411 | + nla_total_size(0) /* RTA_MULTIPATH */ | 2411 | + nla_total_size(0) /* RTA_MULTIPATH */ |
2412 | + maxvif * NLA_ALIGN(sizeof(struct rtnexthop)) | 2412 | + maxvif * NLA_ALIGN(sizeof(struct rtnexthop)) |
2413 | /* RTA_MFC_STATS */ | 2413 | /* RTA_MFC_STATS */ |
2414 | + nla_total_size(sizeof(struct rta_mfc_stats)) | 2414 | + nla_total_size_64bit(sizeof(struct rta_mfc_stats)) |
2415 | ; | 2415 | ; |
2416 | 2416 | ||
2417 | return len; | 2417 | return len; |