1 /* 2 * lib/route/classifier.c Classifier 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation version 2.1 7 * of the License. 8 * 9 * Copyright (c) 2003-2009 Thomas Graf <tgraf (at) suug.ch> 10 */ 11 12 /** 13 * @ingroup tc 14 * @defgroup cls Classifiers 15 * 16 * @par Classifier Identification 17 * - protocol 18 * - priority 19 * - parent 20 * - interface 21 * - kind 22 * - handle 23 * 24 * @{ 25 */ 26 27 #include <netlink-local.h> 28 #include <netlink-tc.h> 29 #include <netlink/netlink.h> 30 #include <netlink/utils.h> 31 #include <netlink/route/tc.h> 32 #include <netlink/route/classifier.h> 33 #include <netlink/route/classifier-modules.h> 34 #include <netlink/route/link.h> 35 36 static struct nl_cache_ops rtnl_cls_ops; 37 38 static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, 39 struct nlmsghdr *nlh, struct nl_parser_param *pp) 40 { 41 struct rtnl_cls_ops *cops; 42 struct rtnl_cls *cls; 43 int err; 44 45 cls = rtnl_cls_alloc(); 46 if (!cls) { 47 err = -NLE_NOMEM; 48 goto errout; 49 } 50 cls->ce_msgtype = nlh->nlmsg_type; 51 52 err = tca_msg_parser(nlh, (struct rtnl_tca *) cls); 53 if (err < 0) 54 goto errout_free; 55 56 cls->c_prio = TC_H_MAJ(cls->c_info) >> 16; 57 cls->c_protocol = ntohs(TC_H_MIN(cls->c_info)); 58 59 cops = rtnl_cls_lookup_ops(cls); 60 if (cops && cops->co_msg_parser && (err = cops->co_msg_parser(cls)) < 0) 61 goto errout_free; 62 63 err = pp->pp_cb((struct nl_object *) cls, pp); 64 errout_free: 65 rtnl_cls_put(cls); 66 errout: 67 return err; 68 } 69 70 static int cls_request_update(struct nl_cache *cache, struct nl_sock *sk) 71 { 72 struct tcmsg tchdr = { 73 .tcm_family = AF_UNSPEC, 74 .tcm_ifindex = cache->c_iarg1, 75 .tcm_parent = cache->c_iarg2, 76 }; 77 78 return nl_send_simple(sk, RTM_GETTFILTER, NLM_F_DUMP, &tchdr, 79 sizeof(tchdr)); 80 } 81 82 83 static int cls_build(struct rtnl_cls *cls, int type, int flags, 84 struct nl_msg **result) 85 { 86 struct rtnl_cls_ops *cops; 87 int err, prio, proto; 88 struct tcmsg *tchdr; 89 90 err = tca_build_msg((struct rtnl_tca *) cls, type, flags, result); 91 if (err < 0) 92 return err; 93 94 tchdr = nlmsg_data(nlmsg_hdr(*result)); 95 prio = rtnl_cls_get_prio(cls); 96 proto = rtnl_cls_get_protocol(cls); 97 tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto)); 98 99 cops = rtnl_cls_lookup_ops(cls); 100 if (cops && cops->co_get_opts) { 101 struct nl_msg *opts; 102 103 if (!(opts = nlmsg_alloc())) { 104 err = -NLE_NOMEM; 105 goto errout; 106 } 107 108 if (!(err = cops->co_get_opts(cls, opts))) 109 err = nla_put_nested(*result, TCA_OPTIONS, opts); 110 111 nlmsg_free(opts); 112 if (err < 0) 113 goto errout; 114 } 115 116 return 0; 117 errout: 118 nlmsg_free(*result); 119 return err; 120 } 121 122 /** 123 * @name Classifier Addition/Modification/Deletion 124 * @{ 125 */ 126 127 /** 128 * Build a netlink message to add a new classifier 129 * @arg cls classifier to add 130 * @arg flags additional netlink message flags 131 * @arg result Pointer to store resulting message. 132 * 133 * Builds a new netlink message requesting an addition of a classifier 134 * The netlink message header isn't fully equipped with all relevant 135 * fields and must be sent out via nl_send_auto_complete() or 136 * supplemented as needed. \a classifier must contain the attributes of 137 * the new classifier set via \c rtnl_cls_set_* functions. \a opts 138 * may point to the clsasifier specific options. 139 * 140 * @return 0 on success or a negative error code. 141 */ 142 int rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags, 143 struct nl_msg **result) 144 { 145 return cls_build(cls, RTM_NEWTFILTER, NLM_F_CREATE | flags, result); 146 } 147 148 /** 149 * Add a new classifier 150 * @arg sk Netlink socket. 151 * @arg cls classifier to add 152 * @arg flags additional netlink message flags 153 * 154 * Builds a netlink message by calling rtnl_cls_build_add_request(), 155 * sends the request to the kernel and waits for the next ACK to be 156 * received and thus blocks until the request has been processed. 157 * 158 * @return 0 on sucess or a negative error if an error occured. 159 */ 160 int rtnl_cls_add(struct nl_sock *sk, struct rtnl_cls *cls, int flags) 161 { 162 struct nl_msg *msg; 163 int err; 164 165 if ((err = rtnl_cls_build_add_request(cls, flags, &msg)) < 0) 166 return err; 167 168 err = nl_send_auto_complete(sk, msg); 169 nlmsg_free(msg); 170 if (err < 0) 171 return err; 172 173 return nl_wait_for_ack(sk); 174 } 175 176 /** 177 * Build a netlink message to change classifier attributes 178 * @arg cls classifier to change 179 * @arg flags additional netlink message flags 180 * @arg result Pointer to store resulting message. 181 * 182 * Builds a new netlink message requesting a change of a neigh 183 * attributes. The netlink message header isn't fully equipped with 184 * all relevant fields and must thus be sent out via nl_send_auto_complete() 185 * or supplemented as needed. 186 * 187 * @return 0 on success or a negative error code. 188 */ 189 int rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags, 190 struct nl_msg **result) 191 { 192 return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags, result); 193 } 194 195 /** 196 * Change a classifier 197 * @arg sk Netlink socket. 198 * @arg cls classifier to change 199 * @arg flags additional netlink message flags 200 * 201 * Builds a netlink message by calling rtnl_cls_build_change_request(), 202 * sends the request to the kernel and waits for the next ACK to be 203 * received and thus blocks until the request has been processed. 204 * 205 * @return 0 on sucess or a negative error if an error occured. 206 */ 207 int rtnl_cls_change(struct nl_sock *sk, struct rtnl_cls *cls, int flags) 208 { 209 struct nl_msg *msg; 210 int err; 211 212 if ((err = rtnl_cls_build_change_request(cls, flags, &msg)) < 0) 213 return err; 214 215 err = nl_send_auto_complete(sk, msg); 216 nlmsg_free(msg); 217 if (err < 0) 218 return err; 219 220 return nl_wait_for_ack(sk); 221 } 222 223 /** 224 * Build a netlink request message to delete a classifier 225 * @arg cls classifier to delete 226 * @arg flags additional netlink message flags 227 * @arg result Pointer to store resulting message. 228 * 229 * Builds a new netlink message requesting a deletion of a classifier. 230 * The netlink message header isn't fully equipped with all relevant 231 * fields and must thus be sent out via nl_send_auto_complete() 232 * or supplemented as needed. 233 * 234 * @return 0 on success or a negative error code. 235 */ 236 int rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags, 237 struct nl_msg **result) 238 { 239 return cls_build(cls, RTM_DELTFILTER, flags, result); 240 } 241 242 243 /** 244 * Delete a classifier 245 * @arg sk Netlink socket. 246 * @arg cls classifier to delete 247 * @arg flags additional netlink message flags 248 * 249 * Builds a netlink message by calling rtnl_cls_build_delete_request(), 250 * sends the request to the kernel and waits for the next ACK to be 251 * received and thus blocks until the request has been processed. 252 * 253 * @return 0 on sucess or a negative error if an error occured. 254 */ 255 int rtnl_cls_delete(struct nl_sock *sk, struct rtnl_cls *cls, int flags) 256 { 257 struct nl_msg *msg; 258 int err; 259 260 if ((err = rtnl_cls_build_delete_request(cls, flags, &msg)) < 0) 261 return err; 262 263 err = nl_send_auto_complete(sk, msg); 264 nlmsg_free(msg); 265 if (err < 0) 266 return err; 267 268 return nl_wait_for_ack(sk); 269 } 270 271 /** @} */ 272 273 /** 274 * @name Cache Management 275 * @{ 276 */ 277 278 /** 279 * Build a classifier cache including all classifiers attached to the 280 * specified class/qdisc on eht specified interface. 281 * @arg sk Netlink socket. 282 * @arg ifindex interface index of the link the classes are 283 * attached to. 284 * @arg parent parent qdisc/class 285 * @arg result Pointer to store resulting cache. 286 * 287 * Allocates a new cache, initializes it properly and updates it to 288 * include all classes attached to the specified interface. 289 * 290 * @note The caller is responsible for destroying and freeing the 291 * cache after using it. 292 * @return 0 on success or a negative error code. 293 */ 294 int rtnl_cls_alloc_cache(struct nl_sock *sk, int ifindex, uint32_t parent, struct nl_cache **result) 295 { 296 struct nl_cache * cache; 297 int err; 298 299 if (!(cache = nl_cache_alloc(&rtnl_cls_ops))) 300 return -NLE_NOMEM; 301 302 cache->c_iarg1 = ifindex; 303 cache->c_iarg2 = parent; 304 305 if (sk && (err = nl_cache_refill(sk, cache)) < 0) { 306 nl_cache_free(cache); 307 return err; 308 } 309 310 *result = cache; 311 return 0; 312 } 313 314 /** @} */ 315 316 static struct nl_cache_ops rtnl_cls_ops = { 317 .co_name = "route/cls", 318 .co_hdrsize = sizeof(struct tcmsg), 319 .co_msgtypes = { 320 { RTM_NEWTFILTER, NL_ACT_NEW, "new" }, 321 { RTM_DELTFILTER, NL_ACT_DEL, "del" }, 322 { RTM_GETTFILTER, NL_ACT_GET, "get" }, 323 END_OF_MSGTYPES_LIST, 324 }, 325 .co_protocol = NETLINK_ROUTE, 326 .co_request_update = cls_request_update, 327 .co_msg_parser = cls_msg_parser, 328 .co_obj_ops = &cls_obj_ops, 329 }; 330 331 static void __init cls_init(void) 332 { 333 nl_cache_mngt_register(&rtnl_cls_ops); 334 } 335 336 static void __exit cls_exit(void) 337 { 338 nl_cache_mngt_unregister(&rtnl_cls_ops); 339 } 340 341 /** @} */ 342