lin
2025-04-16 903fc4b2d160641e35840da17820a65baa59dc20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
 * net/core/netclassid_cgroup.c    Classid Cgroupfs Handling
 *
 *        This program is free software; you can redistribute it and/or
 *        modify it under the terms of the GNU General Public License
 *        as published by the Free Software Foundation; either version
 *        2 of the License, or (at your option) any later version.
 *
 * Authors:    Thomas Graf <tgraf@suug.ch>
 */
 
#include <linux/slab.h>
#include <linux/cgroup.h>
#include <linux/fdtable.h>
#include <net/cls_cgroup.h>
#include <net/sock.h>
 
static inline struct cgroup_cls_state *css_cls_state(struct cgroup_subsys_state *css)
{
   return css ? container_of(css, struct cgroup_cls_state, css) : NULL;
}
 
struct cgroup_cls_state *task_cls_state(struct task_struct *p)
{
   return css_cls_state(task_css_check(p, net_cls_cgrp_id,
                       rcu_read_lock_bh_held()));
}
EXPORT_SYMBOL_GPL(task_cls_state);
 
static struct cgroup_subsys_state *
cgrp_css_alloc(struct cgroup_subsys_state *parent_css)
{
   struct cgroup_cls_state *cs;
 
   cs = kzalloc(sizeof(*cs), GFP_KERNEL);
   if (!cs)
       return ERR_PTR(-ENOMEM);
 
   return &cs->css;
}
 
static int cgrp_css_online(struct cgroup_subsys_state *css)
{
   struct cgroup_cls_state *cs = css_cls_state(css);
   struct cgroup_cls_state *parent = css_cls_state(css->parent);
 
   if (parent)
       cs->classid = parent->classid;
 
   return 0;
}
 
static void cgrp_css_free(struct cgroup_subsys_state *css)
{
   kfree(css_cls_state(css));
}
 
static int update_classid_sock(const void *v, struct file *file, unsigned n)
{
   int err;
   struct socket *sock = sock_from_file(file, &err);
 
   if (sock) {
       spin_lock(&cgroup_sk_update_lock);
       sock_cgroup_set_classid(&sock->sk->sk_cgrp_data,
                   (unsigned long)v);
       spin_unlock(&cgroup_sk_update_lock);
   }
   return 0;
}
 
static void cgrp_attach(struct cgroup_taskset *tset)
{
   struct cgroup_subsys_state *css;
   struct task_struct *p;
 
   cgroup_taskset_for_each(p, css, tset) {
       task_lock(p);
       iterate_fd(p->files, 0, update_classid_sock,
              (void *)(unsigned long)css_cls_state(css)->classid);
       task_unlock(p);
   }
}
 
static u64 read_classid(struct cgroup_subsys_state *css, struct cftype *cft)
{
   return css_cls_state(css)->classid;
}
 
static int write_classid(struct cgroup_subsys_state *css, struct cftype *cft,
            u64 value)
{
   struct cgroup_cls_state *cs = css_cls_state(css);
   struct css_task_iter it;
   struct task_struct *p;
 
   cgroup_sk_alloc_disable();
 
   cs->classid = (u32)value;
 
   css_task_iter_start(css, &it);
   while ((p = css_task_iter_next(&it))) {
       task_lock(p);
       iterate_fd(p->files, 0, update_classid_sock,
              (void *)(unsigned long)cs->classid);
       task_unlock(p);
       cond_resched();
   }
   css_task_iter_end(&it);
 
   return 0;
}
 
static struct cftype ss_files[] = {
   {
       .name        = "classid",
       .read_u64    = read_classid,
       .write_u64    = write_classid,
   },
   { }    /* terminate */
};
 
struct cgroup_subsys net_cls_cgrp_subsys = {
   .css_alloc        = cgrp_css_alloc,
   .css_online        = cgrp_css_online,
   .css_free        = cgrp_css_free,
   .attach            = cgrp_attach,
   .legacy_cftypes        = ss_files,
};