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