/** * Append new 32-bit key to the selector * * @arg cls classifier to be modifier * @arg val value to be matched (network byte-order) * @arg mask mask to be applied before matching (network byte-order) * @arg off offset, in bytes, to start matching * @arg offmask offset mask * * General selectors define the pattern, mask and offset the pattern will be * matched to the packet contents. Using the general selectors you can match * virtually any single bit in the IP (or upper layer) header. * */ int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask, int off, int offmask) { struct tc_u32_sel *sel; struct rtnl_u32 *u; int err; if (!(u = rtnl_tc_data(TC_CAST(cls)))) return -NLE_NOMEM; sel = u32_selector_alloc(u); if (!sel) return -NLE_NOMEM; if (sel->nkeys == UCHAR_MAX) return -NLE_NOMEM; err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key)); if (err < 0) return err; /* the selector might have been moved by realloc */ sel = u32_selector(u); sel->keys[sel->nkeys].mask = mask; sel->keys[sel->nkeys].val = val & mask; sel->keys[sel->nkeys].off = off; sel->keys[sel->nkeys].offmask = offmask; sel->nkeys++; u->cu_mask |= U32_ATTR_SELECTOR; return 0; }
static inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u) { if (!u->cu_selector) u->cu_selector = nl_data_alloc(NULL, sizeof(struct tc_u32_sel)); return u32_selector(u); }
int rtnl_u32_set_hashmask(struct rtnl_cls *cls, uint32_t hashmask, uint32_t offset) { struct rtnl_u32 *u; struct tc_u32_sel *sel; int err; hashmask = htonl(hashmask); if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls)))) return -NLE_NOMEM; sel = u32_selector_alloc(u); if (!sel) return -NLE_NOMEM; err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key)); if(err < 0) return err; sel = u32_selector(u); sel->hmask = hashmask; sel->hoff = offset; return 0; }
/** * Get the 32-bit key from the selector * * @arg cls classifier to be retrieve * @arg index the index of the array of keys, start with 0 * @arg val pointer to store value after masked (network byte-order) * @arg mask pointer to store the mask (network byte-order) * @arg off pointer to store the offset * @arg offmask pointer to store offset mask * */ int rtnl_u32_get_key(struct rtnl_cls *cls, uint8_t index, uint32_t *val, uint32_t *mask, int *off, int *offmask) { struct tc_u32_sel *sel; struct rtnl_u32 *u; if (!(u = rtnl_tc_data(TC_CAST(cls)))) return -NLE_NOMEM; if (!(u->cu_mask & U32_ATTR_SELECTOR)) return -NLE_INVAL; sel = u32_selector(u); if (index >= sel->nkeys) return -NLE_RANGE; *mask = sel->keys[index].mask; *val = sel->keys[index].val; *off = sel->keys[index].off; *offmask = sel->keys[index].offmask; return 0; }
int rtnl_u32_set_cls_terminal(struct rtnl_cls *cls) { struct rtnl_u32 *u; struct tc_u32_sel *sel; int err; if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls)))) return -NLE_NOMEM; sel = u32_selector_alloc(u); if (!sel) return -NLE_NOMEM; err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key)); if(err < 0) return err; sel = u32_selector(u); sel->flags |= TC_U32_TERMINAL; return 0; }