aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2016-04-21 14:22:14 -0400
committerDavid S. Miller <davem@davemloft.net>2016-04-21 14:22:14 -0400
commitc57107c7f59fe438f8c5bb0ce50af857505276b8 (patch)
tree515f5e73913a81246590ea7cb1b7a08f5c349eda
parent732912d727cd6deb3c1a05a8baa74b8ce8d510ac (diff)
parent3d6b66c1d1a8d348928996ca333730f258fbb838 (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.h39
-rw-r--r--include/uapi/linux/rtnetlink.h1
-rw-r--r--lib/nlattr.c99
-rw-r--r--net/core/rtnetlink.c22
-rw-r--r--net/ipv4/ipmr.c4
-rw-r--r--net/ipv6/ip6mr.c4
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);
244int nla_memcmp(const struct nlattr *nla, const void *data, size_t size); 244int nla_memcmp(const struct nlattr *nla, const void *data, size_t size);
245int nla_strcmp(const struct nlattr *nla, const char *str); 245int nla_strcmp(const struct nlattr *nla, const char *str);
246struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen); 246struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen);
247struct nlattr *__nla_reserve_64bit(struct sk_buff *skb, int attrtype,
248 int attrlen, int padattr);
247void *__nla_reserve_nohdr(struct sk_buff *skb, int attrlen); 249void *__nla_reserve_nohdr(struct sk_buff *skb, int attrlen);
248struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen); 250struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen);
251struct nlattr *nla_reserve_64bit(struct sk_buff *skb, int attrtype,
252 int attrlen, int padattr);
249void *nla_reserve_nohdr(struct sk_buff *skb, int attrlen); 253void *nla_reserve_nohdr(struct sk_buff *skb, int attrlen);
250void __nla_put(struct sk_buff *skb, int attrtype, int attrlen, 254void __nla_put(struct sk_buff *skb, int attrtype, int attrlen,
251 const void *data); 255 const void *data);
256void __nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen,
257 const void *data, int padattr);
252void __nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data); 258void __nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data);
253int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data); 259int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data);
260int nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen,
261 const void *data, int padattr);
254int nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data); 262int nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data);
255int nla_append(struct sk_buff *skb, int attrlen, const void *data); 263int 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 */
1248static 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 */
1245static inline int nla_align_64bit(struct sk_buff *skb, int padattr) 1274static 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)
355EXPORT_SYMBOL(__nla_reserve); 355EXPORT_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 */
370struct 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}
378EXPORT_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)
397EXPORT_SYMBOL(nla_reserve); 420EXPORT_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 */
435struct 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}
449EXPORT_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,
436EXPORT_SYMBOL(__nla_put); 488EXPORT_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 */
500void __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}
508EXPORT_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)
474EXPORT_SYMBOL(nla_put); 546EXPORT_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 */
558int 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}
573EXPORT_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;