00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <netlink-local.h>
00019 #include <netlink-tc.h>
00020 #include <netlink/netlink.h>
00021 #include <netlink/route/tc.h>
00022 #include <netlink/route/class.h>
00023 #include <netlink/route/class-modules.h>
00024 #include <netlink/route/qdisc.h>
00025 #include <netlink/route/classifier.h>
00026 #include <netlink/utils.h>
00027
00028 static struct nl_cache_ops rtnl_class_ops;
00029
00030 static int class_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00031 struct nlmsghdr *n, struct nl_parser_param *pp)
00032 {
00033 int err;
00034 struct rtnl_class *class;
00035 struct rtnl_class_ops *cops;
00036
00037 class = rtnl_class_alloc();
00038 if (!class) {
00039 err = -NLE_NOMEM;
00040 goto errout;
00041 }
00042 class->ce_msgtype = n->nlmsg_type;
00043
00044 err = tca_msg_parser(n, (struct rtnl_tca *) class);
00045 if (err < 0)
00046 goto errout_free;
00047
00048 cops = rtnl_class_lookup_ops(class);
00049 if (cops && cops->co_msg_parser) {
00050 err = cops->co_msg_parser(class);
00051 if (err < 0)
00052 goto errout_free;
00053 }
00054
00055 err = pp->pp_cb((struct nl_object *) class, pp);
00056 errout_free:
00057 rtnl_class_put(class);
00058 errout:
00059 return err;
00060 }
00061
00062 static int class_request_update(struct nl_cache *cache, struct nl_sock *sk)
00063 {
00064 struct tcmsg tchdr = {
00065 .tcm_family = AF_UNSPEC,
00066 .tcm_ifindex = cache->c_iarg1,
00067 };
00068
00069 return nl_send_simple(sk, RTM_GETTCLASS, NLM_F_DUMP, &tchdr,
00070 sizeof(tchdr));
00071 }
00072
00073
00074
00075
00076
00077
00078 static int class_build(struct rtnl_class *class, int type, int flags,
00079 struct nl_msg **result)
00080 {
00081 struct rtnl_class_ops *cops;
00082 int err;
00083
00084 err = tca_build_msg((struct rtnl_tca *) class, type, flags, result);
00085 if (err < 0)
00086 return err;
00087
00088 cops = rtnl_class_lookup_ops(class);
00089 if (cops && cops->co_get_opts) {
00090 struct nl_msg *opts;
00091
00092 opts = cops->co_get_opts(class);
00093 if (opts) {
00094 err = nla_put_nested(*result, TCA_OPTIONS, opts);
00095 nlmsg_free(opts);
00096 if (err < 0)
00097 goto errout;
00098 }
00099 }
00100
00101 return 0;
00102 errout:
00103 nlmsg_free(*result);
00104 return err;
00105 }
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 int rtnl_class_build_add_request(struct rtnl_class *class, int flags,
00124 struct nl_msg **result)
00125 {
00126 return class_build(class, RTM_NEWTCLASS, NLM_F_CREATE | flags, result);
00127 }
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144 int rtnl_class_add(struct nl_sock *sk, struct rtnl_class *class, int flags)
00145 {
00146 struct nl_msg *msg;
00147 int err;
00148
00149 if ((err = rtnl_class_build_add_request(class, flags, &msg)) < 0)
00150 return err;
00151
00152 err = nl_send_auto_complete(sk, msg);
00153 nlmsg_free(msg);
00154 if (err < 0)
00155 return err;
00156
00157 return wait_for_ack(sk);
00158 }
00159
00160 int rtnl_class_build_delete_request(struct rtnl_class *class,
00161 struct nl_msg **result)
00162 {
00163 struct nl_msg *msg;
00164 struct tcmsg tchdr;
00165 int required = TCA_ATTR_IFINDEX | TCA_ATTR_PARENT;
00166
00167 if ((class->ce_mask & required) != required)
00168 BUG();
00169
00170 msg = nlmsg_alloc_simple(RTM_DELTCLASS, 0);
00171 if (!msg)
00172 return -NLE_NOMEM;
00173
00174 tchdr.tcm_family = AF_UNSPEC;
00175 tchdr.tcm_handle = class->c_handle;
00176 tchdr.tcm_parent = class->c_parent;
00177 tchdr.tcm_ifindex = class->c_ifindex;
00178 if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) {
00179 nlmsg_free(msg);
00180 return -NLE_MSGSIZE;
00181 }
00182
00183 *result = msg;
00184 return 0;
00185 }
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198 int rtnl_class_delete(struct nl_sock *sk, struct rtnl_class *class)
00199 {
00200 struct nl_msg *msg;
00201 int err;
00202
00203 if ((err = rtnl_class_build_delete_request(class, &msg)) < 0)
00204 return err;
00205
00206 err = nl_send_auto_complete(sk, msg);
00207 nlmsg_free(msg);
00208 if (err < 0)
00209 return err;
00210
00211 return wait_for_ack(sk);
00212 }
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232 int rtnl_class_alloc_cache(struct nl_sock *sk, int ifindex,
00233 struct nl_cache **result)
00234 {
00235 struct nl_cache * cache;
00236 int err;
00237
00238 cache = nl_cache_alloc(&rtnl_class_ops);
00239 if (!cache)
00240 return -NLE_NOMEM;
00241
00242 cache->c_iarg1 = ifindex;
00243
00244 if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
00245 nl_cache_free(cache);
00246 return err;
00247 }
00248
00249 *result = cache;
00250 return 0;
00251 }
00252
00253
00254
00255
00256
00257
00258
00259
00260 struct rtnl_class *rtnl_class_get(struct nl_cache *cache, int ifindex,
00261 uint32_t handle)
00262 {
00263 struct rtnl_class *class;
00264
00265 if (cache->c_ops != &rtnl_class_ops)
00266 return NULL;
00267
00268 nl_list_for_each_entry(class, &cache->c_items, ce_list) {
00269 if (class->c_handle == handle && class->c_ifindex == ifindex) {
00270 nl_object_get((struct nl_object *) class);
00271 return class;
00272 }
00273 }
00274 return NULL;
00275 }
00276
00277
00278
00279 static struct nl_cache_ops rtnl_class_ops = {
00280 .co_name = "route/class",
00281 .co_hdrsize = sizeof(struct tcmsg),
00282 .co_msgtypes = {
00283 { RTM_NEWTCLASS, NL_ACT_NEW, "new" },
00284 { RTM_DELTCLASS, NL_ACT_DEL, "del" },
00285 { RTM_GETTCLASS, NL_ACT_GET, "get" },
00286 END_OF_MSGTYPES_LIST,
00287 },
00288 .co_protocol = NETLINK_ROUTE,
00289 .co_request_update = &class_request_update,
00290 .co_msg_parser = &class_msg_parser,
00291 .co_obj_ops = &class_obj_ops,
00292 };
00293
00294 static void __init class_init(void)
00295 {
00296 nl_cache_mngt_register(&rtnl_class_ops);
00297 }
00298
00299 static void __exit class_exit(void)
00300 {
00301 nl_cache_mngt_unregister(&rtnl_class_ops);
00302 }
00303
00304