TLV Infrastructure for user data

The aim of this infrastructure is provide an easy way to store sequentially user data into nft kernel objects. It provides functions that allow to create a buffer of TLV (Type-Len-Value).

The structures looks like this:

/*
 * TLV structures:
 * nftnl_udata
 *  <-------- HEADER --------> <------ PAYLOAD ------>
 * +------------+-------------+- - - - - - - - - - - -+
 * |    type    |     len     |         value         |
 * |  (1 byte)  |   (1 byte)  |                       |
 * +--------------------------+- - - - - - - - - - - -+
 *  <-- sizeof(nftnl_udata) -> <-- nftnl_udata->len -->
 */
struct nftnl_udata {
        uint8_t         type;
        uint8_t         len;
        unsigned char   value[];
} __attribute__((__packed__));

/*
 *              +---------------------------------++
 *              | data[]                          ||
 *              |   ||                            ||
 *              |   \/                            \/
 *  +-------+-------+-------+-------+ ... +-------+- - - - - - -+
 *  | size  |  end  |  TLV  |  TLV  |     |  TLV  |    Empty    |
 *  +-------+-------+-------+-------+ ... +-------+- - - - - - -+
 *                  |<---- nftnl_udata_len() ---->|
 *                  |<----------- nftnl_udata_size() ---------->|
 */
struct nftnl_udata_buf {
        uint32_t        size;
        char            *end;
        char            data[];
};

And here is and example of use:

struct nftnl_udata_buf *buf;
struct nftnl_udata *attr;
const char *str = "Hello World!";

buf = nftnl_udata_buf_alloc(UDATA_SIZE);
if (!buf) {
        perror("OOM");
        exit(EXIT_FAILURE);
}

if (!nftnl_udata_put_strz(buf, MY_TYPE, str)) {
        perror("Can't put attribute \"%s\"", str);
        exit(EXIT_FAILURE);
}

nftnl_udata_for_each(buf, attr)
        printf("%s\n", (char *)nftnl_udata_attr_value(attr));

nftnl_udata_buf_free(buf);

Commits

nftables

libnftnl

kernel