00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <netlink-local.h>
00028 #include <netlink-tc.h>
00029 #include <netlink/netlink.h>
00030 #include <netlink/utils.h>
00031 #include <netlink/route/tc-api.h>
00032 #include <netlink/route/classifier.h>
00033 #include <netlink/route/link.h>
00034
00035
00036 #define CLS_ATTR_PRIO (TCA_ATTR_MAX << 1)
00037 #define CLS_ATTR_PROTOCOL (TCA_ATTR_MAX << 2)
00038
00039
00040 static struct nl_object_ops cls_obj_ops;
00041 static struct nl_cache_ops rtnl_cls_ops;
00042
00043
00044 static int cls_build(struct rtnl_cls *cls, int type, int flags,
00045 struct nl_msg **result)
00046 {
00047 int err, prio, proto;
00048 struct tcmsg *tchdr;
00049
00050 err = rtnl_tc_msg_build(TC_CAST(cls), type, flags, result);
00051 if (err < 0)
00052 return err;
00053
00054 tchdr = nlmsg_data(nlmsg_hdr(*result));
00055 prio = rtnl_cls_get_prio(cls);
00056 proto = rtnl_cls_get_protocol(cls);
00057 tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto));
00058
00059 return 0;
00060 }
00061
00062
00063
00064
00065
00066
00067 struct rtnl_cls *rtnl_cls_alloc(void)
00068 {
00069 struct rtnl_tc *tc;
00070
00071 tc = TC_CAST(nl_object_alloc(&cls_obj_ops));
00072 if (tc)
00073 tc->tc_type = RTNL_TC_TYPE_CLS;
00074
00075 return (struct rtnl_cls *) tc;
00076 }
00077
00078 void rtnl_cls_put(struct rtnl_cls *cls)
00079 {
00080 nl_object_put((struct nl_object *) cls);
00081 }
00082
00083
00084
00085
00086
00087
00088
00089
00090 void rtnl_cls_set_prio(struct rtnl_cls *cls, uint16_t prio)
00091 {
00092 cls->c_prio = prio;
00093 cls->ce_mask |= CLS_ATTR_PRIO;
00094 }
00095
00096 uint16_t rtnl_cls_get_prio(struct rtnl_cls *cls)
00097 {
00098 if (cls->ce_mask & CLS_ATTR_PRIO)
00099 return cls->c_prio;
00100 else
00101 return 0;
00102 }
00103
00104 void rtnl_cls_set_protocol(struct rtnl_cls *cls, uint16_t protocol)
00105 {
00106 cls->c_protocol = protocol;
00107 cls->ce_mask |= CLS_ATTR_PROTOCOL;
00108 }
00109
00110 uint16_t rtnl_cls_get_protocol(struct rtnl_cls *cls)
00111 {
00112 if (cls->ce_mask & CLS_ATTR_PROTOCOL)
00113 return cls->c_protocol;
00114 else
00115 return ETH_P_ALL;
00116 }
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141 int rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags,
00142 struct nl_msg **result)
00143 {
00144 return cls_build(cls, RTM_NEWTFILTER, NLM_F_CREATE | flags, result);
00145 }
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159 int rtnl_cls_add(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
00160 {
00161 struct nl_msg *msg;
00162 int err;
00163
00164 if ((err = rtnl_cls_build_add_request(cls, flags, &msg)) < 0)
00165 return err;
00166
00167 err = nl_send_auto_complete(sk, msg);
00168 nlmsg_free(msg);
00169 if (err < 0)
00170 return err;
00171
00172 return nl_wait_for_ack(sk);
00173 }
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188 int rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags,
00189 struct nl_msg **result)
00190 {
00191 return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags, result);
00192 }
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206 int rtnl_cls_change(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
00207 {
00208 struct nl_msg *msg;
00209 int err;
00210
00211 if ((err = rtnl_cls_build_change_request(cls, flags, &msg)) < 0)
00212 return err;
00213
00214 err = nl_send_auto_complete(sk, msg);
00215 nlmsg_free(msg);
00216 if (err < 0)
00217 return err;
00218
00219 return nl_wait_for_ack(sk);
00220 }
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235 int rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags,
00236 struct nl_msg **result)
00237 {
00238 return cls_build(cls, RTM_DELTFILTER, flags, result);
00239 }
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254 int rtnl_cls_delete(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
00255 {
00256 struct nl_msg *msg;
00257 int err;
00258
00259 if ((err = rtnl_cls_build_delete_request(cls, flags, &msg)) < 0)
00260 return err;
00261
00262 err = nl_send_auto_complete(sk, msg);
00263 nlmsg_free(msg);
00264 if (err < 0)
00265 return err;
00266
00267 return nl_wait_for_ack(sk);
00268 }
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293 int rtnl_cls_alloc_cache(struct nl_sock *sk, int ifindex, uint32_t parent, struct nl_cache **result)
00294 {
00295 struct nl_cache * cache;
00296 int err;
00297
00298 if (!(cache = nl_cache_alloc(&rtnl_cls_ops)))
00299 return -NLE_NOMEM;
00300
00301 cache->c_iarg1 = ifindex;
00302 cache->c_iarg2 = parent;
00303
00304 if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
00305 nl_cache_free(cache);
00306 return err;
00307 }
00308
00309 *result = cache;
00310 return 0;
00311 }
00312
00313
00314
00315 static void cls_dump_line(struct rtnl_tc *tc, struct nl_dump_params *p)
00316 {
00317 struct rtnl_cls *cls = (struct rtnl_cls *) tc;
00318 char buf[32];
00319
00320 nl_dump(p, " prio %u protocol %s", cls->c_prio,
00321 nl_ether_proto2str(cls->c_protocol, buf, sizeof(buf)));
00322 }
00323
00324 static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00325 struct nlmsghdr *nlh, struct nl_parser_param *pp)
00326 {
00327 struct rtnl_cls *cls;
00328 int err;
00329
00330 if (!(cls = rtnl_cls_alloc()))
00331 return -NLE_NOMEM;
00332
00333 if ((err = rtnl_tc_msg_parse(nlh, TC_CAST(cls))) < 0)
00334 goto errout;
00335
00336 cls->c_prio = TC_H_MAJ(cls->c_info) >> 16;
00337 cls->c_protocol = ntohs(TC_H_MIN(cls->c_info));
00338
00339 err = pp->pp_cb(OBJ_CAST(cls), pp);
00340 errout:
00341 rtnl_cls_put(cls);
00342
00343 return err;
00344 }
00345
00346 static int cls_request_update(struct nl_cache *cache, struct nl_sock *sk)
00347 {
00348 struct tcmsg tchdr = {
00349 .tcm_family = AF_UNSPEC,
00350 .tcm_ifindex = cache->c_iarg1,
00351 .tcm_parent = cache->c_iarg2,
00352 };
00353
00354 return nl_send_simple(sk, RTM_GETTFILTER, NLM_F_DUMP, &tchdr,
00355 sizeof(tchdr));
00356 }
00357
00358 static struct rtnl_tc_type_ops cls_ops = {
00359 .tt_type = RTNL_TC_TYPE_CLS,
00360 .tt_dump_prefix = "cls",
00361 .tt_dump = {
00362 [NL_DUMP_LINE] = cls_dump_line,
00363 },
00364 };
00365
00366 static struct nl_cache_ops rtnl_cls_ops = {
00367 .co_name = "route/cls",
00368 .co_hdrsize = sizeof(struct tcmsg),
00369 .co_msgtypes = {
00370 { RTM_NEWTFILTER, NL_ACT_NEW, "new" },
00371 { RTM_DELTFILTER, NL_ACT_DEL, "del" },
00372 { RTM_GETTFILTER, NL_ACT_GET, "get" },
00373 END_OF_MSGTYPES_LIST,
00374 },
00375 .co_protocol = NETLINK_ROUTE,
00376 .co_request_update = cls_request_update,
00377 .co_msg_parser = cls_msg_parser,
00378 .co_obj_ops = &cls_obj_ops,
00379 };
00380
00381 static struct nl_object_ops cls_obj_ops = {
00382 .oo_name = "route/cls",
00383 .oo_size = sizeof(struct rtnl_cls),
00384 .oo_free_data = rtnl_tc_free_data,
00385 .oo_clone = rtnl_tc_clone,
00386 .oo_dump = {
00387 [NL_DUMP_LINE] = rtnl_tc_dump_line,
00388 [NL_DUMP_DETAILS] = rtnl_tc_dump_details,
00389 [NL_DUMP_STATS] = rtnl_tc_dump_stats,
00390 },
00391 .oo_compare = rtnl_tc_compare,
00392 .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
00393 };
00394
00395 static void __init cls_init(void)
00396 {
00397 rtnl_tc_type_register(&cls_ops);
00398 nl_cache_mngt_register(&rtnl_cls_ops);
00399 }
00400
00401 static void __exit cls_exit(void)
00402 {
00403 nl_cache_mngt_unregister(&rtnl_cls_ops);
00404 rtnl_tc_type_unregister(&cls_ops);
00405 }
00406
00407