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.h>
00032 #include <netlink/route/classifier.h>
00033 #include <netlink/route/classifier-modules.h>
00034 #include <netlink/route/link.h>
00035
00036
00037 #define CLS_ATTR_PRIO (TCA_ATTR_MAX << 1)
00038 #define CLS_ATTR_PROTOCOL (TCA_ATTR_MAX << 2)
00039
00040 static struct nl_cache_ops rtnl_cls_ops;
00041
00042
00043 static struct rtnl_cls_ops *cls_ops_list;
00044
00045 static struct rtnl_cls_ops * cls_lookup_ops(char *kind)
00046 {
00047 struct rtnl_cls_ops *ops;
00048
00049 for (ops = cls_ops_list; ops; ops = ops->co_next)
00050 if (!strcmp(kind, ops->co_kind))
00051 return ops;
00052
00053 return NULL;
00054 }
00055
00056 static inline struct rtnl_cls_ops *cls_ops(struct rtnl_cls *cls)
00057 {
00058 if (!cls->c_ops)
00059 cls->c_ops = cls_lookup_ops(cls->c_kind);
00060
00061 return cls->c_ops;
00062 }
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073 int rtnl_cls_register(struct rtnl_cls_ops *ops)
00074 {
00075 struct rtnl_cls_ops *o, **op;
00076
00077 if (!ops->co_kind)
00078 BUG();
00079
00080 for (op = &cls_ops_list; (o = *op) != NULL; op = &o->co_next)
00081 if (!strcasecmp(ops->co_kind, o->co_kind))
00082 return nl_errno(EEXIST);
00083
00084 ops->co_next = NULL;
00085 *op = ops;
00086
00087 return 0;
00088 }
00089
00090
00091
00092
00093
00094 int rtnl_cls_unregister(struct rtnl_cls_ops *ops)
00095 {
00096 struct rtnl_cls_ops *o, **op;
00097
00098 for (op = &cls_ops_list; (o = *op) != NULL; op = &o->co_next)
00099 if (!strcasecmp(ops->co_kind, o->co_kind))
00100 break;
00101
00102 if (!o)
00103 return nl_errno(ENOENT);
00104
00105 *op = ops->co_next;
00106
00107 return 0;
00108 }
00109
00110
00111
00112 static int cls_msg_parser(struct sockaddr_nl *who, struct nlmsghdr *nlh,
00113 void *arg)
00114 {
00115 int err;
00116 struct nl_parser_param *pp = arg;
00117 struct rtnl_cls *cls;
00118 struct rtnl_cls_ops *ops;
00119
00120 cls = rtnl_cls_alloc();
00121 if (!cls) {
00122 err = nl_errno(ENOMEM);
00123 goto errout;
00124 }
00125 cls->ce_msgtype = nlh->nlmsg_type;
00126
00127 err = tca_msg_parser(nlh, (struct rtnl_tca *) cls);
00128 if (err < 0)
00129 goto errout_free;
00130
00131 cls->c_prio = TC_H_MAJ(cls->c_info) >> 16;
00132 cls->c_protocol = ntohs(TC_H_MIN(cls->c_info));
00133
00134 ops = cls_ops(cls);
00135 if (ops && ops->co_msg_parser) {
00136 err = ops->co_msg_parser(cls);
00137 if (err < 0)
00138 goto errout_free;
00139 }
00140
00141 err = pp->pp_cb((struct nl_object *) cls, pp);
00142 if (err < 0)
00143 goto errout_free;
00144
00145 return P_ACCEPT;
00146
00147 errout_free:
00148 rtnl_cls_put(cls);
00149 errout:
00150 return err;
00151 }
00152
00153 static int cls_request_update(struct nl_cache *cache, struct nl_handle *handle)
00154 {
00155 struct tcmsg tchdr = {
00156 .tcm_family = AF_UNSPEC,
00157 .tcm_ifindex = cache->c_iarg1,
00158 .tcm_parent = cache->c_iarg2,
00159 };
00160
00161 return nl_send_simple(handle, RTM_GETTFILTER, NLM_F_DUMP, &tchdr,
00162 sizeof(tchdr));
00163 }
00164
00165
00166 static void cls_free_data(struct nl_object *obj)
00167 {
00168 struct rtnl_cls *cls = (struct rtnl_cls *) obj;
00169 struct rtnl_cls_ops *ops;
00170
00171 tca_free_data((struct rtnl_tca *) cls);
00172
00173 ops = cls_ops(cls);
00174 if (ops && ops->co_free_data)
00175 ops->co_free_data(cls);
00176 }
00177
00178 static int cls_dump_brief(struct nl_object *obj, struct nl_dump_params *p)
00179 {
00180 char buf[32];
00181 struct rtnl_cls *cls = (struct rtnl_cls *) obj;
00182 struct rtnl_cls_ops *ops;
00183 int line;
00184
00185 line = tca_dump_brief((struct rtnl_tca *) cls, "cls", p, 0);
00186
00187 dp_dump(p, " prio %u protocol %s", cls->c_prio,
00188 nl_ether_proto2str(cls->c_protocol, buf, sizeof(buf)));
00189
00190 ops = cls_ops(cls);
00191 if (ops && ops->co_dump[NL_DUMP_BRIEF])
00192 line = ops->co_dump[NL_DUMP_BRIEF](cls, p, line);
00193 dp_dump(p, "\n");
00194
00195 return line;
00196 }
00197
00198 static int cls_dump_full(struct nl_object *obj, struct nl_dump_params *p)
00199 {
00200 struct rtnl_cls *cls = (struct rtnl_cls *) obj;
00201 struct rtnl_cls_ops *ops;
00202 int line;
00203
00204 line = cls_dump_brief(obj, p);
00205 line = tca_dump_full((struct rtnl_tca *) cls, p, line);
00206
00207 ops = cls_ops(cls);
00208 if (ops && ops->co_dump[NL_DUMP_FULL])
00209 line = ops->co_dump[NL_DUMP_FULL](cls, p, line);
00210 else
00211 dp_dump(p, "no options\n");
00212
00213 return line;
00214 }
00215
00216 static int cls_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
00217 {
00218 struct rtnl_cls *cls = (struct rtnl_cls *) obj;
00219 struct rtnl_cls_ops *ops;
00220 int line;
00221
00222 line = cls_dump_full(obj, p);
00223 line = tca_dump_stats((struct rtnl_tca *) cls, p, line);
00224 dp_dump(p, "\n");
00225
00226 ops = cls_ops(cls);
00227 if (ops && ops->co_dump[NL_DUMP_STATS])
00228 line = ops->co_dump[NL_DUMP_STATS](cls, p, line);
00229
00230 return line;
00231 }
00232
00233 static int cls_filter(struct nl_object *obj, struct nl_object *filter)
00234 {
00235 return tca_filter((struct rtnl_tca *) obj, (struct rtnl_tca *) filter);
00236 }
00237
00238 static struct nl_msg *cls_build(struct rtnl_cls *cls, int type, int flags)
00239 {
00240 struct nl_msg *msg;
00241 struct rtnl_cls_ops *ops;
00242 int err, prio, proto;
00243 struct tcmsg *tchdr;
00244
00245 msg = tca_build_msg((struct rtnl_tca *) cls, type, flags);
00246 if (!msg)
00247 goto errout;
00248
00249 tchdr = nlmsg_data(nlmsg_hdr(msg));
00250 prio = cls->c_mask & CLS_ATTR_PRIO ? cls->c_prio : 0;
00251 proto = cls->c_mask & CLS_ATTR_PROTOCOL ? cls->c_protocol : ETH_P_ALL;
00252 tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto)),
00253
00254 ops = cls_ops(cls);
00255 if (ops && ops->co_get_opts) {
00256 struct nl_msg *opts;
00257
00258 opts = ops->co_get_opts(cls);
00259 if (opts) {
00260 err = nla_put_nested(msg, TCA_OPTIONS, opts);
00261 nlmsg_free(opts);
00262 if (err < 0)
00263 goto errout;
00264 }
00265 }
00266
00267 return msg;
00268 errout:
00269 nlmsg_free(msg);
00270 return NULL;
00271 }
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292 struct nl_msg * rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags)
00293 {
00294 return cls_build(cls, RTM_NEWTFILTER, NLM_F_CREATE | flags);
00295 }
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309 int rtnl_cls_add(struct nl_handle *handle, struct rtnl_cls *cls, int flags)
00310 {
00311 int err;
00312 struct nl_msg *msg;
00313
00314 msg = rtnl_cls_build_add_request(cls, flags);
00315 if (!msg)
00316 return nl_errno(ENOMEM);
00317
00318 err = nl_send_auto_complete(handle, msg);
00319 if (err < 0)
00320 return err;
00321
00322 nlmsg_free(msg);
00323 return nl_wait_for_ack(handle);
00324 }
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338 struct nl_msg *rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags)
00339 {
00340 return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags);
00341 }
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355 int rtnl_cls_change(struct nl_handle *handle, struct rtnl_cls *cls,
00356 int flags)
00357 {
00358 int err;
00359 struct nl_msg *msg;
00360
00361 msg = rtnl_cls_build_change_request(cls, flags);
00362 if (!msg)
00363 return nl_errno(ENOMEM);
00364
00365 err = nl_send_auto_complete(handle, msg);
00366 if (err < 0)
00367 return err;
00368
00369 nlmsg_free(msg);
00370 return nl_wait_for_ack(handle);
00371 }
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385 struct nl_msg *rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags)
00386 {
00387 return cls_build(cls, RTM_DELTFILTER, flags);
00388 }
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403 int rtnl_cls_delete(struct nl_handle *handle, struct rtnl_cls *cls, int flags)
00404 {
00405 int err;
00406 struct nl_msg *msg;
00407
00408 msg = rtnl_cls_build_delete_request(cls, flags);
00409 if (!msg)
00410 return nl_errno(ENOMEM);
00411
00412 err = nl_send_auto_complete(handle, msg);
00413 if (err < 0)
00414 return err;
00415
00416 nlmsg_free(msg);
00417 return nl_wait_for_ack(handle);
00418 }
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431 struct rtnl_cls *rtnl_cls_alloc(void)
00432 {
00433 return (struct rtnl_cls *) nl_object_alloc_from_ops(&rtnl_cls_ops);
00434 }
00435
00436
00437
00438
00439
00440
00441
00442
00443 void rtnl_cls_put(struct rtnl_cls *cls)
00444 {
00445 nl_object_put((struct nl_object *) cls);
00446 }
00447
00448
00449
00450
00451
00452
00453
00454
00455 void rtnl_cls_free(struct rtnl_cls *cls)
00456 {
00457 nl_object_free((struct nl_object *) cls);
00458 }
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475 struct nl_cache *rtnl_cls_alloc_cache(struct nl_handle *handle,
00476 int ifindex, uint32_t parent)
00477 {
00478 struct nl_cache * cache;
00479
00480 cache = nl_cache_alloc_from_ops(&rtnl_cls_ops);
00481 if (cache == NULL)
00482 return NULL;
00483
00484 cache->c_iarg1 = ifindex;
00485 cache->c_iarg2 = parent;
00486
00487 if (nl_cache_update(handle, cache) < 0) {
00488 nl_cache_free(cache);
00489 return NULL;
00490 }
00491
00492 return cache;
00493 }
00494
00495 void rtnl_cls_set_ifindex(struct rtnl_cls *f, int ifindex)
00496 {
00497 tca_set_ifindex((struct rtnl_tca *) f, ifindex);
00498 }
00499
00500 void rtnl_cls_set_handle(struct rtnl_cls *f, uint32_t handle)
00501 {
00502 tca_set_handle((struct rtnl_tca *) f, handle);
00503 }
00504
00505 void rtnl_cls_set_parent(struct rtnl_cls *f, uint32_t parent)
00506 {
00507 tca_set_parent((struct rtnl_tca *) f, parent);
00508 }
00509
00510 void rtnl_cls_set_kind(struct rtnl_cls *f, const char *kind)
00511 {
00512 tca_set_kind((struct rtnl_tca *) f, kind);
00513 }
00514
00515
00516
00517
00518
00519
00520 void rtnl_cls_set_prio(struct rtnl_cls *cls, int prio)
00521 {
00522 cls->c_prio = prio;
00523 cls->c_mask |= CLS_ATTR_PRIO;
00524 }
00525
00526
00527
00528
00529
00530 int rtnl_cls_get_prio(struct rtnl_cls *cls)
00531 {
00532 if (cls->c_mask & CLS_ATTR_PRIO)
00533 return cls->c_prio;
00534 else
00535 return 0;
00536 }
00537
00538
00539
00540
00541
00542
00543 void rtnl_cls_set_protocol(struct rtnl_cls *cls, int protocol)
00544 {
00545 cls->c_protocol = protocol;
00546 cls->c_mask |= CLS_ATTR_PROTOCOL;
00547 }
00548
00549
00550
00551
00552
00553 int rtnl_cls_get_protocol(struct rtnl_cls *cls)
00554 {
00555 if (cls->c_mask & CLS_ATTR_PROTOCOL)
00556 return cls->c_protocol;
00557 else
00558 return 0;
00559 }
00560
00561
00562
00563 static struct nl_cache_ops rtnl_cls_ops = {
00564 .co_name = "route/cls",
00565 .co_size = sizeof(struct rtnl_cls),
00566 .co_hdrsize = sizeof(struct tcmsg),
00567 .co_msgtypes = {
00568 { RTM_NEWTFILTER, "new" },
00569 { RTM_DELTFILTER, "delete" },
00570 { RTM_GETTFILTER, "get" },
00571 { -1, NULL },
00572 },
00573 .co_protocol = NETLINK_ROUTE,
00574 .co_request_update = cls_request_update,
00575 .co_filter = cls_filter,
00576 .co_free_data = cls_free_data,
00577 .co_msg_parser = cls_msg_parser,
00578 .co_dump[NL_DUMP_BRIEF] = cls_dump_brief,
00579 .co_dump[NL_DUMP_FULL] = cls_dump_full,
00580 .co_dump[NL_DUMP_STATS] = cls_dump_stats,
00581 };
00582
00583 static void __init cls_init(void)
00584 {
00585 nl_cache_mngt_register(&rtnl_cls_ops);
00586 }
00587
00588 static void __exit cls_exit(void)
00589 {
00590 nl_cache_mngt_unregister(&rtnl_cls_ops);
00591 }
00592
00593