1 /* 2 * net/sched/cls_cgroup.c Control Group Classifier 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Thomas Graf <tgraf@suug.ch> 10 */ 11 12 #include <linux/module.h> 13 #include <linux/slab.h> 14 #include <linux/skbuff.h> 15 #include <linux/rcupdate.h> 16 #include <net/rtnetlink.h> 17 #include <net/pkt_cls.h> 18 #include <net/sock.h> 19 #include <net/cls_cgroup.h> 20 21 struct cls_cgroup_head { 22 u32 handle; 23 struct tcf_exts exts; 24 struct tcf_ematch_tree ematches; 25 struct tcf_proto *tp; 26 struct rcu_work rwork; 27 }; 28 29 static int cls_cgroup_classify(struct sk_buff *skb, const struct tcf_proto *tp, 30 struct tcf_result *res) 31 { 32 struct cls_cgroup_head *head = rcu_dereference_bh(tp->root); 33 u32 classid = task_get_classid(skb); 34 35 if (unlikely(!head)) 36 return -1; 37 if (!classid) 38 return -1; 39 if (!tcf_em_tree_match(skb, &head->ematches, NULL)) 40 return -1; 41 42 res->classid = classid; 43 res->class = 0; 44 45 return tcf_exts_exec(skb, &head->exts, res); 46 } 47 48 static void *cls_cgroup_get(struct tcf_proto *tp, u32 handle) 49 { 50 return NULL; 51 } 52 53 static int cls_cgroup_init(struct tcf_proto *tp) 54 { 55 return 0; 56 } 57 58 static const struct nla_policy cgroup_policy[TCA_CGROUP_MAX + 1] = { 59 [TCA_CGROUP_EMATCHES] = { .type = NLA_NESTED }, 60 }; 61 62 static void __cls_cgroup_destroy(struct cls_cgroup_head *head) 63 { 64 tcf_exts_destroy(&head->exts); 65 tcf_em_tree_destroy(&head->ematches); 66 tcf_exts_put_net(&head->exts); 67 kfree(head); 68 } 69 70 static void cls_cgroup_destroy_work(struct work_struct *work) 71 { 72 struct cls_cgroup_head *head = container_of(to_rcu_work(work), 73 struct cls_cgroup_head, 74 rwork); 75 rtnl_lock(); 76 __cls_cgroup_destroy(head); 77 rtnl_unlock(); 78 } 79 80 static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb, 81 struct tcf_proto *tp, unsigned long base, 82 u32 handle, struct nlattr **tca, 83 void **arg, bool ovr, bool rtnl_held, 84 struct netlink_ext_ack *extack) 85 { 86 struct nlattr *tb[TCA_CGROUP_MAX + 1]; 87 struct cls_cgroup_head *head = rtnl_dereference(tp->root); 88 struct cls_cgroup_head *new; 89 int err; 90 91 if (!tca[TCA_OPTIONS]) 92 return -EINVAL; 93 94 if (!head && !handle) 95 return -EINVAL; 96 97 if (head && handle != head->handle) 98 return -ENOENT; 99 100 new = kzalloc(sizeof(*head), GFP_KERNEL); 101 if (!new) 102 return -ENOBUFS; 103 104 err = tcf_exts_init(&new->exts, net, TCA_CGROUP_ACT, TCA_CGROUP_POLICE); 105 if (err < 0) 106 goto errout; 107 new->handle = handle; 108 new->tp = tp; 109 err = nla_parse_nested_deprecated(tb, TCA_CGROUP_MAX, 110 tca[TCA_OPTIONS], cgroup_policy, 111 NULL); 112 if (err < 0) 113 goto errout; 114 115 err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &new->exts, ovr, 116 true, extack); 117 if (err < 0) 118 goto errout; 119 120 err = tcf_em_tree_validate(tp, tb[TCA_CGROUP_EMATCHES], &new->ematches); 121 if (err < 0) 122 goto errout; 123 124 rcu_assign_pointer(tp->root, new); 125 if (head) { 126 tcf_exts_get_net(&head->exts); 127 tcf_queue_work(&head->rwork, cls_cgroup_destroy_work); 128 } 129 return 0; 130 errout: 131 tcf_exts_destroy(&new->exts); 132 kfree(new); 133 return err; 134 } 135 136 static void cls_cgroup_destroy(struct tcf_proto *tp, bool rtnl_held, 137 struct netlink_ext_ack *extack) 138 { 139 struct cls_cgroup_head *head = rtnl_dereference(tp->root); 140 141 /* Head can still be NULL due to cls_cgroup_init(). */ 142 if (head) { 143 if (tcf_exts_get_net(&head->exts)) 144 tcf_queue_work(&head->rwork, cls_cgroup_destroy_work); 145 else 146 __cls_cgroup_destroy(head); 147 } 148 } 149 150 static int cls_cgroup_delete(struct tcf_proto *tp, void *arg, bool *last, 151 bool rtnl_held, struct netlink_ext_ack *extack) 152 { 153 return -EOPNOTSUPP; 154 } 155 156 static void cls_cgroup_walk(struct tcf_proto *tp, struct tcf_walker *arg, 157 bool rtnl_held) 158 { 159 struct cls_cgroup_head *head = rtnl_dereference(tp->root); 160 161 if (arg->count < arg->skip) 162 goto skip; 163 164 if (!head) 165 return; 166 if (arg->fn(tp, head, arg) < 0) { 167 arg->stop = 1; 168 return; 169 } 170 skip: 171 arg->count++; 172 } 173 174 static int cls_cgroup_dump(struct net *net, struct tcf_proto *tp, void *fh, 175 struct sk_buff *skb, struct tcmsg *t, bool rtnl_held) 176 { 177 struct cls_cgroup_head *head = rtnl_dereference(tp->root); 178 struct nlattr *nest; 179 180 t->tcm_handle = head->handle; 181 182 nest = nla_nest_start_noflag(skb, TCA_OPTIONS); 183 if (nest == NULL) 184 goto nla_put_failure; 185 186 if (tcf_exts_dump(skb, &head->exts) < 0 || 187 tcf_em_tree_dump(skb, &head->ematches, TCA_CGROUP_EMATCHES) < 0) 188 goto nla_put_failure; 189 190 nla_nest_end(skb, nest); 191 192 if (tcf_exts_dump_stats(skb, &head->exts) < 0) 193 goto nla_put_failure; 194 195 return skb->len; 196 197 nla_put_failure: 198 nla_nest_cancel(skb, nest); 199 return -1; 200 } 201 202 static struct tcf_proto_ops cls_cgroup_ops __read_mostly = { 203 .kind = "cgroup", 204 .init = cls_cgroup_init, 205 .change = cls_cgroup_change, 206 .classify = cls_cgroup_classify, 207 .destroy = cls_cgroup_destroy, 208 .get = cls_cgroup_get, 209 .delete = cls_cgroup_delete, 210 .walk = cls_cgroup_walk, 211 .dump = cls_cgroup_dump, 212 .owner = THIS_MODULE, 213 }; 214 215 static int __init init_cgroup_cls(void) 216 { 217 return register_tcf_proto_ops(&cls_cgroup_ops); 218 } 219 220 static void __exit exit_cgroup_cls(void) 221 { 222 unregister_tcf_proto_ops(&cls_cgroup_ops); 223 } 224 225 module_init(init_cgroup_cls); 226 module_exit(exit_cgroup_cls); 227 MODULE_LICENSE("GPL"); 228