26731bb20d1f130f3ab97ad0ecbccddaf1e6abcf
[linux-2.6.git] / kernel / ckrm / ckrm_sockc.c
1 /* ckrm_sock.c - Class-based Kernel Resource Management (CKRM)
2  *
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
7  * 
8  * 
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.
12  *
13  * Latest version, more details at http://ckrm.sf.net
14  * 
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.
19  *
20  */
21
22 /* Changes
23  *
24  * 28 Aug 2003
25  *        Created.
26  * 06 Nov 2003
27  *        Made modifications to suit the new RBCE module.
28  * 10 Nov 2003
29  *        Fixed a bug in fork and exit callbacks. Added callbacks_active and
30  *        surrounding logic. Added task paramter for all CE callbacks.
31  * 23 Mar 2004
32  *        moved to referenced counted class objects and correct locking
33  * 12 Apr 2004
34  *        introduced adopted to emerging classtype interface
35  */
36
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>
43 #include <linux/mm.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>
51 #include <net/tcp.h>
52
53 #include <linux/ckrm_net.h>
54
55 struct ckrm_sock_class {
56         struct ckrm_core_class core;
57 };
58
59 static struct ckrm_sock_class  sockclass_dflt_class = {
60 };
61
62 #define SOCKET_CLASS_TYPE_NAME  "socket_class"
63
64 const char *dflt_sockclass_name = SOCKET_CLASS_TYPE_NAME;
65
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);
68
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);
73
74 struct ckrm_classtype CT_sockclass = {
75         .mfidx          = 1,
76         .name           = SOCKET_CLASS_TYPE_NAME,
77         .typeID         = CKRM_CLASSTYPE_SOCKET_CLASS, 
78         .maxdepth       = 3,                           
79         .resid_reserved = 0,                           
80         .max_res_ctlrs  = CKRM_MAX_RES_CTLRS,        
81         .max_resid      = 0,
82         .bit_res_ctlrs  = 0L,
83         .res_ctlrs_lock = SPIN_LOCK_UNLOCKED,
84         .classes        = LIST_HEAD_INIT(CT_sockclass.classes),
85
86         .default_class  = &sockclass_dflt_class.core,
87         
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,
93
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,
101
102         // mandatory private version .. no dflt available
103         .add_resctrl    = &sock_add_resctrl,    
104 };
105
106 /* helper functions */
107
108 void
109 ckrm_ns_hold(struct ckrm_net_struct *ns)
110 {
111         atomic_inc(&ns->ns_refcnt);
112         return;
113 }
114
115 void
116 ckrm_ns_put(struct ckrm_net_struct *ns)
117 {
118         if (atomic_dec_and_test(&ns->ns_refcnt))
119                 kfree(ns);
120
121         return;
122 }
123 /*
124  * Change the class of a netstruct 
125  *
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.
128  *
129  */
130
131 static void
132 sock_set_class(struct ckrm_net_struct *ns, struct ckrm_sock_class *newcls,
133               struct ckrm_sock_class *oldcls, enum ckrm_event event)
134 {
135         int i;
136         struct ckrm_res_ctlr *rcbs;
137         struct ckrm_classtype *clstype;
138         void  *old_res_class, *new_res_class;
139
140         if ((newcls == oldcls) || (newcls == NULL)) {
141                 ns->core = (void *)oldcls;
142                 return;
143         }
144
145         class_lock(class_core(newcls));
146         ns->core = newcls;
147         list_add(&ns->ckrm_link, &class_core(newcls)->objlist);
148         class_unlock(class_core(newcls));
149
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]);
159         }
160         return;
161 }
162
163 static void
164 sock_add_resctrl(struct ckrm_core_class *core, int resid)
165 {
166         struct ckrm_net_struct *ns;
167         struct ckrm_res_ctlr *rcbs;
168
169         if ((resid < 0) || (resid >= CKRM_MAX_RES_CTLRS) || ((rcbs = core->classtype->res_ctlrs[resid]) == NULL)) 
170                 return;
171
172         class_lock(core);
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]);
176         }
177         class_unlock(core);
178 }
179
180
181 /**************************************************************************
182  *                   Functions called from classification points          *
183  **************************************************************************/
184
185 static void
186 cb_sockclass_listen_start(struct sock *sk)
187 {
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;
192         int i = 0;
193
194         // XXX - TBD ipv6
195         if (sk->sk_family == IPPROTO_IPV6)
196                 return;
197
198         // to store the socket address
199         ns = (struct ckrm_net_struct *)
200                 kmalloc(sizeof(struct ckrm_net_struct), GFP_ATOMIC);
201         if (!ns)
202                 return;
203
204         memset(ns,0, sizeof(ns));
205         INIT_LIST_HEAD(&ns->ckrm_link);
206
207         ns->ns_family = sk->sk_family;
208         if (ns->ns_family == IPPROTO_IPV6)      // IPv6 not supported yet.
209                 return;
210
211         ns->ns_daddrv4 = inet_sk(sk)->rcv_saddr;
212         ns->ns_dport = inet_sk(sk)->num;
213                 
214         ns->ns_pid = current->pid;
215         ns->ns_tgid = current->tgid;
216
217         ce_protect(&CT_sockclass);
218         CE_CLASSIFY_RET(newcls,&CT_sockclass,CKRM_EVENT_LISTEN_START,ns,current);
219         ce_release(&CT_sockclass);
220
221         if (newcls == NULL)  {
222                 newcls = &sockclass_dflt_class;
223                 ckrm_core_grab(class_core(newcls));
224         }
225
226         class_lock(class_core(newcls));
227         list_add(&ns->ckrm_link, &class_core(newcls)->objlist);
228         ckrm_ns_put(ns);
229         ns->core = newcls;
230         class_unlock(class_core(newcls));
231         
232
233         // the socket is already locked
234         // take a reference on socket on our behalf
235         sock_hold(sk);
236         sk->sk_ns = (void *)ns;
237         ns->ns_sk = sk;
238
239         // modify its shares
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]);
247                 }
248                 atomic_dec(&clstype->nr_resusers[i]);
249         }
250         return;
251 }
252
253 static void
254 cb_sockclass_listen_stop(struct sock *sk)
255 {
256         struct ckrm_net_struct *ns = NULL;
257         struct ckrm_sock_class *newcls = NULL;
258
259         // XXX - TBD ipv6
260         if (sk->sk_family == IPPROTO_IPV6)
261                 return;
262
263         ns =  (struct ckrm_net_struct *)sk->sk_ns;
264         if (!ns) // listen_start called before socket_aq was loaded
265                 return;
266
267         newcls = ns->core;
268         if (newcls) {
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));
274         }
275
276         // the socket is already locked
277         sk->sk_ns = NULL;
278         sock_put(sk);
279
280         // Should be the last count and free it
281         ckrm_ns_put(ns);
282         return;
283 }
284
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  ),
288         { -1 }
289 };
290
291 /**************************************************************************
292  *                  Class Object Creation / Destruction
293  **************************************************************************/
294
295 static struct ckrm_core_class *
296 sock_alloc_class(struct ckrm_core_class *parent, const char *name)
297 {
298         struct ckrm_sock_class *sockcls;
299         sockcls = kmalloc(sizeof(struct ckrm_sock_class), GFP_KERNEL);
300         if (sockcls == NULL) 
301                 return NULL;
302
303         ckrm_init_core_class(&CT_sockclass,class_core(sockcls),parent,name);
304
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);
309
310         return class_core(sockcls);
311 }
312
313 static int
314 sock_free_class(struct ckrm_core_class *core)
315 {
316         struct ckrm_sock_class *sockcls;
317
318         if (!ckrm_is_core_valid(core)) {
319                 // Invalid core
320                 return (-EINVAL);
321         }
322         if (core == core->classtype->default_class) {
323                 // reset the name tag
324                 core->name = dflt_sockclass_name;
325                 return 0;
326         }
327
328         sockcls = class_type(struct ckrm_sock_class, core);
329
330         ce_protect(&CT_sockclass);
331
332         if (CT_sockclass.ce_cb_active && CT_sockclass.ce_callbacks.class_delete)
333                 (*CT_sockclass.ce_callbacks.class_delete)(core->name,sockcls);
334
335         sock_reclassify_class ( sockcls );
336
337         ce_release(&CT_sockclass);
338
339         ckrm_release_core_class(core);  // Hubertus .... could just drop the class .. error message
340         return 0;
341 }
342
343
344 static int                      
345 sock_show_members(struct ckrm_core_class *core, struct seq_file *seq) 
346 {
347         struct list_head *lh;
348         struct ckrm_net_struct *ns = NULL;
349
350         class_lock(core);
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);
355         }
356         class_unlock(core);
357
358         return 0;
359 }
360
361 static int
362 sock_forced_reclassify_ns(struct ckrm_net_struct *tns, struct ckrm_core_class *core)
363 {
364         struct ckrm_net_struct *ns = NULL;
365         struct sock *sk = NULL;
366         struct ckrm_sock_class *oldcls, *newcls;
367         int rc = -EINVAL;
368
369         if (!ckrm_is_core_valid(core)) {
370                 return rc;
371         }
372
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);
377         if (!sk) {
378                 printk(KERN_INFO "No such listener 0x%x:%d\n",
379                                 tns->ns_daddrv4, tns->ns_dport);
380                 return rc;
381         }
382         lock_sock(sk);
383         if (!sk->sk_ns) {
384                 goto out;
385         }
386         ns = sk->sk_ns;
387         ckrm_ns_hold(ns);
388         oldcls = ns->core;
389         if ((oldcls == NULL) || (oldcls == newcls)) {
390                 ckrm_ns_put(ns);
391                 goto out;
392         }
393
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);
398         ns->core = NULL;
399         class_unlock(class_core(oldcls));
400
401         sock_set_class(ns, newcls, oldcls, CKRM_EVENT_MANUAL);
402         ckrm_ns_put(ns);
403         rc = 0;
404 out:
405         release_sock(sk);
406         sock_put(sk);
407
408         return rc;
409
410
411
412 enum sock_target_token_t {
413         IPV4, IPV6, SOCKC_TARGET_ERR
414 };
415
416 static match_table_t sock_target_tokens = {
417         {IPV4, "ipv4=%s"},
418         {IPV6, "ipv6=%s"},
419         {SOCKC_TARGET_ERR, NULL},
420 };
421
422 char *
423 v4toi(char *s, char c, __u32 *v)
424 {
425         unsigned int  k = 0, n = 0;
426
427         while(*s && (*s != c)) {
428                 if (*s == '.') {
429                         n <<= 8;
430                         n |= k;
431                         k = 0;
432                 }
433                 else 
434                         k = k *10 + *s - '0';
435                 s++;
436         }
437
438         n <<= 8;
439         *v = n | k;
440
441         return s;
442 }
443
444 static int
445 sock_forced_reclassify(struct ckrm_core_class *target,const char *options)
446 {       
447         char *p,*p2;
448         struct ckrm_net_struct ns;
449         __u32 v4addr, tmp;
450
451         if (!options)
452                 return 1;
453         
454         while ((p = strsep((char**)&options, ",")) != NULL) {
455                 substring_t args[MAX_OPT_ARGS];
456                 int token;
457                 
458                 if (!*p)
459                         continue;
460                 token = match_token(p, sock_target_tokens, args);
461                 switch (token) {
462
463                 case IPV4:
464
465                         p2 = p;
466                         while(*p2 && (*p2 != '='))
467                                 ++p2;
468                         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);
474                         
475                         sock_forced_reclassify_ns(&ns,target);
476                         break;
477
478                 case IPV6:
479                         printk(KERN_INFO "rcfs: IPV6 not supported yet\n");
480                         return 0;       
481                 default:
482                         return 0;
483                 }
484         }
485         return 1;
486 }       
487
488 /*
489  * Listen_aq reclassification.
490  */
491 static void
492 sock_reclassify_class(struct ckrm_sock_class *cls)
493 {
494         struct ckrm_net_struct *ns, *tns;
495         struct ckrm_core_class *core = class_core(cls);
496         LIST_HEAD(local_list);
497
498         if (!cls)
499                 return;
500
501         if (!ckrm_validate_and_grab_core(core))
502                 return;
503
504         class_lock(core);
505         // we have the core refcnt
506         if (list_empty(&core->objlist)) {
507                 class_unlock(core);
508                 ckrm_core_drop(core);
509                 return;
510         }
511
512         INIT_LIST_HEAD(&local_list);
513         list_splice_init(&core->objlist, &local_list);
514         class_unlock(core);
515         ckrm_core_drop(core);
516         
517         list_for_each_entry_safe(ns, tns, &local_list, ckrm_link) {
518                 ckrm_ns_hold(ns);
519                 list_del(&ns->ckrm_link);
520                 if (ns->ns_sk) {
521                         lock_sock(ns->ns_sk);
522                         sock_set_class(ns, &sockclass_dflt_class, NULL, CKRM_EVENT_MANUAL);
523                         release_sock(ns->ns_sk);
524                 }
525                 ckrm_ns_put(ns);
526         }
527         return ;
528 }
529
530 void __init
531 ckrm_meta_init_sockclass(void)
532 {
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);
537
538         // register classtype and initialize default task class
539         ckrm_register_classtype(&CT_sockclass);
540         ckrm_register_event_set(sock_events_callbacks);
541
542         // note registeration of all resource controllers will be done later dynamically 
543         // as these are specified as modules
544 }
545
546
547
548 #if 1
549
550 /***************************************************************************************
551  * Debugging Network Classes:  Utility functions
552  **************************************************************************************/
553
554 #endif