/* Some bitmaps are internally represented as an array of unsigned long, some * as an array of u32 (some even as single u32 for now). To avoid the need of * wrappers on caller side, we provide two set of functions: those with "32" * suffix in their names expect u32 based bitmaps, those without it expect * unsigned long bitmaps.
*/
/** * ethnl_bitmap32_clear() - Clear u32 based bitmap * @dst: bitmap to clear * @start: beginning of the interval * @end: end of the interval * @mod: set if bitmap was modified * * Clear @nbits bits of a bitmap with indices @start <= i < @end
*/ staticvoid ethnl_bitmap32_clear(u32 *dst, unsignedint start, unsignedint end, bool *mod)
{ unsignedint start_word = start / 32; unsignedint end_word = end / 32; unsignedint i;
u32 mask;
for (i = start_word; i < end_word; i++) { if (dst[i]) {
dst[i] = 0;
*mod = true;
}
} if (end % 32) {
mask = ethnl_lower_bits(end); if (dst[end_word] & mask) {
dst[end_word] &= ~mask;
*mod = true;
}
}
}
/** * ethnl_bitmap32_not_zero() - Check if any bit is set in an interval * @map: bitmap to test * @start: beginning of the interval * @end: end of the interval * * Return: true if there is non-zero bit with index @start <= i < @end, * false if the whole interval is zero
*/ staticbool ethnl_bitmap32_not_zero(const u32 *map, unsignedint start, unsignedint end)
{ unsignedint start_word = start / 32; unsignedint end_word = end / 32;
u32 mask;
if (end <= start) returntrue;
if (start % 32) {
mask = ethnl_upper_bits(start); if (end_word == start_word) {
mask &= ethnl_lower_bits(end); return map[start_word] & mask;
} if (map[start_word] & mask) returntrue;
start_word++;
}
/** * ethnl_bitmap32_update() - Modify u32 based bitmap according to value/mask * pair * @dst: bitmap to update * @nbits: bit size of the bitmap * @value: values to set * @mask: mask of bits to set * @mod: set to true if bitmap is modified, preserve if not * * Set bits in @dst bitmap which are set in @mask to values from @value, leave * the rest untouched. If destination bitmap was modified, set @mod to true, * leave as it is if not.
*/ staticvoid ethnl_bitmap32_update(u32 *dst, unsignedint nbits, const u32 *value, const u32 *mask, bool *mod)
{ while (nbits > 0) {
u32 real_mask = mask ? *mask : ~(u32)0;
u32 new_value;
/** * ethnl_bitset32_size() - Calculate size of bitset nested attribute * @val: value bitmap (u32 based) * @mask: mask bitmap (u32 based, optional) * @nbits: bit length of the bitset * @names: array of bit names (optional) * @compact: assume compact format for output * * Estimate length of netlink attribute composed by a later call to * ethnl_put_bitset32() call with the same arguments. * * Return: negative error code or attribute length estimate
*/ int ethnl_bitset32_size(const u32 *val, const u32 *mask, unsignedint nbits,
ethnl_string_array_t names, bool compact)
{ unsignedint len = 0;
/* list flag */ if (!mask)
len += nla_total_size(sizeof(u32)); /* size */
len += nla_total_size(sizeof(u32));
if (compact) { unsignedint nwords = DIV_ROUND_UP(nbits, 32);
/** * ethnl_put_bitset32() - Put a bitset nest into a message * @skb: skb with the message * @attrtype: attribute type for the bitset nest * @val: value bitmap (u32 based) * @mask: mask bitmap (u32 based, optional) * @nbits: bit length of the bitset * @names: array of bit names (optional) * @compact: use compact format for the output * * Compose a nested attribute representing a bitset. If @mask is null, simple * bitmap (bit list) is created, if @mask is provided, represent a value/mask * pair. Bit names are only used in verbose mode and when provided by calller. * * Return: 0 on success, negative error value on error
*/ int ethnl_put_bitset32(struct sk_buff *skb, int attrtype, const u32 *val, const u32 *mask, unsignedint nbits,
ethnl_string_array_t names, bool compact)
{ struct nlattr *nest; struct nlattr *attr;
nest = nla_nest_start(skb, attrtype); if (!nest) return -EMSGSIZE;
if (!mask && nla_put_flag(skb, ETHTOOL_A_BITSET_NOMASK)) goto nla_put_failure; if (nla_put_u32(skb, ETHTOOL_A_BITSET_SIZE, nbits)) goto nla_put_failure; if (compact) { unsignedint nwords = DIV_ROUND_UP(nbits, 32); unsignedint nbytes = nwords * sizeof(u32);
u32 *dst;
/** * ethnl_bitset_is_compact() - check if bitset attribute represents a compact * bitset * @bitset: nested attribute representing a bitset * @compact: pointer for return value * * Return: 0 on success, negative error code on failure
*/ int ethnl_bitset_is_compact(conststruct nlattr *bitset, bool *compact)
{ struct nlattr *tb[ARRAY_SIZE(bitset_policy)]; int ret;
ret = nla_parse_nested(tb, ARRAY_SIZE(bitset_policy) - 1, bitset,
bitset_policy, NULL); if (ret < 0) return ret;
if (tb[ETHTOOL_A_BITSET_BITS]) { if (tb[ETHTOOL_A_BITSET_VALUE] || tb[ETHTOOL_A_BITSET_MASK]) return -EINVAL;
*compact = false; return 0;
} if (!tb[ETHTOOL_A_BITSET_SIZE] || !tb[ETHTOOL_A_BITSET_VALUE]) return -EINVAL;
*compact = true; return 0;
}
/** * ethnl_name_to_idx() - look up string index for a name * @names: array of ETH_GSTRING_LEN sized strings * @n_names: number of strings in the array * @name: name to look up * * Return: index of the string if found, -ENOENT if not found
*/ staticint ethnl_name_to_idx(ethnl_string_array_t names, unsignedint n_names, constchar *name)
{ unsignedint i;
if (!names) return -ENOENT;
for (i = 0; i < n_names; i++) { /* names[i] may not be null terminated */ if (!strncmp(names[i], name, ETH_GSTRING_LEN) &&
strlen(name) <= ETH_GSTRING_LEN) return i;
}
ret = nla_parse_nested(tb, ARRAY_SIZE(bit_policy) - 1, bit_attr,
bit_policy, extack); if (ret < 0) return ret;
if (tb[ETHTOOL_A_BITSET_BIT_INDEX]) { constchar *name;
idx = nla_get_u32(tb[ETHTOOL_A_BITSET_BIT_INDEX]); if (idx >= nbits) {
NL_SET_ERR_MSG_ATTR(extack,
tb[ETHTOOL_A_BITSET_BIT_INDEX], "bit index too high"); return -EOPNOTSUPP;
}
name = names ? names[idx] : NULL; if (tb[ETHTOOL_A_BITSET_BIT_NAME] && name &&
strncmp(nla_data(tb[ETHTOOL_A_BITSET_BIT_NAME]), name,
nla_len(tb[ETHTOOL_A_BITSET_BIT_NAME]))) {
NL_SET_ERR_MSG_ATTR(extack, bit_attr, "bit index and name mismatch"); return -EINVAL;
}
} elseif (tb[ETHTOOL_A_BITSET_BIT_NAME]) {
idx = ethnl_name_to_idx(names, nbits,
nla_data(tb[ETHTOOL_A_BITSET_BIT_NAME])); if (idx < 0) {
NL_SET_ERR_MSG_ATTR(extack,
tb[ETHTOOL_A_BITSET_BIT_NAME], "bit name not found"); return -EOPNOTSUPP;
}
} else {
NL_SET_ERR_MSG_ATTR(extack, bit_attr, "neither bit index nor name specified"); return -EINVAL;
}
if (tb[ETHTOOL_A_BITSET_VALUE]) {
NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_VALUE], "value only allowed in compact bitset"); return -EINVAL;
} if (tb[ETHTOOL_A_BITSET_MASK]) {
NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_MASK], "mask only allowed in compact bitset"); return -EINVAL;
}
/* The bitmap size is only the size of the map part without * its mask part.
*/
saved_bitmap = kcalloc(nwords, sizeof(u32), GFP_KERNEL); if (!saved_bitmap) return -ENOMEM;
memcpy(saved_bitmap, bitmap, nbytes);
ethnl_bitmap32_clear(bitmap, 0, nbits, &dummy);
}
/** * ethnl_update_bitset32() - Apply a bitset nest to a u32 based bitmap * @bitmap: bitmap to update * @nbits: size of the updated bitmap in bits * @attr: nest attribute to parse and apply * @names: array of bit names; may be null for compact format * @extack: extack for error reporting * @mod: set this to true if bitmap is modified, leave as it is if not * * Apply bitset netsted attribute to a bitmap. If the attribute represents * a bit list, @bitmap is set to its contents; otherwise, bits in mask are * set to values from value. Bitmaps in the attribute may be longer than * @nbits but the message must not request modifying any bits past @nbits. * * Return: negative error code on failure, 0 on success
*/ int ethnl_update_bitset32(u32 *bitmap, unsignedint nbits, conststruct nlattr *attr, ethnl_string_array_t names, struct netlink_ext_ack *extack, bool *mod)
{ struct nlattr *tb[ARRAY_SIZE(bitset_policy)]; unsignedint change_bits; bool no_mask; int ret;
if (!attr) return 0;
ret = nla_parse_nested(tb, ARRAY_SIZE(bitset_policy) - 1, attr,
bitset_policy, extack); if (ret < 0) return ret;
if (tb[ETHTOOL_A_BITSET_BITS]) return ethnl_update_bitset32_verbose(bitmap, nbits, attr, tb,
names, extack, mod);
ret = ethnl_compact_sanity_checks(nbits, attr, tb, extack); if (ret < 0) return ret;
/** * ethnl_parse_bitset() - Compute effective value and mask from bitset nest * @val: unsigned long based bitmap to put value into * @mask: unsigned long based bitmap to put mask into * @nbits: size of @val and @mask bitmaps * @attr: nest attribute to parse and apply * @names: array of bit names; may be null for compact format * @extack: extack for error reporting * * Provide @nbits size long bitmaps for value and mask so that * x = (val & mask) | (x & ~mask) would modify any @nbits sized bitmap x * the same way ethnl_update_bitset() with the same bitset attribute would. * * Return: negative error code on failure, 0 on success
*/ int ethnl_parse_bitset(unsignedlong *val, unsignedlong *mask, unsignedint nbits, conststruct nlattr *attr,
ethnl_string_array_t names, struct netlink_ext_ack *extack)
{ struct nlattr *tb[ARRAY_SIZE(bitset_policy)]; conststruct nlattr *bit_attr; bool no_mask; int rem; int ret;
if (!attr) return 0;
ret = nla_parse_nested(tb, ARRAY_SIZE(bitset_policy) - 1, attr,
bitset_policy, extack); if (ret < 0) return ret;
no_mask = tb[ETHTOOL_A_BITSET_NOMASK];
if (!tb[ETHTOOL_A_BITSET_BITS]) { unsignedint change_bits;
ret = ethnl_compact_sanity_checks(nbits, attr, tb, extack); if (ret < 0) return ret;
if (tb[ETHTOOL_A_BITSET_VALUE]) {
NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_VALUE], "value only allowed in compact bitset"); return -EINVAL;
} if (tb[ETHTOOL_A_BITSET_MASK]) {
NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_MASK], "mask only allowed in compact bitset"); return -EINVAL;
}
bitmap_zero(val, nbits); if (no_mask)
bitmap_fill(mask, nbits); else
bitmap_zero(mask, nbits);
ret = ethnl_parse_bit(&idx, &bit_val, nbits, bit_attr, no_mask,
names, extack); if (ret < 0) return ret; if (bit_val)
__set_bit(idx, val); if (!no_mask)
__set_bit(idx, mask);
}
return 0;
}
#if BITS_PER_LONG == 64 && defined(__BIG_ENDIAN)
/* 64-bit big endian architectures are the only case when u32 based bitmaps * and unsigned long based bitmaps have different memory layout so that we * cannot simply cast the latter to the former and need actual wrappers * converting the latter to the former. * * To reduce the number of slab allocations, the wrappers use fixed size local * variables for bitmaps up to ETHNL_SMALL_BITMAP_BITS bits which is the * majority of bitmaps used by ethtool.
*/ #define ETHNL_SMALL_BITMAP_BITS 128 #define ETHNL_SMALL_BITMAP_WORDS DIV_ROUND_UP(ETHNL_SMALL_BITMAP_BITS, 32)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.