1 /* 2 * lib/route/cls/basic.c Basic 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) 2008-2013 Thomas Graf <tgraf (at) suug.ch> 10 */ 11 12 /** 13 * @ingroup cls 14 * @defgroup cls_basic Basic Classifier 15 * 16 * @par Introduction 17 * The basic classifier is the simplest form of a classifier. It does 18 * not have any special classification capabilities, instead it can be 19 * used to classify exclusively based on extended matches or to 20 * create a "catch-all" filter. 21 * 22 * @{ 23 */ 24 25 #include <netlink-private/netlink.h> 26 #include <netlink-private/tc.h> 27 #include <netlink/netlink.h> 28 #include <netlink-private/route/tc-api.h> 29 #include <netlink/route/classifier.h> 30 #include <netlink/route/action.h> 31 #include <netlink/route/cls/basic.h> 32 #include <netlink/route/cls/ematch.h> 33 34 struct rtnl_basic 35 { 36 uint32_t b_target; 37 struct rtnl_ematch_tree * b_ematch; 38 int b_mask; 39 struct rtnl_act * b_act; 40 }; 41 42 /** @cond SKIP */ 43 #define BASIC_ATTR_TARGET 0x001 44 #define BASIC_ATTR_EMATCH 0x002 45 #define BASIC_ATTR_ACTION 0x004 46 /** @endcond */ 47 48 static struct nla_policy basic_policy[TCA_BASIC_MAX+1] = { 49 [TCA_BASIC_CLASSID] = { .type = NLA_U32 }, 50 [TCA_BASIC_EMATCHES] = { .type = NLA_NESTED }, 51 }; 52 53 static int basic_clone(void *_dst, void *_src) 54 { 55 return -NLE_OPNOTSUPP; 56 } 57 58 static void basic_free_data(struct rtnl_tc *tc, void *data) 59 { 60 struct rtnl_basic *b = data; 61 62 if (!b) 63 return; 64 65 if (b->b_act) 66 rtnl_act_put_all(&b->b_act); 67 rtnl_ematch_tree_free(b->b_ematch); 68 } 69 70 static int basic_msg_parser(struct rtnl_tc *tc, void *data) 71 { 72 struct nlattr *tb[TCA_BASIC_MAX + 1]; 73 struct rtnl_basic *b = data; 74 int err; 75 76 err = tca_parse(tb, TCA_BASIC_MAX, tc, basic_policy); 77 if (err < 0) 78 return err; 79 80 if (tb[TCA_BASIC_CLASSID]) { 81 b->b_target = nla_get_u32(tb[TCA_BASIC_CLASSID]); 82 b->b_mask |= BASIC_ATTR_TARGET; 83 } 84 85 if (tb[TCA_BASIC_EMATCHES]) { 86 if ((err = rtnl_ematch_parse_attr(tb[TCA_BASIC_EMATCHES], 87 &b->b_ematch)) < 0) 88 return err; 89 90 if (b->b_ematch) 91 b->b_mask |= BASIC_ATTR_EMATCH; 92 } 93 if (tb[TCA_BASIC_ACT]) { 94 b->b_mask |= BASIC_ATTR_ACTION; 95 err = rtnl_act_parse(&b->b_act, tb[TCA_BASIC_ACT]); 96 if (err) 97 return err; 98 } 99 100 return 0; 101 } 102 103 static void basic_dump_line(struct rtnl_tc *tc, void *data, 104 struct nl_dump_params *p) 105 { 106 struct rtnl_basic *b = data; 107 char buf[32]; 108 109 if (!b) 110 return; 111 112 if (b->b_mask & BASIC_ATTR_EMATCH) 113 nl_dump(p, " ematch"); 114 else 115 nl_dump(p, " match-all"); 116 117 if (b->b_mask & BASIC_ATTR_TARGET) 118 nl_dump(p, " target %s", 119 rtnl_tc_handle2str(b->b_target, buf, sizeof(buf))); 120 } 121 122 static void basic_dump_details(struct rtnl_tc *tc, void *data, 123 struct nl_dump_params *p) 124 { 125 struct rtnl_basic *b = data; 126 127 if (!b) 128 return; 129 130 if (b->b_mask & BASIC_ATTR_EMATCH) { 131 nl_dump_line(p, " ematch "); 132 rtnl_ematch_tree_dump(b->b_ematch, p); 133 } else 134 nl_dump(p, "no options.\n"); 135 } 136 137 static int basic_msg_fill(struct rtnl_tc *tc, void *data, 138 struct nl_msg *msg) 139 { 140 struct rtnl_basic *b = data; 141 142 if (!b) 143 return 0; 144 145 if (b->b_mask & BASIC_ATTR_TARGET) 146 NLA_PUT_U32(msg, TCA_BASIC_CLASSID, b->b_target); 147 148 if (b->b_mask & BASIC_ATTR_EMATCH && 149 rtnl_ematch_fill_attr(msg, TCA_BASIC_EMATCHES, b->b_ematch) < 0) 150 goto nla_put_failure; 151 152 if (b->b_mask & BASIC_ATTR_ACTION) { 153 int err; 154 155 err = rtnl_act_fill(msg, TCA_BASIC_ACT, b->b_act); 156 if (err) 157 return err; 158 } 159 160 return 0; 161 162 nla_put_failure: 163 return -NLE_NOMEM; 164 } 165 166 /** 167 * @name Attribute Modifications 168 * @{ 169 */ 170 171 void rtnl_basic_set_target(struct rtnl_cls *cls, uint32_t target) 172 { 173 struct rtnl_basic *b; 174 175 if (!(b = rtnl_tc_data(TC_CAST(cls)))) 176 return; 177 178 b->b_target = target; 179 b->b_mask |= BASIC_ATTR_TARGET; 180 } 181 182 uint32_t rtnl_basic_get_target(struct rtnl_cls *cls) 183 { 184 struct rtnl_basic *b; 185 186 if (!(b = rtnl_tc_data(TC_CAST(cls)))) 187 return 0; 188 189 return b->b_target; 190 } 191 192 void rtnl_basic_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree) 193 { 194 struct rtnl_basic *b; 195 196 if (!(b = rtnl_tc_data(TC_CAST(cls)))) 197 return; 198 199 if (b->b_ematch) { 200 rtnl_ematch_tree_free(b->b_ematch); 201 b->b_mask &= ~BASIC_ATTR_EMATCH; 202 } 203 204 b->b_ematch = tree; 205 206 if (tree) 207 b->b_mask |= BASIC_ATTR_EMATCH; 208 } 209 210 struct rtnl_ematch_tree *rtnl_basic_get_ematch(struct rtnl_cls *cls) 211 { 212 struct rtnl_basic *b; 213 214 if (!(b = rtnl_tc_data(TC_CAST(cls)))) 215 return NULL; 216 217 return b->b_ematch; 218 } 219 220 int rtnl_basic_add_action(struct rtnl_cls *cls, struct rtnl_act *act) 221 { 222 struct rtnl_basic *b; 223 224 if (!act) 225 return 0; 226 227 if (!(b = rtnl_tc_data(TC_CAST(cls)))) 228 return -NLE_NOMEM; 229 230 b->b_mask |= BASIC_ATTR_ACTION; 231 /* In case user frees it */ 232 rtnl_act_get(act); 233 return rtnl_act_append(&b->b_act, act); 234 } 235 236 int rtnl_basic_del_action(struct rtnl_cls *cls, struct rtnl_act *act) 237 { 238 struct rtnl_basic *b; 239 int ret; 240 241 if (!act) 242 return 0; 243 244 if (!(b = rtnl_tc_data(TC_CAST(cls)))) 245 return -NLE_NOMEM; 246 247 if (!(b->b_mask & BASIC_ATTR_ACTION)) 248 return -NLE_INVAL; 249 ret = rtnl_act_remove(&b->b_act, act); 250 if (ret) 251 return ret; 252 253 if (!b->b_act) 254 b->b_mask &= ~BASIC_ATTR_ACTION; 255 rtnl_act_put(act); 256 return 0; 257 } 258 /** @} */ 259 260 static struct rtnl_tc_ops basic_ops = { 261 .to_kind = "basic", 262 .to_type = RTNL_TC_TYPE_CLS, 263 .to_size = sizeof(struct rtnl_basic), 264 .to_msg_parser = basic_msg_parser, 265 .to_clone = basic_clone, 266 .to_free_data = basic_free_data, 267 .to_msg_fill = basic_msg_fill, 268 .to_dump = { 269 [NL_DUMP_LINE] = basic_dump_line, 270 [NL_DUMP_DETAILS] = basic_dump_details, 271 }, 272 }; 273 274 static void __init basic_init(void) 275 { 276 rtnl_tc_register(&basic_ops); 277 } 278 279 static void __exit basic_exit(void) 280 { 281 rtnl_tc_unregister(&basic_ops); 282 } 283 284 /** @} */ 285