12#include <netlink-private/netlink.h>
13#include <netlink-private/tc.h>
14#include <netlink/netlink.h>
15#include <netlink/utils.h>
16#include <netlink/route/link.h>
17#include <netlink-private/route/tc-api.h>
18#include <netlink/route/qdisc.h>
19#include <netlink/route/class.h>
20#include <netlink/route/classifier.h>
22static struct nl_cache_ops rtnl_qdisc_ops;
23static struct nl_object_ops qdisc_obj_ops;
25static int qdisc_msg_parser(
struct nl_cache_ops *ops,
struct sockaddr_nl *who,
26 struct nlmsghdr *n,
struct nl_parser_param *pp)
28 struct rtnl_qdisc *qdisc;
31 if (!(qdisc = rtnl_qdisc_alloc()))
34 if ((err = rtnl_tc_msg_parse(n,
TC_CAST(qdisc))) < 0)
37 err = pp->pp_cb(OBJ_CAST(qdisc), pp);
39 rtnl_qdisc_put(qdisc);
44static int qdisc_request_update(
struct nl_cache *c,
struct nl_sock *sk)
46 struct tcmsg tchdr = {
47 .tcm_family = AF_UNSPEC,
48 .tcm_ifindex = c->c_iarg1,
60struct rtnl_qdisc *rtnl_qdisc_alloc(
void)
66 tc->tc_type = RTNL_TC_TYPE_QDISC;
68 return (
struct rtnl_qdisc *) tc;
71void rtnl_qdisc_put(
struct rtnl_qdisc *qdisc)
83static int build_qdisc_msg(
struct rtnl_qdisc *qdisc,
int type,
int flags,
84 struct nl_msg **result)
86 if (!(qdisc->ce_mask & TCA_ATTR_IFINDEX)) {
87 APPBUG(
"ifindex must be specified");
88 return -NLE_MISSING_ATTR;
91 return rtnl_tc_msg_build(
TC_CAST(qdisc), type, flags, result);
109 struct nl_msg **result)
111 if (!(qdisc->ce_mask & (TCA_ATTR_HANDLE | TCA_ATTR_PARENT))) {
112 APPBUG(
"handle or parent must be specified");
113 return -NLE_MISSING_ATTR;
116 return build_qdisc_msg(qdisc, RTM_NEWQDISC, flags, result);
183 struct rtnl_qdisc *
new,
int flags,
184 struct nl_msg **result)
186 if (flags & (NLM_F_CREATE | NLM_F_EXCL)) {
187 APPBUG(
"NLM_F_CREATE and NLM_F_EXCL may not be used here, "
188 "use rtnl_qdisc_add()");
192 if (!(qdisc->ce_mask & TCA_ATTR_IFINDEX)) {
193 APPBUG(
"ifindex must be specified");
194 return -NLE_MISSING_ATTR;
197 if (!(qdisc->ce_mask & (TCA_ATTR_HANDLE | TCA_ATTR_PARENT))) {
198 APPBUG(
"handle or parent must be specified");
199 return -NLE_MISSING_ATTR;
204 if (qdisc->ce_mask & TCA_ATTR_HANDLE)
207 if (qdisc->ce_mask & TCA_ATTR_PARENT)
210 return build_qdisc_msg(
new, RTM_NEWQDISC, flags, result);
242 struct rtnl_qdisc *
new,
int flags)
268 struct nl_msg **result)
272 uint32_t required = TCA_ATTR_IFINDEX | TCA_ATTR_PARENT;
274 if ((qdisc->ce_mask & required) != required) {
275 APPBUG(
"ifindex and parent must be specified");
276 return -NLE_MISSING_ATTR;
282 memset(&tchdr, 0,
sizeof(tchdr));
284 tchdr.tcm_family = AF_UNSPEC;
285 tchdr.tcm_ifindex = qdisc->q_ifindex;
286 tchdr.tcm_parent = qdisc->q_parent;
288 if (qdisc->ce_mask & TCA_ATTR_HANDLE)
289 tchdr.tcm_handle = qdisc->q_handle;
291 if (
nlmsg_append(msg, &tchdr,
sizeof(tchdr), NLMSG_ALIGNTO) < 0)
292 goto nla_put_failure;
294 if (qdisc->ce_mask & TCA_ATTR_KIND)
382 int ifindex, uint32_t parent)
384 struct rtnl_qdisc *q;
386 if (cache->c_ops != &rtnl_qdisc_ops)
389 nl_list_for_each_entry(q, &cache->c_items, ce_list) {
390 if (q->q_parent == parent && q->q_ifindex == ifindex) {
414 int ifindex,
char *kind)
416 struct rtnl_qdisc *q;
418 if (cache->c_ops != &rtnl_qdisc_ops)
421 nl_list_for_each_entry(q, &cache->c_items, ce_list) {
422 if ((q->q_ifindex == ifindex) && (!strcmp(q->q_kind, kind))) {
448 struct rtnl_qdisc *q;
450 if (cache->c_ops != &rtnl_qdisc_ops)
453 nl_list_for_each_entry(q, &cache->c_items, ce_list) {
454 if (q->q_handle == handle && q->q_ifindex == ifindex) {
477 void (*cb)(
struct nl_object *,
void *),
void *arg)
479 struct rtnl_class *filter;
481 filter = rtnl_class_alloc();
491 rtnl_class_put(filter);
501 void (*cb)(
struct nl_object *,
void *),
void *arg)
503 struct rtnl_cls *filter;
505 if (!(filter = rtnl_cls_alloc()))
512 rtnl_cls_put(filter);
523 struct rtnl_qdisc *
new,
524 struct nl_msg **result)
538 struct rtnl_qdisc *
new)
545static void qdisc_dump_details(
struct rtnl_tc *tc,
struct nl_dump_params *p)
547 struct rtnl_qdisc *qdisc = (
struct rtnl_qdisc *) tc;
549 nl_dump(p,
"refcnt %u", qdisc->q_info);
552static struct rtnl_tc_type_ops qdisc_ops = {
553 .tt_type = RTNL_TC_TYPE_QDISC,
554 .tt_dump_prefix =
"qdisc",
560static struct nl_cache_ops rtnl_qdisc_ops = {
561 .co_name =
"route/qdisc",
562 .co_hdrsize =
sizeof(
struct tcmsg),
564 { RTM_NEWQDISC, NL_ACT_NEW,
"new" },
565 { RTM_DELQDISC, NL_ACT_DEL,
"del" },
566 { RTM_GETQDISC, NL_ACT_GET,
"get" },
567 END_OF_MSGTYPES_LIST,
569 .co_protocol = NETLINK_ROUTE,
570 .co_groups = tc_groups,
571 .co_request_update = qdisc_request_update,
572 .co_msg_parser = qdisc_msg_parser,
573 .co_obj_ops = &qdisc_obj_ops,
576static struct nl_object_ops qdisc_obj_ops = {
577 .oo_name =
"route/qdisc",
578 .oo_size =
sizeof(
struct rtnl_qdisc),
579 .oo_free_data = rtnl_tc_free_data,
580 .oo_clone = rtnl_tc_clone,
586 .oo_compare = rtnl_tc_compare,
587 .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
590static void __init qdisc_init(
void)
592 rtnl_tc_type_register(&qdisc_ops);
596static void __exit qdisc_exit(
void)
599 rtnl_tc_type_unregister(&qdisc_ops);
#define NLA_PUT_STRING(msg, attrtype, value)
Add string attribute to netlink message.
int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
Unregister a set of cache operations.
int nl_cache_mngt_register(struct nl_cache_ops *ops)
Register a set of cache operations.
void nl_cache_foreach_filter(struct nl_cache *cache, struct nl_object *filter, void(*cb)(struct nl_object *, void *), void *arg)
Call a callback on each element of the cache (filtered).
int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_sock *sock, struct nl_cache **result)
Allocate new cache and fill it.
struct nl_msg * nlmsg_alloc_simple(int nlmsgtype, int flags)
Allocate a new netlink message.
void nlmsg_free(struct nl_msg *msg)
Release a reference from an netlink message.
int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
Append data to tail of a netlink message.
void nl_object_put(struct nl_object *obj)
Release a reference from an object.
void nl_object_get(struct nl_object *obj)
Acquire a reference on a object.
struct nl_object * nl_object_alloc(struct nl_object_ops *ops)
Allocate a new object of kind specified by the operations handle.
int rtnl_qdisc_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
Allocate a cache and fill it with all configured qdiscs.
int rtnl_qdisc_delete(struct nl_sock *sk, struct rtnl_qdisc *qdisc)
Delete qdisc.
int rtnl_qdisc_build_change_request(struct rtnl_qdisc *qdisc, struct rtnl_qdisc *new, struct nl_msg **result)
Build a netlink message requesting the update of a qdisc.
int rtnl_qdisc_build_delete_request(struct rtnl_qdisc *qdisc, struct nl_msg **result)
Build netlink message requesting the deletion of a qdisc.
struct rtnl_qdisc * rtnl_qdisc_get_by_kind(struct nl_cache *cache, int ifindex, char *kind)
Search qdisc by kind.
int rtnl_qdisc_change(struct nl_sock *sk, struct rtnl_qdisc *qdisc, struct rtnl_qdisc *new)
Change attributes of a qdisc.
struct rtnl_qdisc * rtnl_qdisc_get_by_parent(struct nl_cache *cache, int ifindex, uint32_t parent)
Search qdisc by interface index and parent.
void rtnl_qdisc_foreach_cls(struct rtnl_qdisc *qdisc, struct nl_cache *cache, void(*cb)(struct nl_object *, void *), void *arg)
Call a callback for each filter attached to the qdisc (deprecated)
struct rtnl_qdisc * rtnl_qdisc_get(struct nl_cache *cache, int ifindex, uint32_t handle)
Search qdisc by interface index and handle.
int rtnl_qdisc_build_add_request(struct rtnl_qdisc *qdisc, int flags, struct nl_msg **result)
Build a netlink message requesting the addition of a qdisc.
int rtnl_qdisc_update(struct nl_sock *sk, struct rtnl_qdisc *qdisc, struct rtnl_qdisc *new, int flags)
Update qdisc.
int rtnl_qdisc_add(struct nl_sock *sk, struct rtnl_qdisc *qdisc, int flags)
Add qdisc.
void rtnl_qdisc_foreach_child(struct rtnl_qdisc *qdisc, struct nl_cache *cache, void(*cb)(struct nl_object *, void *), void *arg)
Call a callback for each child class of a qdisc (deprecated)
int rtnl_qdisc_build_update_request(struct rtnl_qdisc *qdisc, struct rtnl_qdisc *new, int flags, struct nl_msg **result)
Build netlink message requesting the update of a qdisc.
int nl_send_sync(struct nl_sock *sk, struct nl_msg *msg)
Finalize and transmit Netlink message and wait for ACK or error message.
int nl_send_simple(struct nl_sock *sk, int type, int flags, void *buf, size_t size)
Construct and transmit a Netlink message.
int rtnl_tc_set_kind(struct rtnl_tc *tc, const char *kind)
Define the type of traffic control object.
void rtnl_tc_set_ifindex(struct rtnl_tc *tc, int ifindex)
Set interface index of traffic control object.
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
void rtnl_tc_set_handle(struct rtnl_tc *tc, uint32_t id)
Set identifier of traffic control object.
void rtnl_tc_set_parent(struct rtnl_tc *tc, uint32_t parent)
Set the parent identifier of a traffic control object.
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
@ NL_DUMP_STATS
Dump all attributes including statistics.
@ NL_DUMP_LINE
Dump object briefly on one line.
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.