1 /* ckrm_sock.c - Class-based Kernel Resource Management (CKRM)
3 * Copyright (C) Hubertus Franke, IBM Corp. 2003,2004
4 * (C) Shailabh Nagar, IBM Corp. 2003
5 * (C) Chandra Seetharaman, IBM Corp. 2003
6 * (C) Vivek Kashyap, IBM Corp. 2004
9 * Provides kernel API of CKRM for in-kernel,per-resource controllers
10 * (one each for cpu, memory, io, network) and callbacks for
11 * classification modules.
13 * Latest version, more details at http://ckrm.sf.net
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
27 * Made modifications to suit the new RBCE module.
29 * Fixed a bug in fork and exit callbacks. Added callbacks_active and
30 * surrounding logic. Added task paramter for all CE callbacks.
32 * moved to referenced counted class objects and correct locking
34 * introduced adopted to emerging classtype interface
37 #include <linux/config.h>
38 #include <linux/init.h>
39 #include <linux/linkage.h>
40 #include <linux/kernel.h>
41 #include <linux/errno.h>
42 #include <asm/uaccess.h>
44 #include <asm/errno.h>
45 #include <linux/string.h>
46 #include <linux/list.h>
47 #include <linux/spinlock.h>
48 #include <linux/module.h>
49 #include <linux/ckrm_rc.h>
50 #include <linux/parser.h>
53 #include <linux/ckrm_net.h>
55 struct ckrm_sock_class {
56 struct ckrm_core_class core;
59 static struct ckrm_sock_class sockclass_dflt_class = {
62 #define SOCKET_CLASS_TYPE_NAME "socketclass"
64 const char *dflt_sockclass_name = SOCKET_CLASS_TYPE_NAME;
66 static struct ckrm_core_class *sock_alloc_class(struct ckrm_core_class *parent,
68 static int sock_free_class(struct ckrm_core_class *core);
70 static int sock_forced_reclassify(ckrm_core_class_t * target,
72 static int sock_show_members(struct ckrm_core_class *core,
73 struct seq_file *seq);
74 static void sock_add_resctrl(struct ckrm_core_class *core, int resid);
75 static void sock_reclassify_class(struct ckrm_sock_class *cls);
77 struct ckrm_classtype CT_sockclass = {
79 .name = SOCKET_CLASS_TYPE_NAME,
80 .typeID = CKRM_CLASSTYPE_SOCKET_CLASS,
83 .max_res_ctlrs = CKRM_MAX_RES_CTLRS,
86 .res_ctlrs_lock = SPIN_LOCK_UNLOCKED,
87 .classes = LIST_HEAD_INIT(CT_sockclass.classes),
89 .default_class = &sockclass_dflt_class.core,
91 // private version of functions
92 .alloc = &sock_alloc_class,
93 .free = &sock_free_class,
94 .show_members = &sock_show_members,
95 .forced_reclassify = &sock_forced_reclassify,
97 // use of default functions
98 .show_shares = &ckrm_class_show_shares,
99 .show_stats = &ckrm_class_show_stats,
100 .show_config = &ckrm_class_show_config,
101 .set_config = &ckrm_class_set_config,
102 .set_shares = &ckrm_class_set_shares,
103 .reset_stats = &ckrm_class_reset_stats,
105 // mandatory private version .. no dflt available
106 .add_resctrl = &sock_add_resctrl,
109 /* helper functions */
111 void ckrm_ns_hold(struct ckrm_net_struct *ns)
113 atomic_inc(&ns->ns_refcnt);
117 void ckrm_ns_put(struct ckrm_net_struct *ns)
119 if (atomic_dec_and_test(&ns->ns_refcnt))
125 * Change the class of a netstruct
127 * Change the task's task class to "newcls" if the task's current
128 * class (task->taskclass) is same as given "oldcls", if it is non-NULL.
133 sock_set_class(struct ckrm_net_struct *ns, struct ckrm_sock_class *newcls,
134 struct ckrm_sock_class *oldcls, enum ckrm_event event)
137 struct ckrm_res_ctlr *rcbs;
138 struct ckrm_classtype *clstype;
139 void *old_res_class, *new_res_class;
141 if ((newcls == oldcls) || (newcls == NULL)) {
142 ns->core = (void *)oldcls;
146 class_lock(class_core(newcls));
148 list_add(&ns->ckrm_link, &class_core(newcls)->objlist);
149 class_unlock(class_core(newcls));
151 clstype = class_isa(newcls);
152 for (i = 0; i < clstype->max_resid; i++) {
153 atomic_inc(&clstype->nr_resusers[i]);
155 oldcls ? class_core(oldcls)->res_class[i] : NULL;
157 newcls ? class_core(newcls)->res_class[i] : NULL;
158 rcbs = clstype->res_ctlrs[i];
159 if (rcbs && rcbs->change_resclass
160 && (old_res_class != new_res_class))
161 (*rcbs->change_resclass) (ns, old_res_class,
163 atomic_dec(&clstype->nr_resusers[i]);
168 static void sock_add_resctrl(struct ckrm_core_class *core, int resid)
170 struct ckrm_net_struct *ns;
171 struct ckrm_res_ctlr *rcbs;
173 if ((resid < 0) || (resid >= CKRM_MAX_RES_CTLRS)
174 || ((rcbs = core->classtype->res_ctlrs[resid]) == NULL))
178 list_for_each_entry(ns, &core->objlist, ckrm_link) {
179 if (rcbs->change_resclass)
180 (*rcbs->change_resclass) (ns, NULL,
181 core->res_class[resid]);
186 /**************************************************************************
187 * Functions called from classification points *
188 **************************************************************************/
190 static void cb_sockclass_listen_start(struct sock *sk)
192 struct ckrm_net_struct *ns = NULL;
193 struct ckrm_sock_class *newcls = NULL;
194 struct ckrm_res_ctlr *rcbs;
195 struct ckrm_classtype *clstype;
199 if (sk->sk_family == AF_INET6)
202 // to store the socket address
203 ns = (struct ckrm_net_struct *)
204 kmalloc(sizeof(struct ckrm_net_struct), GFP_ATOMIC);
208 memset(ns, 0, sizeof(*ns));
209 INIT_LIST_HEAD(&ns->ckrm_link);
212 ns->ns_family = sk->sk_family;
213 if (ns->ns_family == AF_INET6) // IPv6 not supported yet.
216 ns->ns_daddrv4 = inet_sk(sk)->rcv_saddr;
217 ns->ns_dport = inet_sk(sk)->num;
219 ns->ns_pid = current->pid;
220 ns->ns_tgid = current->tgid;
221 ns->ns_tsk = current;
222 ce_protect(&CT_sockclass);
223 CE_CLASSIFY_RET(newcls, &CT_sockclass, CKRM_EVENT_LISTEN_START, ns,
225 ce_release(&CT_sockclass);
227 if (newcls == NULL) {
228 newcls = &sockclass_dflt_class;
229 ckrm_core_grab(class_core(newcls));
232 class_lock(class_core(newcls));
233 list_add(&ns->ckrm_link, &class_core(newcls)->objlist);
235 class_unlock(class_core(newcls));
237 // the socket is already locked
238 // take a reference on socket on our behalf
240 sk->sk_ns = (void *)ns;
244 clstype = class_isa(newcls);
245 for (i = 0; i < clstype->max_resid; i++) {
246 atomic_inc(&clstype->nr_resusers[i]);
247 rcbs = clstype->res_ctlrs[i];
248 if (rcbs && rcbs->change_resclass) {
249 (*rcbs->change_resclass) ((void *)ns,
254 atomic_dec(&clstype->nr_resusers[i]);
259 static void cb_sockclass_listen_stop(struct sock *sk)
261 struct ckrm_net_struct *ns = NULL;
262 struct ckrm_sock_class *newcls = NULL;
265 if (sk->sk_family == AF_INET6)
268 ns = (struct ckrm_net_struct *)sk->sk_ns;
269 if (!ns) // listen_start called before socket_aq was loaded
274 class_lock(class_core(newcls));
275 list_del(&ns->ckrm_link);
276 INIT_LIST_HEAD(&ns->ckrm_link);
277 class_unlock(class_core(newcls));
278 ckrm_core_drop(class_core(newcls));
280 // the socket is already locked
284 // Should be the last count and free it
289 static struct ckrm_event_spec sock_events_callbacks[] = {
290 CKRM_EVENT_SPEC(LISTEN_START, cb_sockclass_listen_start),
291 CKRM_EVENT_SPEC(LISTEN_STOP, cb_sockclass_listen_stop),
295 /**************************************************************************
296 * Class Object Creation / Destruction
297 **************************************************************************/
299 static struct ckrm_core_class *sock_alloc_class(struct ckrm_core_class *parent,
302 struct ckrm_sock_class *sockcls;
303 sockcls = kmalloc(sizeof(struct ckrm_sock_class), GFP_KERNEL);
306 memset(sockcls, 0, sizeof(struct ckrm_sock_class));
308 ckrm_init_core_class(&CT_sockclass, class_core(sockcls), parent, name);
310 ce_protect(&CT_sockclass);
311 if (CT_sockclass.ce_cb_active && CT_sockclass.ce_callbacks.class_add)
312 (*CT_sockclass.ce_callbacks.class_add) (name, sockcls,
313 CT_sockclass.typeID);
314 ce_release(&CT_sockclass);
316 return class_core(sockcls);
319 static int sock_free_class(struct ckrm_core_class *core)
321 struct ckrm_sock_class *sockcls;
323 if (!ckrm_is_core_valid(core)) {
327 if (core == core->classtype->default_class) {
328 // reset the name tag
329 core->name = dflt_sockclass_name;
333 sockcls = class_type(struct ckrm_sock_class, core);
335 ce_protect(&CT_sockclass);
337 if (CT_sockclass.ce_cb_active && CT_sockclass.ce_callbacks.class_delete)
338 (*CT_sockclass.ce_callbacks.class_delete) (core->name, sockcls,
339 CT_sockclass.typeID);
341 sock_reclassify_class(sockcls);
343 ce_release(&CT_sockclass);
345 ckrm_release_core_class(core);
346 // Hubertus .... could just drop the class .. error message
351 static int sock_show_members(struct ckrm_core_class *core, struct seq_file *seq)
353 struct list_head *lh;
354 struct ckrm_net_struct *ns = NULL;
357 list_for_each(lh, &core->objlist) {
358 ns = container_of(lh, struct ckrm_net_struct, ckrm_link);
359 seq_printf(seq, "%d.%d.%d.%d\\%d\n",
360 NIPQUAD(ns->ns_daddrv4), ns->ns_dport);
368 sock_forced_reclassify_ns(struct ckrm_net_struct *tns,
369 struct ckrm_core_class *core)
371 struct ckrm_net_struct *ns = NULL;
372 struct sock *sk = NULL;
373 struct ckrm_sock_class *oldcls, *newcls;
376 if (!ckrm_is_core_valid(core)) {
380 newcls = class_type(struct ckrm_sock_class, core);
381 // lookup the listening sockets
382 // returns with a reference count set on socket
383 if (tns->ns_family == AF_INET6)
386 sk = tcp_v4_lookup_listener(tns->ns_daddrv4, tns->ns_dport, 0);
388 printk(KERN_INFO "No such listener 0x%x:%d\n",
389 tns->ns_daddrv4, tns->ns_dport);
398 if (!capable(CAP_NET_ADMIN) && (ns->ns_tsk->user != current->user)) {
405 if ((oldcls == NULL) || (oldcls == newcls)) {
409 // remove the net_struct from the current class
410 class_lock(class_core(oldcls));
411 list_del(&ns->ckrm_link);
412 INIT_LIST_HEAD(&ns->ckrm_link);
414 class_unlock(class_core(oldcls));
416 sock_set_class(ns, newcls, oldcls, CKRM_EVENT_MANUAL);
427 enum sock_target_token_t {
428 IPV4, IPV6, SOCKC_TARGET_ERR
431 static match_table_t sock_target_tokens = {
434 {SOCKC_TARGET_ERR, NULL},
437 char *v4toi(char *s, char c, __u32 * v)
439 unsigned int k = 0, n = 0;
441 while (*s && (*s != c)) {
447 k = k * 10 + *s - '0';
458 sock_forced_reclassify(struct ckrm_core_class *target, const char *options)
461 struct ckrm_net_struct ns;
467 if (target == NULL) {
468 unsigned long id = simple_strtol(options,NULL,0);
469 if (!capable(CAP_NET_ADMIN))
473 printk("sock_class: reclassify all not net implemented\n");
477 while ((p = strsep((char **)&options, ",")) != NULL) {
478 substring_t args[MAX_OPT_ARGS];
483 token = match_token(p, sock_target_tokens, args);
489 while (*p2 && (*p2 != '='))
492 p2 = v4toi(p2, '\\', &(v4addr));
493 ns.ns_daddrv4 = htonl(v4addr);
494 ns.ns_family = AF_INET;
495 p2 = v4toi(++p2, ':', &tmp);
496 ns.ns_dport = (__u16) tmp;
498 p2 = v4toi(++p2, '\0', &ns.ns_pid);
499 sock_forced_reclassify_ns(&ns, target);
503 printk(KERN_INFO "rcfs: IPV6 not supported yet\n");
513 * Listen_aq reclassification.
515 static void sock_reclassify_class(struct ckrm_sock_class *cls)
517 struct ckrm_net_struct *ns, *tns;
518 struct ckrm_core_class *core = class_core(cls);
519 LIST_HEAD(local_list);
524 if (!ckrm_validate_and_grab_core(core))
528 // we have the core refcnt
529 if (list_empty(&core->objlist)) {
531 ckrm_core_drop(core);
535 INIT_LIST_HEAD(&local_list);
536 list_splice_init(&core->objlist, &local_list);
538 ckrm_core_drop(core);
540 list_for_each_entry_safe(ns, tns, &local_list, ckrm_link) {
542 list_del(&ns->ckrm_link);
544 lock_sock(ns->ns_sk);
545 sock_set_class(ns, &sockclass_dflt_class, NULL,
547 release_sock(ns->ns_sk);
554 void __init ckrm_meta_init_sockclass(void)
556 printk("...... Initializing ClassType<%s> ........\n",
558 // intialize the default class
559 ckrm_init_core_class(&CT_sockclass, class_core(&sockclass_dflt_class),
560 NULL, dflt_sockclass_name);
562 // register classtype and initialize default task class
563 ckrm_register_classtype(&CT_sockclass);
564 ckrm_register_event_set(sock_events_callbacks);
566 // note registeration of all resource controllers will be done
567 // later dynamically as these are specified as modules
572 /*****************************************************************************
573 * Debugging Network Classes: Utility functions
574 *****************************************************************************/