static int fw_msg_parser(struct rtnl_cls *cls) { struct rtnl_fw *f = rtnl_cls_data(cls); struct nlattr *tb[TCA_FW_MAX + 1]; int err; err = tca_parse(tb, TCA_FW_MAX, (struct rtnl_tca *) cls, fw_policy); if (err < 0) return err; if (tb[TCA_FW_CLASSID]) { f->cf_classid = nla_get_u32(tb[TCA_FW_CLASSID]); f->cf_mask |= FW_ATTR_CLASSID; } if (tb[TCA_FW_ACT]) { f->cf_act = nl_data_alloc_attr(tb[TCA_FW_ACT]); if (!f->cf_act) return -NLE_NOMEM; f->cf_mask |= FW_ATTR_ACTION; } if (tb[TCA_FW_POLICE]) { f->cf_police = nl_data_alloc_attr(tb[TCA_FW_POLICE]); if (!f->cf_police) return -NLE_NOMEM; f->cf_mask |= FW_ATTR_POLICE; } if (tb[TCA_FW_INDEV]) { nla_strlcpy(f->cf_indev, tb[TCA_FW_INDEV], IFNAMSIZ); f->cf_mask |= FW_ATTR_INDEV; } return 0; }
int tca_msg_parser(struct nlmsghdr *n, struct rtnl_tc *g) { struct nlattr *tb[TCA_MAX + 1]; struct tcmsg *tm; int err; err = nlmsg_parse(n, sizeof(*tm), tb, TCA_MAX, tc_policy); if (err < 0) return err; if (tb[TCA_KIND] == NULL) return -NLE_MISSING_ATTR; nla_strlcpy(g->tc_kind, tb[TCA_KIND], TCKINDSIZ); tm = nlmsg_data(n); g->tc_family = tm->tcm_family; g->tc_ifindex = tm->tcm_ifindex; g->tc_handle = tm->tcm_handle; g->tc_parent = tm->tcm_parent; g->tc_info = tm->tcm_info; g->ce_mask = (TCA_ATTR_FAMILY | TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE | TCA_ATTR_PARENT | TCA_ATTR_INFO | TCA_ATTR_KIND); if (tb[TCA_OPTIONS]) { g->tc_opts = nl_data_alloc_attr(tb[TCA_OPTIONS]); if (!g->tc_opts) return -NLE_NOMEM; g->ce_mask |= TCA_ATTR_OPTS; } if (tb[TCA_STATS2]) { struct nlattr *tbs[TCA_STATS_MAX + 1]; err = nla_parse_nested(tbs, TCA_STATS_MAX, tb[TCA_STATS2], tc_stats2_policy); if (err < 0) return err; if (tbs[TCA_STATS_BASIC]) { struct gnet_stats_basic *bs; bs = nla_data(tbs[TCA_STATS_BASIC]); g->tc_stats[RTNL_TC_BYTES] = bs->bytes; g->tc_stats[RTNL_TC_PACKETS] = bs->packets; } if (tbs[TCA_STATS_RATE_EST]) { struct gnet_stats_rate_est *re; re = nla_data(tbs[TCA_STATS_RATE_EST]); g->tc_stats[RTNL_TC_RATE_BPS] = re->bps; g->tc_stats[RTNL_TC_RATE_PPS] = re->pps; } if (tbs[TCA_STATS_QUEUE]) { struct gnet_stats_queue *q; q = nla_data(tbs[TCA_STATS_QUEUE]); g->tc_stats[RTNL_TC_QLEN] = q->qlen; g->tc_stats[RTNL_TC_BACKLOG] = q->backlog; g->tc_stats[RTNL_TC_DROPS] = q->drops; g->tc_stats[RTNL_TC_REQUEUES] = q->requeues; g->tc_stats[RTNL_TC_OVERLIMITS] = q->overlimits; } g->ce_mask |= TCA_ATTR_STATS; if (tbs[TCA_STATS_APP]) { g->tc_xstats = nl_data_alloc_attr(tbs[TCA_STATS_APP]); if (g->tc_xstats == NULL) return -NLE_NOMEM; } else goto compat_xstats; } else { if (tb[TCA_STATS]) { struct tc_stats *st = nla_data(tb[TCA_STATS]); g->tc_stats[RTNL_TC_BYTES] = st->bytes; g->tc_stats[RTNL_TC_PACKETS] = st->packets; g->tc_stats[RTNL_TC_RATE_BPS] = st->bps; g->tc_stats[RTNL_TC_RATE_PPS] = st->pps; g->tc_stats[RTNL_TC_QLEN] = st->qlen; g->tc_stats[RTNL_TC_BACKLOG] = st->backlog; g->tc_stats[RTNL_TC_DROPS] = st->drops; g->tc_stats[RTNL_TC_OVERLIMITS] = st->overlimits; g->ce_mask |= TCA_ATTR_STATS; } compat_xstats: if (tb[TCA_XSTATS]) { g->tc_xstats = nl_data_alloc_attr(tb[TCA_XSTATS]); if (g->tc_xstats == NULL) return -NLE_NOMEM; g->ce_mask |= TCA_ATTR_XSTATS; } } return 0; }
int rtnl_tc_msg_parse(struct nlmsghdr *n, struct rtnl_tc *tc) { struct nl_cache *link_cache; struct rtnl_tc_ops *ops; struct nlattr *tb[TCA_MAX + 1]; char kind[TCKINDSIZ]; struct tcmsg *tm; int err; tc->ce_msgtype = n->nlmsg_type; err = nlmsg_parse(n, sizeof(*tm), tb, TCA_MAX, tc_policy); if (err < 0) return err; if (tb[TCA_KIND] == NULL) return -NLE_MISSING_ATTR; nla_strlcpy(kind, tb[TCA_KIND], sizeof(kind)); rtnl_tc_set_kind(tc, kind); tm = nlmsg_data(n); tc->tc_family = tm->tcm_family; tc->tc_ifindex = tm->tcm_ifindex; tc->tc_handle = tm->tcm_handle; tc->tc_parent = tm->tcm_parent; tc->tc_info = tm->tcm_info; tc->ce_mask |= (TCA_ATTR_FAMILY | TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE| TCA_ATTR_PARENT | TCA_ATTR_INFO); if (tb[TCA_OPTIONS]) { tc->tc_opts = nl_data_alloc_attr(tb[TCA_OPTIONS]); if (!tc->tc_opts) return -NLE_NOMEM; tc->ce_mask |= TCA_ATTR_OPTS; } if (tb[TCA_STATS2]) { struct nlattr *tbs[TCA_STATS_MAX + 1]; err = nla_parse_nested(tbs, TCA_STATS_MAX, tb[TCA_STATS2], tc_stats2_policy); if (err < 0) return err; if (tbs[TCA_STATS_BASIC]) { struct gnet_stats_basic *bs; bs = nla_data(tbs[TCA_STATS_BASIC]); tc->tc_stats[RTNL_TC_BYTES] = bs->bytes; tc->tc_stats[RTNL_TC_PACKETS] = bs->packets; } if (tbs[TCA_STATS_RATE_EST]) { struct gnet_stats_rate_est *re; re = nla_data(tbs[TCA_STATS_RATE_EST]); tc->tc_stats[RTNL_TC_RATE_BPS] = re->bps; tc->tc_stats[RTNL_TC_RATE_PPS] = re->pps; } if (tbs[TCA_STATS_QUEUE]) { struct gnet_stats_queue *q; q = nla_data(tbs[TCA_STATS_QUEUE]); tc->tc_stats[RTNL_TC_QLEN] = q->qlen; tc->tc_stats[RTNL_TC_BACKLOG] = q->backlog; tc->tc_stats[RTNL_TC_DROPS] = q->drops; tc->tc_stats[RTNL_TC_REQUEUES] = q->requeues; tc->tc_stats[RTNL_TC_OVERLIMITS] = q->overlimits; } tc->ce_mask |= TCA_ATTR_STATS; if (tbs[TCA_STATS_APP]) { tc->tc_xstats = nl_data_alloc_attr(tbs[TCA_STATS_APP]); if (tc->tc_xstats == NULL) return -NLE_NOMEM; tc->ce_mask |= TCA_ATTR_XSTATS; } else goto compat_xstats; } else { if (tb[TCA_STATS]) { struct tc_stats *st = nla_data(tb[TCA_STATS]); tc->tc_stats[RTNL_TC_BYTES] = st->bytes; tc->tc_stats[RTNL_TC_PACKETS] = st->packets; tc->tc_stats[RTNL_TC_RATE_BPS] = st->bps; tc->tc_stats[RTNL_TC_RATE_PPS] = st->pps; tc->tc_stats[RTNL_TC_QLEN] = st->qlen; tc->tc_stats[RTNL_TC_BACKLOG] = st->backlog; tc->tc_stats[RTNL_TC_DROPS] = st->drops; tc->tc_stats[RTNL_TC_OVERLIMITS]= st->overlimits; tc->ce_mask |= TCA_ATTR_STATS; } compat_xstats: if (tb[TCA_XSTATS]) { tc->tc_xstats = nl_data_alloc_attr(tb[TCA_XSTATS]); if (tc->tc_xstats == NULL) return -NLE_NOMEM; tc->ce_mask |= TCA_ATTR_XSTATS; } } ops = rtnl_tc_get_ops(tc); if (ops && ops->to_msg_parser) { void *data = rtnl_tc_data(tc); if (!data) return -NLE_NOMEM; err = ops->to_msg_parser(tc, data); if (err < 0) return err; } if ((link_cache = __nl_cache_mngt_require("route/link"))) { struct rtnl_link *link; if ((link = rtnl_link_get(link_cache, tc->tc_ifindex))) { rtnl_tc_set_link(tc, link); /* rtnl_tc_set_link incs refcnt */ rtnl_link_put(link); } } return 0; }
static int u32_msg_parser(struct rtnl_tc *tc, void *data) { struct rtnl_u32 *u = data; struct nlattr *tb[TCA_U32_MAX + 1]; int err; err = tca_parse(tb, TCA_U32_MAX, tc, u32_policy); if (err < 0) return err; if (tb[TCA_U32_DIVISOR]) { u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]); u->cu_mask |= U32_ATTR_DIVISOR; } if (tb[TCA_U32_SEL]) { u->cu_selector = nl_data_alloc_attr(tb[TCA_U32_SEL]); if (!u->cu_selector) goto errout_nomem; u->cu_mask |= U32_ATTR_SELECTOR; } if (tb[TCA_U32_MARK]) { u->cu_mark = nl_data_alloc_attr(tb[TCA_U32_MARK]); if (!u->cu_mark) goto errout_nomem; u->cu_mask |= U32_ATTR_MARK; } if (tb[TCA_U32_HASH]) { u->cu_hash = nla_get_u32(tb[TCA_U32_HASH]); u->cu_mask |= U32_ATTR_HASH; } if (tb[TCA_U32_CLASSID]) { u->cu_classid = nla_get_u32(tb[TCA_U32_CLASSID]); u->cu_mask |= U32_ATTR_CLASSID; } if (tb[TCA_U32_LINK]) { u->cu_link = nla_get_u32(tb[TCA_U32_LINK]); u->cu_mask |= U32_ATTR_LINK; } if (tb[TCA_U32_ACT]) { u->cu_mask |= U32_ATTR_ACTION; err = rtnl_act_parse(&u->cu_act, tb[TCA_U32_ACT]); if (err) return err; } if (tb[TCA_U32_POLICE]) { u->cu_police = nl_data_alloc_attr(tb[TCA_U32_POLICE]); if (!u->cu_police) goto errout_nomem; u->cu_mask |= U32_ATTR_POLICE; } if (tb[TCA_U32_PCNT]) { struct tc_u32_sel *sel; size_t pcnt_size; if (!tb[TCA_U32_SEL]) { err = -NLE_MISSING_ATTR; goto errout; } sel = u->cu_selector->d_data; pcnt_size = sizeof(struct tc_u32_pcnt) + (sel->nkeys * sizeof(uint64_t)); if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) { err = -NLE_INVAL; goto errout; } u->cu_pcnt = nl_data_alloc_attr(tb[TCA_U32_PCNT]); if (!u->cu_pcnt) goto errout_nomem; u->cu_mask |= U32_ATTR_PCNT; } if (tb[TCA_U32_INDEV]) { nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ); u->cu_mask |= U32_ATTR_INDEV; } return 0; errout_nomem: err = -NLE_NOMEM; errout: return err; }