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 "socket_class"
64 const char *dflt_sockclass_name = SOCKET_CLASS_TYPE_NAME;
66 static struct ckrm_core_class *sock_alloc_class(struct ckrm_core_class *parent, const char *name);
67 static int sock_free_class(struct ckrm_core_class *core);
69 static int sock_forced_reclassify(ckrm_core_class_t *target, const char *resname);
70 static int sock_show_members(struct ckrm_core_class *core, struct seq_file *seq);
71 static void sock_add_resctrl(struct ckrm_core_class *core, int resid);
72 static void sock_reclassify_class(struct ckrm_sock_class *cls);
74 struct ckrm_classtype CT_sockclass = {
76 .name = SOCKET_CLASS_TYPE_NAME,
77 .typeID = CKRM_CLASSTYPE_SOCKET_CLASS,
80 .max_res_ctlrs = CKRM_MAX_RES_CTLRS,
83 .res_ctlrs_lock = SPIN_LOCK_UNLOCKED,
84 .classes = LIST_HEAD_INIT(CT_sockclass.classes),
86 .default_class = &sockclass_dflt_class.core,
88 // private version of functions
89 .alloc = &sock_alloc_class,
90 .free = &sock_free_class,
91 .show_members = &sock_show_members,
92 .forced_reclassify = &sock_forced_reclassify,
94 // use of default functions
95 .show_shares = &ckrm_class_show_shares,
96 .show_stats = &ckrm_class_show_stats,
97 .show_config = &ckrm_class_show_config,
98 .set_config = &ckrm_class_set_config,
99 .set_shares = &ckrm_class_set_shares,
100 .reset_stats = &ckrm_class_reset_stats,
102 // mandatory private version .. no dflt available
103 .add_resctrl = &sock_add_resctrl,
106 /* helper functions */
109 ckrm_ns_hold(struct ckrm_net_struct *ns)
111 atomic_inc(&ns->ns_refcnt);
116 ckrm_ns_put(struct ckrm_net_struct *ns)
118 if (atomic_dec_and_test(&ns->ns_refcnt))
124 * Change the class of a netstruct
126 * Change the task's task class to "newcls" if the task's current
127 * class (task->taskclass) is same as given "oldcls", if it is non-NULL.
132 sock_set_class(struct ckrm_net_struct *ns, struct ckrm_sock_class *newcls,
133 struct ckrm_sock_class *oldcls, enum ckrm_event event)
136 struct ckrm_res_ctlr *rcbs;
137 struct ckrm_classtype *clstype;
138 void *old_res_class, *new_res_class;
140 if ((newcls == oldcls) || (newcls == NULL)) {
141 ns->core = (void *)oldcls;
145 class_lock(class_core(newcls));
147 list_add(&ns->ckrm_link, &class_core(newcls)->objlist);
148 class_unlock(class_core(newcls));
150 clstype = class_isa(newcls);
151 for (i = 0; i < clstype->max_resid; i++) {
152 atomic_inc(&clstype->nr_resusers[i]);
153 old_res_class = oldcls ? class_core(oldcls)->res_class[i] : NULL;
154 new_res_class = newcls ? class_core(newcls)->res_class[i] : NULL;
155 rcbs = clstype->res_ctlrs[i];
156 if (rcbs && rcbs->change_resclass && (old_res_class != new_res_class))
157 (*rcbs->change_resclass)(ns, old_res_class, new_res_class);
158 atomic_dec(&clstype->nr_resusers[i]);
164 sock_add_resctrl(struct ckrm_core_class *core, int resid)
166 struct ckrm_net_struct *ns;
167 struct ckrm_res_ctlr *rcbs;
169 if ((resid < 0) || (resid >= CKRM_MAX_RES_CTLRS) || ((rcbs = core->classtype->res_ctlrs[resid]) == NULL))
173 list_for_each_entry(ns, &core->objlist, ckrm_link) {
174 if (rcbs->change_resclass)
175 (*rcbs->change_resclass)(ns, NULL, core->res_class[resid]);
181 /**************************************************************************
182 * Functions called from classification points *
183 **************************************************************************/
186 cb_sockclass_listen_start(struct sock *sk)
188 struct ckrm_net_struct *ns = NULL;
189 struct ckrm_sock_class *newcls = NULL;
190 struct ckrm_res_ctlr *rcbs;
191 struct ckrm_classtype *clstype;
195 if (sk->sk_family == IPPROTO_IPV6)
198 // to store the socket address
199 ns = (struct ckrm_net_struct *)
200 kmalloc(sizeof(struct ckrm_net_struct), GFP_ATOMIC);
204 memset(ns,0, sizeof(ns));
205 INIT_LIST_HEAD(&ns->ckrm_link);
207 ns->ns_family = sk->sk_family;
208 if (ns->ns_family == IPPROTO_IPV6) // IPv6 not supported yet.
211 ns->ns_daddrv4 = inet_sk(sk)->rcv_saddr;
212 ns->ns_dport = inet_sk(sk)->num;
214 ns->ns_pid = current->pid;
215 ns->ns_tgid = current->tgid;
217 ce_protect(&CT_sockclass);
218 CE_CLASSIFY_RET(newcls,&CT_sockclass,CKRM_EVENT_LISTEN_START,ns,current);
219 ce_release(&CT_sockclass);
221 if (newcls == NULL) {
222 newcls = &sockclass_dflt_class;
223 ckrm_core_grab(class_core(newcls));
226 class_lock(class_core(newcls));
227 list_add(&ns->ckrm_link, &class_core(newcls)->objlist);
230 class_unlock(class_core(newcls));
233 // the socket is already locked
234 // take a reference on socket on our behalf
236 sk->sk_ns = (void *)ns;
240 clstype = class_isa(newcls);
241 for (i = 0; i < clstype->max_resid; i++) {
242 atomic_inc(&clstype->nr_resusers[i]);
243 rcbs = clstype->res_ctlrs[i];
244 if (rcbs && rcbs->change_resclass) {
245 (*rcbs->change_resclass)((void *)ns,
246 NULL,class_core(newcls)->res_class[i]);
248 atomic_dec(&clstype->nr_resusers[i]);
254 cb_sockclass_listen_stop(struct sock *sk)
256 struct ckrm_net_struct *ns = NULL;
257 struct ckrm_sock_class *newcls = NULL;
260 if (sk->sk_family == IPPROTO_IPV6)
263 ns = (struct ckrm_net_struct *)sk->sk_ns;
264 if (!ns) // listen_start called before socket_aq was loaded
269 class_lock(class_core(newcls));
270 list_del(&ns->ckrm_link);
271 INIT_LIST_HEAD(&ns->ckrm_link);
272 class_unlock(class_core(newcls));
273 ckrm_core_drop(class_core(newcls));
276 // the socket is already locked
280 // Should be the last count and free it
285 static struct ckrm_event_spec sock_events_callbacks[] = {
286 CKRM_EVENT_SPEC( LISTEN_START, cb_sockclass_listen_start ),
287 CKRM_EVENT_SPEC( LISTEN_STOP, cb_sockclass_listen_stop ),
291 /**************************************************************************
292 * Class Object Creation / Destruction
293 **************************************************************************/
295 static struct ckrm_core_class *
296 sock_alloc_class(struct ckrm_core_class *parent, const char *name)
298 struct ckrm_sock_class *sockcls;
299 sockcls = kmalloc(sizeof(struct ckrm_sock_class), GFP_KERNEL);
303 ckrm_init_core_class(&CT_sockclass,class_core(sockcls),parent,name);
305 ce_protect(&CT_sockclass);
306 if (CT_sockclass.ce_cb_active && CT_sockclass.ce_callbacks.class_add)
307 (*CT_sockclass.ce_callbacks.class_add)(name,sockcls);
308 ce_release(&CT_sockclass);
310 return class_core(sockcls);
314 sock_free_class(struct ckrm_core_class *core)
316 struct ckrm_sock_class *sockcls;
318 if (!ckrm_is_core_valid(core)) {
322 if (core == core->classtype->default_class) {
323 // reset the name tag
324 core->name = dflt_sockclass_name;
328 sockcls = class_type(struct ckrm_sock_class, core);
330 ce_protect(&CT_sockclass);
332 if (CT_sockclass.ce_cb_active && CT_sockclass.ce_callbacks.class_delete)
333 (*CT_sockclass.ce_callbacks.class_delete)(core->name,sockcls);
335 sock_reclassify_class ( sockcls );
337 ce_release(&CT_sockclass);
339 ckrm_release_core_class(core); // Hubertus .... could just drop the class .. error message
345 sock_show_members(struct ckrm_core_class *core, struct seq_file *seq)
347 struct list_head *lh;
348 struct ckrm_net_struct *ns = NULL;
351 list_for_each(lh, &core->objlist) {
352 ns = container_of(lh, struct ckrm_net_struct,ckrm_link);
353 seq_printf(seq, "%d.%d.%d.%d\\%d\n",
354 NIPQUAD(ns->ns_daddrv4),ns->ns_dport);
362 sock_forced_reclassify_ns(struct ckrm_net_struct *tns, struct ckrm_core_class *core)
364 struct ckrm_net_struct *ns = NULL;
365 struct sock *sk = NULL;
366 struct ckrm_sock_class *oldcls, *newcls;
369 if (!ckrm_is_core_valid(core)) {
373 newcls = class_type(struct ckrm_sock_class, core);
374 // lookup the listening sockets
375 // returns with a reference count set on socket
376 sk = tcp_v4_lookup_listener(tns->ns_daddrv4,tns->ns_dport,0);
378 printk(KERN_INFO "No such listener 0x%x:%d\n",
379 tns->ns_daddrv4, tns->ns_dport);
389 if ((oldcls == NULL) || (oldcls == newcls)) {
394 // remove the net_struct from the current class
395 class_lock(class_core(oldcls));
396 list_del(&ns->ckrm_link);
397 INIT_LIST_HEAD(&ns->ckrm_link);
399 class_unlock(class_core(oldcls));
401 sock_set_class(ns, newcls, oldcls, CKRM_EVENT_MANUAL);
412 enum sock_target_token_t {
413 IPV4, IPV6, SOCKC_TARGET_ERR
416 static match_table_t sock_target_tokens = {
419 {SOCKC_TARGET_ERR, NULL},
423 v4toi(char *s, char c, __u32 *v)
425 unsigned int k = 0, n = 0;
427 while(*s && (*s != c)) {
434 k = k *10 + *s - '0';
445 sock_forced_reclassify(struct ckrm_core_class *target,const char *options)
448 struct ckrm_net_struct ns;
454 while ((p = strsep((char**)&options, ",")) != NULL) {
455 substring_t args[MAX_OPT_ARGS];
460 token = match_token(p, sock_target_tokens, args);
466 while(*p2 && (*p2 != '='))
469 p2 = v4toi(p2, '\\',&(v4addr));
470 ns.ns_daddrv4 = htonl(v4addr);
471 ns.ns_family = 4; //IPPROTO_IPV4
472 p2 = v4toi(++p2, ':',&tmp); ns.ns_dport = (__u16)tmp;
473 p2 = v4toi(++p2,'\0',&ns.ns_pid);
475 sock_forced_reclassify_ns(&ns,target);
479 printk(KERN_INFO "rcfs: IPV6 not supported yet\n");
489 * Listen_aq reclassification.
492 sock_reclassify_class(struct ckrm_sock_class *cls)
494 struct ckrm_net_struct *ns, *tns;
495 struct ckrm_core_class *core = class_core(cls);
496 LIST_HEAD(local_list);
501 if (!ckrm_validate_and_grab_core(core))
505 // we have the core refcnt
506 if (list_empty(&core->objlist)) {
508 ckrm_core_drop(core);
512 INIT_LIST_HEAD(&local_list);
513 list_splice_init(&core->objlist, &local_list);
515 ckrm_core_drop(core);
517 list_for_each_entry_safe(ns, tns, &local_list, ckrm_link) {
519 list_del(&ns->ckrm_link);
521 lock_sock(ns->ns_sk);
522 sock_set_class(ns, &sockclass_dflt_class, NULL, CKRM_EVENT_MANUAL);
523 release_sock(ns->ns_sk);
531 ckrm_meta_init_sockclass(void)
533 printk("...... Initializing ClassType<%s> ........\n",CT_sockclass.name);
534 // intialize the default class
535 ckrm_init_core_class(&CT_sockclass, class_core(&sockclass_dflt_class),
536 NULL,dflt_sockclass_name);
538 // register classtype and initialize default task class
539 ckrm_register_classtype(&CT_sockclass);
540 ckrm_register_event_set(sock_events_callbacks);
542 // note registeration of all resource controllers will be done later dynamically
543 // as these are specified as modules
550 /***************************************************************************************
551 * Debugging Network Classes: Utility functions
552 **************************************************************************************/