18 #include <netlink-private/netlink.h>
19 #include <netlink-private/tc.h>
20 #include <netlink/netlink.h>
21 #include <netlink/utils.h>
22 #include <netlink/route/link.h>
23 #include <netlink-private/route/tc-api.h>
24 #include <netlink/route/qdisc.h>
25 #include <netlink/route/class.h>
26 #include <netlink/route/classifier.h>
28 static struct nl_cache_ops rtnl_qdisc_ops;
29 static struct nl_object_ops qdisc_obj_ops;
31 static int qdisc_msg_parser(
struct nl_cache_ops *ops,
struct sockaddr_nl *who,
32 struct nlmsghdr *n,
struct nl_parser_param *pp)
34 struct rtnl_qdisc *qdisc;
37 if (!(qdisc = rtnl_qdisc_alloc()))
40 if ((err = rtnl_tc_msg_parse(n,
TC_CAST(qdisc))) < 0)
43 err = pp->pp_cb(OBJ_CAST(qdisc), pp);
45 rtnl_qdisc_put(qdisc);
50 static int qdisc_request_update(
struct nl_cache *c,
struct nl_sock *sk)
52 struct tcmsg tchdr = {
53 .tcm_family = AF_UNSPEC,
54 .tcm_ifindex = c->c_iarg1,
66 struct rtnl_qdisc *rtnl_qdisc_alloc(
void)
72 tc->tc_type = RTNL_TC_TYPE_QDISC;
74 return (
struct rtnl_qdisc *) tc;
77 void rtnl_qdisc_put(
struct rtnl_qdisc *qdisc)
89 static int build_qdisc_msg(
struct rtnl_qdisc *qdisc,
int type,
int flags,
90 struct nl_msg **result)
92 if (!(qdisc->ce_mask & TCA_ATTR_IFINDEX)) {
93 APPBUG(
"ifindex must be specified");
94 return -NLE_MISSING_ATTR;
97 return rtnl_tc_msg_build(
TC_CAST(qdisc), type, flags, result);
115 struct nl_msg **result)
117 if (!(qdisc->ce_mask & (TCA_ATTR_HANDLE | TCA_ATTR_PARENT))) {
118 APPBUG(
"handle or parent must be specified");
119 return -NLE_MISSING_ATTR;
122 return build_qdisc_msg(qdisc, RTM_NEWQDISC, flags, result);
189 struct rtnl_qdisc *
new,
int flags,
190 struct nl_msg **result)
192 if (flags & (NLM_F_CREATE | NLM_F_EXCL)) {
193 APPBUG(
"NLM_F_CREATE and NLM_F_EXCL may not be used here, "
194 "use rtnl_qdisc_add()");
198 if (!(qdisc->ce_mask & TCA_ATTR_IFINDEX)) {
199 APPBUG(
"ifindex must be specified");
200 return -NLE_MISSING_ATTR;
203 if (!(qdisc->ce_mask & (TCA_ATTR_HANDLE | TCA_ATTR_PARENT))) {
204 APPBUG(
"handle or parent must be specified");
205 return -NLE_MISSING_ATTR;
210 if (qdisc->ce_mask & TCA_ATTR_HANDLE)
213 if (qdisc->ce_mask & TCA_ATTR_PARENT)
216 return build_qdisc_msg(
new, RTM_NEWQDISC, flags, result);
248 struct rtnl_qdisc *
new,
int flags)
274 struct nl_msg **result)
278 uint32_t required = TCA_ATTR_IFINDEX | TCA_ATTR_PARENT;
280 if ((qdisc->ce_mask & required) != required) {
281 APPBUG(
"ifindex and parent must be specified");
282 return -NLE_MISSING_ATTR;
288 memset(&tchdr, 0,
sizeof(tchdr));
290 tchdr.tcm_family = AF_UNSPEC;
291 tchdr.tcm_ifindex = qdisc->q_ifindex;
292 tchdr.tcm_parent = qdisc->q_parent;
294 if (qdisc->ce_mask & TCA_ATTR_HANDLE)
295 tchdr.tcm_handle = qdisc->q_handle;
297 if (
nlmsg_append(msg, &tchdr,
sizeof(tchdr), NLMSG_ALIGNTO) < 0)
298 goto nla_put_failure;
300 if (qdisc->ce_mask & TCA_ATTR_KIND)
388 int ifindex, uint32_t parent)
390 struct rtnl_qdisc *q;
392 if (cache->c_ops != &rtnl_qdisc_ops)
395 nl_list_for_each_entry(q, &cache->c_items, ce_list) {
396 if (q->q_parent == parent && q->q_ifindex == ifindex) {
422 struct rtnl_qdisc *q;
424 if (cache->c_ops != &rtnl_qdisc_ops)
427 nl_list_for_each_entry(q, &cache->c_items, ce_list) {
428 if (q->q_handle == handle && q->q_ifindex == ifindex) {
451 void (*cb)(
struct nl_object *,
void *),
void *arg)
453 struct rtnl_class *filter;
455 filter = rtnl_class_alloc();
465 rtnl_class_put(filter);
475 void (*cb)(
struct nl_object *,
void *),
void *arg)
477 struct rtnl_cls *filter;
479 if (!(filter = rtnl_cls_alloc()))
486 rtnl_cls_put(filter);
497 struct rtnl_qdisc *
new,
498 struct nl_msg **result)
512 struct rtnl_qdisc *
new)
519 static void qdisc_dump_details(
struct rtnl_tc *tc,
struct nl_dump_params *p)
521 struct rtnl_qdisc *qdisc = (
struct rtnl_qdisc *) tc;
523 nl_dump(p,
"refcnt %u ", qdisc->q_info);
526 static struct rtnl_tc_type_ops qdisc_ops = {
527 .tt_type = RTNL_TC_TYPE_QDISC,
528 .tt_dump_prefix =
"qdisc",
534 static struct nl_cache_ops rtnl_qdisc_ops = {
535 .co_name =
"route/qdisc",
536 .co_hdrsize =
sizeof(
struct tcmsg),
538 { RTM_NEWQDISC, NL_ACT_NEW,
"new" },
539 { RTM_DELQDISC, NL_ACT_DEL,
"del" },
540 { RTM_GETQDISC, NL_ACT_GET,
"get" },
541 END_OF_MSGTYPES_LIST,
543 .co_protocol = NETLINK_ROUTE,
544 .co_request_update = qdisc_request_update,
545 .co_msg_parser = qdisc_msg_parser,
546 .co_obj_ops = &qdisc_obj_ops,
549 static struct nl_object_ops qdisc_obj_ops = {
550 .oo_name =
"route/qdisc",
551 .oo_size =
sizeof(
struct rtnl_qdisc),
552 .oo_free_data = rtnl_tc_free_data,
553 .oo_clone = rtnl_tc_clone,
559 .oo_compare = rtnl_tc_compare,
560 .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
563 static void __init qdisc_init(
void)
565 rtnl_tc_type_register(&qdisc_ops);
569 static void __exit qdisc_exit(
void)
572 rtnl_tc_type_unregister(&qdisc_ops);