# `Linx.Netlink.Attr`
[🔗](https://github.com/oshlabs/linx/blob/v0.2.0/lib/linx/netlink/attr.ex#L1)

Encoding and decoding of netlink attributes — the type-length-value (TLV)
elements that carry a message's variable-length data.

This is a generic codec: it knows the TLV wire format (`struct rtattr` —
`include/uapi/linux/rtnetlink.h`) but nothing about what any attribute
*means*. An attribute is a `{type, value}` pair — a 16-bit integer type and
a raw binary payload — and a list of them is what this module encodes and
decodes. Interpreting a type, or a value's shape, belongs to the per-message
codec above this layer.

The TLV pair is deliberately a tuple, not a struct: it is a wire primitive,
not domain data. The named-field structs (`Linx.Netlink.Message`, and the
per-resource structs above it) model the domain.

Nested attributes — an attribute whose payload is itself a list of
attributes — need no special support: `encode/1` the inner list and pass the
result as the outer attribute's value; on decode, `decode/1` the value of an
attribute already known to be nested.

One attribute on the wire:

    0      2      4
    +------+------+------ ... ------+- ... -+
    | len  | type |     payload     |  pad  |
    +------+------+------ ... ------+- ... -+

`len` (native byte order, as everywhere in netlink) covers the 4-byte header
and the payload but not the padding; each attribute is zero-padded to the
next 4-byte boundary.

# `attr`

```elixir
@type attr() :: {type :: 0..65535, value :: binary()}
```

# `decode`

```elixir
@spec decode(binary()) :: [attr()]
```

Decodes a binary into its list of `{type, value}` attributes, in order.

`value` is the raw payload, with the header and padding stripped. A trailing
run too short to be an attribute header is treated as alignment padding and
ignored. Raises `ArgumentError` if an attribute's declared length is
inconsistent with the data.

# `encode`

```elixir
@spec encode([{0..65535, iodata()}]) :: binary()
```

Encodes a list of `{type, value}` attributes into a binary.

`value` is any iodata; for a nested attribute, pass `encode/1` of the inner
list. Attributes appear in the result in list order.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
