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 static struct nl_cache_ops rtnl_cls_ops;
00037
00038 static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00039 struct nlmsghdr *nlh, struct nl_parser_param *pp)
00040 {
00041 struct rtnl_cls_ops *cops;
00042 struct rtnl_cls *cls;
00043 int err;
00044
00045 cls = rtnl_cls_alloc();
00046 if (!cls) {
00047 err = -NLE_NOMEM;
00048 goto errout;
00049 }
00050 cls->ce_msgtype = nlh->nlmsg_type;
00051
00052 err = tca_msg_parser(nlh, (struct rtnl_tca *) cls);
00053 if (err < 0)
00054 goto errout_free;
00055
00056 cls->c_prio = TC_H_MAJ(cls->c_info) >> 16;
00057 cls->c_protocol = ntohs(TC_H_MIN(cls->c_info));
00058
00059 cops = rtnl_cls_lookup_ops(cls);
00060 if (cops && cops->co_msg_parser && (err = cops->co_msg_parser(cls)) < 0)
00061 goto errout_free;
00062
00063 err = pp->pp_cb((struct nl_object *) cls, pp);
00064 errout_free:
00065 rtnl_cls_put(cls);
00066 errout:
00067 return err;
00068 }
00069
00070 static int cls_request_update(struct nl_cache *cache, struct nl_sock *sk)
00071 {
00072 struct tcmsg tchdr = {
00073 .tcm_family = AF_UNSPEC,
00074 .tcm_ifindex = cache->c_iarg1,
00075 .tcm_parent = cache->c_iarg2,
00076 };
00077
00078 return nl_send_simple(sk, RTM_GETTFILTER, NLM_F_DUMP, &tchdr,
00079 sizeof(tchdr));
00080 }
00081
00082
00083 static int cls_build(struct rtnl_cls *cls, int type, int flags,
00084 struct nl_msg **result)
00085 {
00086 struct rtnl_cls_ops *cops;
00087 int err, prio, proto;
00088 struct tcmsg *tchdr;
00089
00090 err = tca_build_msg((struct rtnl_tca *) cls, type, flags, result);
00091 if (err < 0)
00092 return err;
00093
00094 tchdr = nlmsg_data(nlmsg_hdr(*result));
00095 prio = rtnl_cls_get_prio(cls);
00096 proto = rtnl_cls_get_protocol(cls);
00097 tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto));
00098
00099 cops = rtnl_cls_lookup_ops(cls);
00100 if (cops && cops->co_get_opts) {
00101 struct nl_msg *opts;
00102
00103 if (!(opts = nlmsg_alloc())) {
00104 err = -NLE_NOMEM;
00105 goto errout;
00106 }
00107
00108 if (!(err = cops->co_get_opts(cls, opts)))
00109 err = nla_put_nested(*result, TCA_OPTIONS, opts);
00110
00111 nlmsg_free(opts);
00112 if (err < 0)
00113 goto errout;
00114 }
00115
00116 return 0;
00117 errout:
00118 nlmsg_free(*result);
00119 return err;
00120 }
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 int rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags,
00143 struct nl_msg **result)
00144 {
00145 return cls_build(cls, RTM_NEWTFILTER, NLM_F_CREATE | flags, result);
00146 }
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160 int rtnl_cls_add(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
00161 {
00162 struct nl_msg *msg;
00163 int err;
00164
00165 if ((err = rtnl_cls_build_add_request(cls, flags, &msg)) < 0)
00166 return err;
00167
00168 err = nl_send_auto_complete(sk, msg);
00169 nlmsg_free(msg);
00170 if (err < 0)
00171 return err;
00172
00173 return nl_wait_for_ack(sk);
00174 }
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189 int rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags,
00190 struct nl_msg **result)
00191 {
00192 return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags, result);
00193 }
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207 int rtnl_cls_change(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
00208 {
00209 struct nl_msg *msg;
00210 int err;
00211
00212 if ((err = rtnl_cls_build_change_request(cls, flags, &msg)) < 0)
00213 return err;
00214
00215 err = nl_send_auto_complete(sk, msg);
00216 nlmsg_free(msg);
00217 if (err < 0)
00218 return err;
00219
00220 return nl_wait_for_ack(sk);
00221 }
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236 int rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags,
00237 struct nl_msg **result)
00238 {
00239 return cls_build(cls, RTM_DELTFILTER, flags, result);
00240 }
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255 int rtnl_cls_delete(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
00256 {
00257 struct nl_msg *msg;
00258 int err;
00259
00260 if ((err = rtnl_cls_build_delete_request(cls, flags, &msg)) < 0)
00261 return err;
00262
00263 err = nl_send_auto_complete(sk, msg);
00264 nlmsg_free(msg);
00265 if (err < 0)
00266 return err;
00267
00268 return nl_wait_for_ack(sk);
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
00294 int rtnl_cls_alloc_cache(struct nl_sock *sk, int ifindex, uint32_t parent, struct nl_cache **result)
00295 {
00296 struct nl_cache * cache;
00297 int err;
00298
00299 if (!(cache = nl_cache_alloc(&rtnl_cls_ops)))
00300 return -NLE_NOMEM;
00301
00302 cache->c_iarg1 = ifindex;
00303 cache->c_iarg2 = parent;
00304
00305 if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
00306 nl_cache_free(cache);
00307 return err;
00308 }
00309
00310 *result = cache;
00311 return 0;
00312 }
00313
00314
00315
00316 static struct nl_cache_ops rtnl_cls_ops = {
00317 .co_name = "route/cls",
00318 .co_hdrsize = sizeof(struct tcmsg),
00319 .co_msgtypes = {
00320 { RTM_NEWTFILTER, NL_ACT_NEW, "new" },
00321 { RTM_DELTFILTER, NL_ACT_DEL, "del" },
00322 { RTM_GETTFILTER, NL_ACT_GET, "get" },
00323 END_OF_MSGTYPES_LIST,
00324 },
00325 .co_protocol = NETLINK_ROUTE,
00326 .co_request_update = cls_request_update,
00327 .co_msg_parser = cls_msg_parser,
00328 .co_obj_ops = &cls_obj_ops,
00329 };
00330
00331 static void __init cls_init(void)
00332 {
00333 nl_cache_mngt_register(&rtnl_cls_ops);
00334 }
00335
00336 static void __exit cls_exit(void)
00337 {
00338 nl_cache_mngt_unregister(&rtnl_cls_ops);
00339 }
00340
00341