1 | From: Geliang Tang <tanggeliang@kylinos.cn> | 1 | From: Geliang Tang <tanggeliang@kylinos.cn> |
---|---|---|---|
2 | 2 | ||
3 | Implement address_announced/address_removed/subflow_established/ | ||
4 | subflow_closed interfaces. | ||
5 | |||
3 | Depends on: | 6 | Depends on: |
7 | - BPF path manager, part 4, v5 | ||
8 | Based-on: <cover.1740019794.git.tanggeliang@kylinos.cn> | ||
4 | 9 | ||
5 | - BPF path manager, part 4, v4 | 10 | Geliang Tang (9): |
6 | Based-on: <cover.1738919954.git.tanggeliang@kylinos.cn> | 11 | mptcp: pm: in-kernel: add address_removed/subflow_closed |
12 | mptcp: pm: in-kernel: address_announced interface | ||
13 | mptcp: pm: in-kernel: address_removed interface | ||
14 | mptcp: pm: in-kernel: subflow_established interface | ||
15 | mptcp: pm: in-kernel: subflow_closed interface | ||
16 | mptcp: pm: userspace: address_announced interface | ||
17 | mptcp: pm: userspace: address_removed interface | ||
18 | mptcp: pm: userspace: subflow_established interface | ||
19 | mptcp: pm: userspace: subflow_closed interface | ||
7 | 20 | ||
8 | - add mptcp_address bpf_iter, v5 | 21 | net/mptcp/pm_netlink.c | 115 ++++++++++++++------ |
9 | Based-on: <cover.1738924354.git.tanggeliang@kylinos.cn> | 22 | net/mptcp/pm_userspace.c | 220 +++++++++++++++++++++++---------------- |
10 | 23 | 2 files changed, 215 insertions(+), 120 deletions(-) | |
11 | Geliang Tang (5): | ||
12 | bpf: Add mptcp path manager struct_ops | ||
13 | bpf: Register mptcp struct_ops kfunc set | ||
14 | selftests/bpf: Add mptcp userspace pm subtest | ||
15 | selftests/bpf: Implement mptcp pm helpers in BPF | ||
16 | selftests/bpf: Add mptcp bpf path manager subtest | ||
17 | |||
18 | net/mptcp/bpf.c | 372 +++++++++++++++++- | ||
19 | .../testing/selftests/bpf/prog_tests/mptcp.c | 211 ++++++++++ | ||
20 | tools/testing/selftests/bpf/progs/mptcp_bpf.h | 185 +++++++++ | ||
21 | .../bpf/progs/mptcp_bpf_userspace_pm.c | 275 +++++++++++++ | ||
22 | 4 files changed, 1042 insertions(+), 1 deletion(-) | ||
23 | create mode 100644 tools/testing/selftests/bpf/progs/mptcp_bpf_userspace_pm.c | ||
24 | 24 | ||
25 | -- | 25 | -- |
26 | 2.43.0 | 26 | 2.43.0 | diff view generated by jsdifflib |
1 | From: Geliang Tang <tanggeliang@kylinos.cn> | 1 | From: Geliang Tang <tanggeliang@kylinos.cn> |
---|---|---|---|
2 | 2 | ||
3 | To verify that the behavior of BPF path manager is the same as that of | 3 | This patch defines the code in the loop of traversing all msks in |
4 | userspace pm in the kernel, a userspace pm self-test has been added. | 4 | mptcp_nl_remove_subflow_and_signal_addr() as two new helpers, |
5 | BPF path manager in the next commit will also use this test. | 5 | mptcp_pm_nl_address_removed() and mptcp_pm_nl_subflow_closed(), |
6 | used for signaling a RM_ADDR and closing a subflow respectively. | ||
6 | 7 | ||
7 | Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> | 8 | Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> |
8 | --- | 9 | --- |
9 | .../testing/selftests/bpf/prog_tests/mptcp.c | 160 ++++++++++++++++++ | 10 | net/mptcp/pm_netlink.c | 60 +++++++++++++++++++++++++++--------------- |
10 | 1 file changed, 160 insertions(+) | 11 | 1 file changed, 39 insertions(+), 21 deletions(-) |
11 | 12 | ||
12 | diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c | 13 | diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c |
13 | index XXXXXXX..XXXXXXX 100644 | 14 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c | 15 | --- a/net/mptcp/pm_netlink.c |
15 | +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c | 16 | +++ b/net/mptcp/pm_netlink.c |
16 | @@ -XXX,XX +XXX,XX @@ enum mptcp_pm_type { | 17 | @@ -XXX,XX +XXX,XX @@ static void __mark_subflow_endp_available(struct mptcp_sock *msk, u8 id) |
17 | __MPTCP_PM_TYPE_MAX = __MPTCP_PM_TYPE_NR - 1, | 18 | msk->pm.local_addr_used--; |
18 | }; | 19 | } |
19 | 20 | ||
20 | +enum mptcp_pm_family { | 21 | +static int mptcp_pm_nl_address_removed(struct mptcp_sock *msk, |
21 | + IPV4 = 0, | 22 | + const struct mptcp_pm_addr_entry *local) |
22 | + IPV4MAPPED, | 23 | +{ |
23 | + IPV6, | 24 | + bool remove_subflow; |
24 | +}; | ||
25 | + | 25 | + |
26 | static const unsigned int total_bytes = 10 * 1024 * 1024; | 26 | + remove_subflow = mptcp_lookup_subflow_by_saddr(&msk->conn_list, &local->addr); |
27 | static int duration; | 27 | + mptcp_pm_remove_anno_addr(msk, &local->addr, remove_subflow && |
28 | 28 | + !(local->flags & MPTCP_PM_ADDR_FLAG_IMPLICIT)); | |
29 | @@ -XXX,XX +XXX,XX @@ static void test_iters_address(void) | 29 | + return 0; |
30 | close(cgroup_fd); | ||
31 | } | ||
32 | |||
33 | +static int userspace_pm_add_addr(__u32 token, char *addr, __u8 id) | ||
34 | +{ | ||
35 | + return SYS_NOFAIL("ip netns exec %s %s ann %s id %u token %u", | ||
36 | + NS_TEST, PM_CTL, addr, id, token); | ||
37 | +} | 30 | +} |
38 | + | 31 | + |
39 | +static int userspace_pm_rm_addr(__u32 token, __u8 id) | 32 | +static int mptcp_pm_nl_subflow_closed(struct mptcp_sock *msk, |
33 | + const struct mptcp_pm_addr_entry *local) | ||
40 | +{ | 34 | +{ |
41 | + return SYS_NOFAIL("ip netns exec %s %s rem id %u token %u", | 35 | + struct mptcp_rm_list list = { .nr = 1 }; |
42 | + NS_TEST, PM_CTL, id, token); | 36 | + bool remove_subflow; |
37 | + | ||
38 | + list.ids[0] = mptcp_endp_get_local_id(msk, &local->addr); | ||
39 | + remove_subflow = mptcp_lookup_subflow_by_saddr(&msk->conn_list, &local->addr); | ||
40 | + if (remove_subflow) { | ||
41 | + spin_lock_bh(&msk->pm.lock); | ||
42 | + mptcp_pm_nl_rm_subflow_received(msk, &list); | ||
43 | + spin_unlock_bh(&msk->pm.lock); | ||
44 | + } | ||
45 | + | ||
46 | + if (local->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) { | ||
47 | + spin_lock_bh(&msk->pm.lock); | ||
48 | + __mark_subflow_endp_available(msk, list.ids[0]); | ||
49 | + spin_unlock_bh(&msk->pm.lock); | ||
50 | + } | ||
51 | + | ||
52 | + if (msk->mpc_endpoint_id == local->addr.id) | ||
53 | + msk->mpc_endpoint_id = 0; | ||
54 | + | ||
55 | + return 0; | ||
43 | +} | 56 | +} |
44 | + | 57 | + |
45 | +static int userspace_pm_rm_subflow(__u32 token, char *addr, __u8 id) | 58 | static int mptcp_nl_remove_subflow_and_signal_addr(struct net *net, |
46 | +{ | 59 | const struct mptcp_pm_addr_entry *entry) |
47 | + bool ipv6 = strstr(addr, ":"); | ||
48 | + char line[1024], *str; | ||
49 | + __u32 sport, dport; | ||
50 | + | ||
51 | + if (userspace_pm_get_events_line("type:10", line)) | ||
52 | + return -1; | ||
53 | + | ||
54 | + str = strstr(line, "sport"); | ||
55 | + if (!str || sscanf(str, "sport:%u,dport:%u,", &sport, &dport) != 2) { | ||
56 | + log_err("rm_subflow error, str=%s\n", str); | ||
57 | + return -1; | ||
58 | + } | ||
59 | + | ||
60 | + str = ipv6 ? (strstr(addr, ".") ? "::ffff:"ADDR_1 : ADDR6_1) : ADDR_1; | ||
61 | + return SYS_NOFAIL("ip netns exec %s %s dsf lip %s lport %u rip %s rport %u token %u", | ||
62 | + NS_TEST, PM_CTL, addr, sport, str, dport, token); | ||
63 | +} | ||
64 | + | ||
65 | +static int userspace_pm_set_flags(__u32 token, char *addr, char *flags) | ||
66 | +{ | ||
67 | + bool ipv6 = strstr(addr, ":"); | ||
68 | + char line[1024], *str; | ||
69 | + __u32 sport, dport; | ||
70 | + | ||
71 | + if (userspace_pm_get_events_line("type:10", line)) | ||
72 | + return -1; | ||
73 | + | ||
74 | + str = strstr(line, "sport"); | ||
75 | + if (!str || sscanf(str, "sport:%u,dport:%u,", &sport, &dport) != 2) { | ||
76 | + log_err("set_flags error, str=%s\n", str); | ||
77 | + return -1; | ||
78 | + } | ||
79 | + | ||
80 | + str = ipv6 ? (strstr(addr, ".") ? "::ffff:"ADDR_1 : ADDR6_1) : ADDR_1; | ||
81 | + return SYS_NOFAIL("ip netns exec %s %s set %s port %u rip %s rport %u flags %s token %u", | ||
82 | + NS_TEST, PM_CTL, addr, sport, str, dport, flags, token); | ||
83 | +} | ||
84 | + | ||
85 | +static void run_userspace_pm(enum mptcp_pm_family family) | ||
86 | +{ | ||
87 | + bool ipv4mapped = (family == IPV4MAPPED); | ||
88 | + bool ipv6 = (family == IPV6 || ipv4mapped); | ||
89 | + int server_fd, client_fd, accept_fd; | ||
90 | + __u32 token; | ||
91 | + char *addr; | ||
92 | + int err; | ||
93 | + | ||
94 | + addr = ipv6 ? (ipv4mapped ? "::ffff:"ADDR_1 : ADDR6_1) : ADDR_1; | ||
95 | + server_fd = start_mptcp_server(ipv6 ? AF_INET6 : AF_INET, addr, PORT_1, 0); | ||
96 | + if (!ASSERT_OK_FD(server_fd, "start_mptcp_server")) | ||
97 | + return; | ||
98 | + | ||
99 | + client_fd = connect_to_fd(server_fd, 0); | ||
100 | + if (!ASSERT_OK_FD(client_fd, "connect_to_fd")) | ||
101 | + goto close_server; | ||
102 | + | ||
103 | + accept_fd = accept(server_fd, NULL, NULL); | ||
104 | + if (!ASSERT_OK_FD(accept_fd, "accept")) | ||
105 | + goto close_client; | ||
106 | + | ||
107 | + token = userspace_pm_get_token(client_fd); | ||
108 | + if (!token) | ||
109 | + goto close_client; | ||
110 | + recv_byte(accept_fd); | ||
111 | + usleep(200000); /* 0.2s */ | ||
112 | + | ||
113 | + addr = ipv6 ? (ipv4mapped ? "::ffff:"ADDR_2 : ADDR6_2) : ADDR_2; | ||
114 | + err = userspace_pm_add_subflow(token, addr, 100); | ||
115 | + if (!ASSERT_OK(err, "userspace_pm_add_subflow 100")) | ||
116 | + goto close_accept; | ||
117 | + | ||
118 | + send_byte(accept_fd); | ||
119 | + recv_byte(client_fd); | ||
120 | + | ||
121 | + err = userspace_pm_set_flags(token, addr, "backup"); | ||
122 | + if (!ASSERT_OK(err, "userspace_pm_set_flags backup")) | ||
123 | + goto close_accept; | ||
124 | + | ||
125 | + send_byte(client_fd); | ||
126 | + recv_byte(accept_fd); | ||
127 | + | ||
128 | + err = userspace_pm_set_flags(token, addr, "nobackup"); | ||
129 | + if (!ASSERT_OK(err, "userspace_pm_set_flags nobackup")) | ||
130 | + goto close_accept; | ||
131 | + | ||
132 | + send_byte(accept_fd); | ||
133 | + recv_byte(client_fd); | ||
134 | + | ||
135 | + err = userspace_pm_rm_subflow(token, addr, 100); | ||
136 | + if (!ASSERT_OK(err, "userspace_pm_rm_subflow 100")) | ||
137 | + goto close_accept; | ||
138 | + | ||
139 | + send_byte(client_fd); | ||
140 | + recv_byte(accept_fd); | ||
141 | + | ||
142 | + addr = ipv6 ? (ipv4mapped ? "::ffff:"ADDR_3 : ADDR6_3) : ADDR_3; | ||
143 | + err = userspace_pm_add_addr(token, addr, 200); | ||
144 | + if (!ASSERT_OK(err, "userspace_pm_add_addr 200")) | ||
145 | + goto close_accept; | ||
146 | + | ||
147 | + send_byte(accept_fd); | ||
148 | + recv_byte(client_fd); | ||
149 | + | ||
150 | + err = userspace_pm_rm_addr(token, 200); | ||
151 | + if (!ASSERT_OK(err, "userspace_pm_rm_addr 200")) | ||
152 | + goto close_accept; | ||
153 | + | ||
154 | + send_byte(client_fd); | ||
155 | + recv_byte(accept_fd); | ||
156 | + | ||
157 | +close_accept: | ||
158 | + close(accept_fd); | ||
159 | +close_client: | ||
160 | + close(client_fd); | ||
161 | +close_server: | ||
162 | + close(server_fd); | ||
163 | +} | ||
164 | + | ||
165 | +static void test_userspace_pm(void) | ||
166 | +{ | ||
167 | + struct netns_obj *netns; | ||
168 | + int err; | ||
169 | + | ||
170 | + netns = netns_new(NS_TEST, true); | ||
171 | + if (!ASSERT_OK_PTR(netns, "netns_new")) | ||
172 | + return; | ||
173 | + | ||
174 | + err = userspace_pm_init(MPTCP_PM_TYPE_USERSPACE); | ||
175 | + if (!ASSERT_OK(err, "userspace_pm_init: userspace pm")) | ||
176 | + goto fail; | ||
177 | + | ||
178 | + run_userspace_pm(IPV4MAPPED); | ||
179 | + | ||
180 | + userspace_pm_cleanup(); | ||
181 | +fail: | ||
182 | + netns_free(netns); | ||
183 | +} | ||
184 | + | ||
185 | static struct netns_obj *sched_init(char *flags, char *sched) | ||
186 | { | 60 | { |
187 | struct netns_obj *netns; | 61 | const struct mptcp_addr_info *addr = &entry->addr; |
188 | @@ -XXX,XX +XXX,XX @@ void test_mptcp(void) | 62 | - struct mptcp_rm_list list = { .nr = 1 }; |
189 | test_iters_subflow(); | 63 | long s_slot = 0, s_num = 0; |
190 | if (test__start_subtest("iters_address")) | 64 | struct mptcp_sock *msk; |
191 | test_iters_address(); | 65 | |
192 | + if (test__start_subtest("userspace_pm")) | 66 | @@ -XXX,XX +XXX,XX @@ static int mptcp_nl_remove_subflow_and_signal_addr(struct net *net, |
193 | + test_userspace_pm(); | 67 | |
194 | if (test__start_subtest("default")) | 68 | while ((msk = mptcp_token_iter_next(net, &s_slot, &s_num)) != NULL) { |
195 | test_default(); | 69 | struct sock *sk = (struct sock *)msk; |
196 | if (test__start_subtest("first")) | 70 | - bool remove_subflow; |
71 | |||
72 | if (mptcp_pm_is_userspace(msk)) | ||
73 | goto next; | ||
74 | |||
75 | lock_sock(sk); | ||
76 | - remove_subflow = mptcp_lookup_subflow_by_saddr(&msk->conn_list, addr); | ||
77 | - mptcp_pm_remove_anno_addr(msk, addr, remove_subflow && | ||
78 | - !(entry->flags & MPTCP_PM_ADDR_FLAG_IMPLICIT)); | ||
79 | - | ||
80 | - list.ids[0] = mptcp_endp_get_local_id(msk, addr); | ||
81 | - if (remove_subflow) { | ||
82 | - spin_lock_bh(&msk->pm.lock); | ||
83 | - mptcp_pm_nl_rm_subflow_received(msk, &list); | ||
84 | - spin_unlock_bh(&msk->pm.lock); | ||
85 | - } | ||
86 | - | ||
87 | - if (entry->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) { | ||
88 | - spin_lock_bh(&msk->pm.lock); | ||
89 | - __mark_subflow_endp_available(msk, list.ids[0]); | ||
90 | - spin_unlock_bh(&msk->pm.lock); | ||
91 | - } | ||
92 | - | ||
93 | - if (msk->mpc_endpoint_id == entry->addr.id) | ||
94 | - msk->mpc_endpoint_id = 0; | ||
95 | + mptcp_pm_nl_address_removed(msk, entry); | ||
96 | + mptcp_pm_nl_subflow_closed(msk, entry); | ||
97 | release_sock(sk); | ||
98 | |||
99 | next: | ||
197 | -- | 100 | -- |
198 | 2.43.0 | 101 | 2.43.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Geliang Tang <tanggeliang@kylinos.cn> | ||
1 | 2 | ||
3 | Extract address_announced() interface of the in-kernel netlink PM from | ||
4 | the helper mptcp_nl_add_subflow_or_signal_addr(), only leave the code | ||
5 | for traversing all msk in the helper. | ||
6 | |||
7 | This interface is invoked under holding the msk socket lock. | ||
8 | |||
9 | Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> | ||
10 | --- | ||
11 | net/mptcp/pm_netlink.c | 34 +++++++++++++++++++++++++--------- | ||
12 | 1 file changed, 25 insertions(+), 9 deletions(-) | ||
13 | |||
14 | diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/net/mptcp/pm_netlink.c | ||
17 | +++ b/net/mptcp/pm_netlink.c | ||
18 | @@ -XXX,XX +XXX,XX @@ static struct pm_nl_pernet *genl_info_pm_nl(struct genl_info *info) | ||
19 | return pm_nl_get_pernet(genl_info_net(info)); | ||
20 | } | ||
21 | |||
22 | +static int mptcp_pm_nl_address_announced(struct mptcp_sock *msk, | ||
23 | + struct mptcp_pm_param *param) | ||
24 | +{ | ||
25 | + struct mptcp_addr_info *addr = ¶m->addr; | ||
26 | + struct mptcp_addr_info mpc_addr; | ||
27 | + | ||
28 | + /* if the endp linked to the init sf is re-added with a != ID */ | ||
29 | + mptcp_local_address((struct sock_common *)msk, &mpc_addr); | ||
30 | + | ||
31 | + spin_lock_bh(&msk->pm.lock); | ||
32 | + if (mptcp_addresses_equal(addr, &mpc_addr, addr->port)) | ||
33 | + msk->mpc_endpoint_id = addr->id; | ||
34 | + | ||
35 | + mptcp_pm_create_subflow_or_signal_addr(msk); | ||
36 | + spin_unlock_bh(&msk->pm.lock); | ||
37 | + | ||
38 | + return 0; | ||
39 | +} | ||
40 | + | ||
41 | static int mptcp_nl_add_subflow_or_signal_addr(struct net *net, | ||
42 | struct mptcp_addr_info *addr) | ||
43 | { | ||
44 | @@ -XXX,XX +XXX,XX @@ static int mptcp_nl_add_subflow_or_signal_addr(struct net *net, | ||
45 | |||
46 | while ((msk = mptcp_token_iter_next(net, &s_slot, &s_num)) != NULL) { | ||
47 | struct sock *sk = (struct sock *)msk; | ||
48 | - struct mptcp_addr_info mpc_addr; | ||
49 | + struct mptcp_pm_param param; | ||
50 | |||
51 | if (!READ_ONCE(msk->fully_established) || | ||
52 | mptcp_pm_is_userspace(msk)) | ||
53 | goto next; | ||
54 | |||
55 | - /* if the endp linked to the init sf is re-added with a != ID */ | ||
56 | - mptcp_local_address((struct sock_common *)msk, &mpc_addr); | ||
57 | - | ||
58 | lock_sock(sk); | ||
59 | - spin_lock_bh(&msk->pm.lock); | ||
60 | - if (mptcp_addresses_equal(addr, &mpc_addr, addr->port)) | ||
61 | - msk->mpc_endpoint_id = addr->id; | ||
62 | - mptcp_pm_create_subflow_or_signal_addr(msk); | ||
63 | - spin_unlock_bh(&msk->pm.lock); | ||
64 | + mptcp_pm_param_set_contexts(¶m, NULL, addr); | ||
65 | + msk->pm.ops && msk->pm.ops->address_announced ? | ||
66 | + msk->pm.ops->address_announced(msk, ¶m) : | ||
67 | + mptcp_pm_nl_address_announced(msk, ¶m); | ||
68 | release_sock(sk); | ||
69 | |||
70 | next: | ||
71 | @@ -XXX,XX +XXX,XX @@ static struct pernet_operations mptcp_pm_pernet_ops = { | ||
72 | }; | ||
73 | |||
74 | static struct mptcp_pm_ops mptcp_netlink_pm = { | ||
75 | + .address_announced = mptcp_pm_nl_address_announced, | ||
76 | .get_local_id = mptcp_pm_nl_get_local_id, | ||
77 | .get_priority = mptcp_pm_nl_get_priority, | ||
78 | .type = MPTCP_PM_TYPE_KERNEL, | ||
79 | -- | ||
80 | 2.43.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Geliang Tang <tanggeliang@kylinos.cn> | ||
1 | 2 | ||
3 | Update the 2nd parameter of mptcp_pm_nl_address_removed(), and define it | ||
4 | as the address_removed() interface of the in-kernel netlink PM. | ||
5 | |||
6 | This interface is invoked under holding the msk socket lock. | ||
7 | |||
8 | Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> | ||
9 | --- | ||
10 | net/mptcp/pm_netlink.c | 10 ++++++++-- | ||
11 | 1 file changed, 8 insertions(+), 2 deletions(-) | ||
12 | |||
13 | diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c | ||
14 | index XXXXXXX..XXXXXXX 100644 | ||
15 | --- a/net/mptcp/pm_netlink.c | ||
16 | +++ b/net/mptcp/pm_netlink.c | ||
17 | @@ -XXX,XX +XXX,XX @@ static void __mark_subflow_endp_available(struct mptcp_sock *msk, u8 id) | ||
18 | } | ||
19 | |||
20 | static int mptcp_pm_nl_address_removed(struct mptcp_sock *msk, | ||
21 | - const struct mptcp_pm_addr_entry *local) | ||
22 | + struct mptcp_pm_param *param) | ||
23 | { | ||
24 | + struct mptcp_pm_addr_entry *local = ¶m->entry; | ||
25 | bool remove_subflow; | ||
26 | |||
27 | remove_subflow = mptcp_lookup_subflow_by_saddr(&msk->conn_list, &local->addr); | ||
28 | @@ -XXX,XX +XXX,XX @@ static int mptcp_nl_remove_subflow_and_signal_addr(struct net *net, | ||
29 | |||
30 | while ((msk = mptcp_token_iter_next(net, &s_slot, &s_num)) != NULL) { | ||
31 | struct sock *sk = (struct sock *)msk; | ||
32 | + struct mptcp_pm_param param; | ||
33 | |||
34 | if (mptcp_pm_is_userspace(msk)) | ||
35 | goto next; | ||
36 | |||
37 | lock_sock(sk); | ||
38 | - mptcp_pm_nl_address_removed(msk, entry); | ||
39 | + mptcp_pm_param_set_contexts(¶m, entry, NULL); | ||
40 | + msk->pm.ops && msk->pm.ops->address_removed ? | ||
41 | + msk->pm.ops->address_removed(msk, ¶m) : | ||
42 | + mptcp_pm_nl_address_removed(msk, ¶m); | ||
43 | mptcp_pm_nl_subflow_closed(msk, entry); | ||
44 | release_sock(sk); | ||
45 | |||
46 | @@ -XXX,XX +XXX,XX @@ static struct pernet_operations mptcp_pm_pernet_ops = { | ||
47 | |||
48 | static struct mptcp_pm_ops mptcp_netlink_pm = { | ||
49 | .address_announced = mptcp_pm_nl_address_announced, | ||
50 | + .address_removed = mptcp_pm_nl_address_removed, | ||
51 | .get_local_id = mptcp_pm_nl_get_local_id, | ||
52 | .get_priority = mptcp_pm_nl_get_priority, | ||
53 | .type = MPTCP_PM_TYPE_KERNEL, | ||
54 | -- | ||
55 | 2.43.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Geliang Tang <tanggeliang@kylinos.cn> | ||
1 | 2 | ||
3 | Update mptcp_pm_nl_subflow_established() to match the parameters and | ||
4 | return value of subflow_established() interface and define it as the | ||
5 | interface of the in-kernel netlink PM. | ||
6 | |||
7 | This interface is invoked under holding the msk socket lock. | ||
8 | |||
9 | Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> | ||
10 | --- | ||
11 | net/mptcp/pm_netlink.c | 11 +++++++++-- | ||
12 | 1 file changed, 9 insertions(+), 2 deletions(-) | ||
13 | |||
14 | diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/net/mptcp/pm_netlink.c | ||
17 | +++ b/net/mptcp/pm_netlink.c | ||
18 | @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_nl_fully_established(struct mptcp_sock *msk) | ||
19 | mptcp_pm_create_subflow_or_signal_addr(msk); | ||
20 | } | ||
21 | |||
22 | -static void mptcp_pm_nl_subflow_established(struct mptcp_sock *msk) | ||
23 | +static int mptcp_pm_nl_subflow_established(struct mptcp_sock *msk, | ||
24 | + struct mptcp_pm_param *param) | ||
25 | { | ||
26 | mptcp_pm_create_subflow_or_signal_addr(msk); | ||
27 | + | ||
28 | + return 0; | ||
29 | } | ||
30 | |||
31 | /* Fill all the local addresses into the array addrs[], | ||
32 | @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_nl_rm_subflow_received(struct mptcp_sock *msk, | ||
33 | void mptcp_pm_nl_work(struct mptcp_sock *msk) | ||
34 | { | ||
35 | struct mptcp_pm_data *pm = &msk->pm; | ||
36 | + struct mptcp_pm_param param; | ||
37 | |||
38 | msk_owned_by_me(msk); | ||
39 | |||
40 | @@ -XXX,XX +XXX,XX @@ void mptcp_pm_nl_work(struct mptcp_sock *msk) | ||
41 | } | ||
42 | if (pm->status & BIT(MPTCP_PM_SUBFLOW_ESTABLISHED)) { | ||
43 | pm->status &= ~BIT(MPTCP_PM_SUBFLOW_ESTABLISHED); | ||
44 | - mptcp_pm_nl_subflow_established(msk); | ||
45 | + msk->pm.ops && msk->pm.ops->subflow_established ? | ||
46 | + msk->pm.ops->subflow_established(msk, ¶m) : | ||
47 | + mptcp_pm_nl_subflow_established(msk, ¶m); | ||
48 | } | ||
49 | |||
50 | spin_unlock_bh(&msk->pm.lock); | ||
51 | @@ -XXX,XX +XXX,XX @@ static struct pernet_operations mptcp_pm_pernet_ops = { | ||
52 | static struct mptcp_pm_ops mptcp_netlink_pm = { | ||
53 | .address_announced = mptcp_pm_nl_address_announced, | ||
54 | .address_removed = mptcp_pm_nl_address_removed, | ||
55 | + .subflow_established = mptcp_pm_nl_subflow_established, | ||
56 | .get_local_id = mptcp_pm_nl_get_local_id, | ||
57 | .get_priority = mptcp_pm_nl_get_priority, | ||
58 | .type = MPTCP_PM_TYPE_KERNEL, | ||
59 | -- | ||
60 | 2.43.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Geliang Tang <tanggeliang@kylinos.cn> | ||
1 | 2 | ||
3 | Update the 2nd parameter of mptcp_pm_nl_subflow_closed(), and define it | ||
4 | as the subflow_closed() interface of the in-kernel netlink PM. | ||
5 | |||
6 | This interface is invoked under holding the msk socket lock. | ||
7 | |||
8 | Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> | ||
9 | --- | ||
10 | net/mptcp/pm_netlink.c | 8 ++++++-- | ||
11 | 1 file changed, 6 insertions(+), 2 deletions(-) | ||
12 | |||
13 | diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c | ||
14 | index XXXXXXX..XXXXXXX 100644 | ||
15 | --- a/net/mptcp/pm_netlink.c | ||
16 | +++ b/net/mptcp/pm_netlink.c | ||
17 | @@ -XXX,XX +XXX,XX @@ static int mptcp_pm_nl_address_removed(struct mptcp_sock *msk, | ||
18 | } | ||
19 | |||
20 | static int mptcp_pm_nl_subflow_closed(struct mptcp_sock *msk, | ||
21 | - const struct mptcp_pm_addr_entry *local) | ||
22 | + struct mptcp_pm_param *param) | ||
23 | { | ||
24 | + struct mptcp_pm_addr_entry *local = ¶m->entry; | ||
25 | struct mptcp_rm_list list = { .nr = 1 }; | ||
26 | bool remove_subflow; | ||
27 | |||
28 | @@ -XXX,XX +XXX,XX @@ static int mptcp_nl_remove_subflow_and_signal_addr(struct net *net, | ||
29 | msk->pm.ops && msk->pm.ops->address_removed ? | ||
30 | msk->pm.ops->address_removed(msk, ¶m) : | ||
31 | mptcp_pm_nl_address_removed(msk, ¶m); | ||
32 | - mptcp_pm_nl_subflow_closed(msk, entry); | ||
33 | + msk->pm.ops && msk->pm.ops->subflow_closed ? | ||
34 | + msk->pm.ops->subflow_closed(msk, ¶m) : | ||
35 | + mptcp_pm_nl_subflow_closed(msk, ¶m); | ||
36 | release_sock(sk); | ||
37 | |||
38 | next: | ||
39 | @@ -XXX,XX +XXX,XX @@ static struct mptcp_pm_ops mptcp_netlink_pm = { | ||
40 | .address_announced = mptcp_pm_nl_address_announced, | ||
41 | .address_removed = mptcp_pm_nl_address_removed, | ||
42 | .subflow_established = mptcp_pm_nl_subflow_established, | ||
43 | + .subflow_closed = mptcp_pm_nl_subflow_closed, | ||
44 | .get_local_id = mptcp_pm_nl_get_local_id, | ||
45 | .get_priority = mptcp_pm_nl_get_priority, | ||
46 | .type = MPTCP_PM_TYPE_KERNEL, | ||
47 | -- | ||
48 | 2.43.0 | diff view generated by jsdifflib |
1 | From: Geliang Tang <tanggeliang@kylinos.cn> | 1 | From: Geliang Tang <tanggeliang@kylinos.cn> |
---|---|---|---|
2 | 2 | ||
3 | This patch adds an mptcp bpf userspace pm example program, implements | 3 | Extract address_announced() interface of the userspace PM from the handler |
4 | address_announce, address_remove, subflow_create, subflow_destroy, | 4 | of netlink command MPTCP_PM_CMD_ANNOUNCE mptcp_pm_nl_announce_doit(), only |
5 | get_local_id, is_backup, and set_flags interfaces using almost the | 5 | leave the code for obtaining msk through "info" and parsing address entry |
6 | same logic as the userspace pm in kernel. | 6 | in the handler. |
7 | |||
8 | This interface is invoked under holding the msk socket lock. | ||
7 | 9 | ||
8 | Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> | 10 | Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> |
9 | --- | 11 | --- |
10 | .../testing/selftests/bpf/prog_tests/mptcp.c | 51 ++++ | 12 | net/mptcp/pm_userspace.c | 49 ++++++++++++++++++++++++++-------------- |
11 | tools/testing/selftests/bpf/progs/mptcp_bpf.h | 75 +++++ | 13 | 1 file changed, 32 insertions(+), 17 deletions(-) |
12 | .../bpf/progs/mptcp_bpf_userspace_pm.c | 275 ++++++++++++++++++ | ||
13 | 3 files changed, 401 insertions(+) | ||
14 | create mode 100644 tools/testing/selftests/bpf/progs/mptcp_bpf_userspace_pm.c | ||
15 | 14 | ||
16 | diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c | 15 | diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c |
17 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c | 17 | --- a/net/mptcp/pm_userspace.c |
19 | +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c | 18 | +++ b/net/mptcp/pm_userspace.c |
20 | @@ -XXX,XX +XXX,XX @@ | 19 | @@ -XXX,XX +XXX,XX @@ static struct mptcp_sock *mptcp_userspace_pm_get_sock(const struct genl_info *in |
21 | #include "mptcpify.skel.h" | 20 | return msk; |
22 | #include "mptcp_subflow.skel.h" | ||
23 | #include "mptcp_bpf_iters.skel.h" | ||
24 | +#include "mptcp_bpf_userspace_pm.skel.h" | ||
25 | #include "mptcp_bpf_first.skel.h" | ||
26 | #include "mptcp_bpf_bkup.skel.h" | ||
27 | #include "mptcp_bpf_rr.skel.h" | ||
28 | @@ -XXX,XX +XXX,XX @@ | ||
29 | enum mptcp_pm_type { | ||
30 | MPTCP_PM_TYPE_KERNEL = 0, | ||
31 | MPTCP_PM_TYPE_USERSPACE, | ||
32 | + MPTCP_PM_TYPE_BPF_USERSPACE, | ||
33 | |||
34 | __MPTCP_PM_TYPE_NR, | ||
35 | __MPTCP_PM_TYPE_MAX = __MPTCP_PM_TYPE_NR - 1, | ||
36 | @@ -XXX,XX +XXX,XX @@ static void test_userspace_pm(void) | ||
37 | netns_free(netns); | ||
38 | } | 21 | } |
39 | 22 | ||
40 | +static void test_bpf_path_manager(void) | 23 | +static int mptcp_userspace_pm_address_announced(struct mptcp_sock *msk, |
24 | + struct mptcp_pm_param *param) | ||
41 | +{ | 25 | +{ |
42 | + struct mptcp_bpf_userspace_pm *skel; | 26 | + struct mptcp_pm_addr_entry *local = ¶m->entry; |
43 | + struct netns_obj *netns; | ||
44 | + int err; | ||
45 | + | ||
46 | + skel = mptcp_bpf_userspace_pm__open(); | ||
47 | + if (!ASSERT_OK_PTR(skel, "open: userspace_pm")) | ||
48 | + return; | ||
49 | + | ||
50 | + err = bpf_program__set_flags(skel->progs.mptcp_userspace_pm_address_announced, | ||
51 | + BPF_F_SLEEPABLE); | ||
52 | + err = err ?: bpf_program__set_flags(skel->progs.mptcp_userspace_pm_address_removed, | ||
53 | + BPF_F_SLEEPABLE); | ||
54 | + err = err ?: bpf_program__set_flags(skel->progs.mptcp_userspace_pm_subflow_established, | ||
55 | + BPF_F_SLEEPABLE); | ||
56 | + err = err ?: bpf_program__set_flags(skel->progs.mptcp_userspace_pm_subflow_closed, | ||
57 | + BPF_F_SLEEPABLE); | ||
58 | + err = err ?: bpf_program__set_flags(skel->progs.mptcp_userspace_pm_set_priority, | ||
59 | + BPF_F_SLEEPABLE); | ||
60 | + if (!ASSERT_OK(err, "set sleepable flags")) | ||
61 | + goto skel_destroy; | ||
62 | + | ||
63 | + if (!ASSERT_OK(mptcp_bpf_userspace_pm__load(skel), "load: userspace_pm")) | ||
64 | + goto skel_destroy; | ||
65 | + | ||
66 | + err = mptcp_bpf_userspace_pm__attach(skel); | ||
67 | + if (!ASSERT_OK(err, "attach: userspace_pm")) | ||
68 | + goto skel_destroy; | ||
69 | + | ||
70 | + netns = netns_new(NS_TEST, true); | ||
71 | + if (!ASSERT_OK_PTR(netns, "netns_new")) | ||
72 | + goto skel_destroy; | ||
73 | + | ||
74 | + err = userspace_pm_init(MPTCP_PM_TYPE_BPF_USERSPACE); | ||
75 | + if (!ASSERT_OK(err, "userspace_pm_init: bpf pm")) | ||
76 | + goto close_netns; | ||
77 | + | ||
78 | + run_userspace_pm(skel->kconfig->CONFIG_MPTCP_IPV6 ? IPV6 : IPV4); | ||
79 | + | ||
80 | + userspace_pm_cleanup(); | ||
81 | +close_netns: | ||
82 | + netns_free(netns); | ||
83 | +skel_destroy: | ||
84 | + mptcp_bpf_userspace_pm__destroy(skel); | ||
85 | +} | ||
86 | + | ||
87 | static struct netns_obj *sched_init(char *flags, char *sched) | ||
88 | { | ||
89 | struct netns_obj *netns; | ||
90 | @@ -XXX,XX +XXX,XX @@ void test_mptcp(void) | ||
91 | test_iters_address(); | ||
92 | if (test__start_subtest("userspace_pm")) | ||
93 | test_userspace_pm(); | ||
94 | + if (test__start_subtest("bpf_path_manager")) | ||
95 | + test_bpf_path_manager(); | ||
96 | if (test__start_subtest("default")) | ||
97 | test_default(); | ||
98 | if (test__start_subtest("first")) | ||
99 | diff --git a/tools/testing/selftests/bpf/progs/mptcp_bpf.h b/tools/testing/selftests/bpf/progs/mptcp_bpf.h | ||
100 | index XXXXXXX..XXXXXXX 100644 | ||
101 | --- a/tools/testing/selftests/bpf/progs/mptcp_bpf.h | ||
102 | +++ b/tools/testing/selftests/bpf/progs/mptcp_bpf.h | ||
103 | @@ -XXX,XX +XXX,XX @@ static inline int list_is_head(const struct list_head *list, | ||
104 | #define ENOMEM 12 /* Out of Memory */ | ||
105 | #define EINVAL 22 /* Invalid argument */ | ||
106 | |||
107 | +/* mptcp helpers from include/net/mptcp.h */ | ||
108 | +#define U8_MAX ((u8)~0U) | ||
109 | + | ||
110 | +/* max value of mptcp_addr_info.id */ | ||
111 | +#define MPTCP_PM_MAX_ADDR_ID U8_MAX | ||
112 | + | ||
113 | +/* mptcp macros from include/uapi/linux/mptcp.h */ | ||
114 | +#define MPTCP_PM_ADDR_FLAG_SIGNAL (1 << 0) | ||
115 | +#define MPTCP_PM_ADDR_FLAG_SUBFLOW (1 << 1) | ||
116 | +#define MPTCP_PM_ADDR_FLAG_BACKUP (1 << 2) | ||
117 | +#define MPTCP_PM_ADDR_FLAG_FULLMESH (1 << 3) | ||
118 | +#define MPTCP_PM_ADDR_FLAG_IMPLICIT (1 << 4) | ||
119 | + | ||
120 | +/* address families macros from include/linux/socket.h */ | ||
121 | +#define AF_UNSPEC 0 | ||
122 | +#define AF_INET 2 | ||
123 | +#define AF_INET6 10 | ||
124 | + | ||
125 | +/* shutdown macros from include/net/sock.h */ | ||
126 | +#define RCV_SHUTDOWN 1 | ||
127 | +#define SEND_SHUTDOWN 2 | ||
128 | + | ||
129 | +/* GFP macros from include/linux/gfp_types.h */ | ||
130 | +#define __AC(X,Y) (X##Y) | ||
131 | +#define _AC(X,Y) __AC(X,Y) | ||
132 | +#define _UL(x) (_AC(x, UL)) | ||
133 | +#define UL(x) (_UL(x)) | ||
134 | +#define BIT(nr) (UL(1) << (nr)) | ||
135 | + | ||
136 | +#define ___GFP_HIGH BIT(___GFP_HIGH_BIT) | ||
137 | +#define __GFP_HIGH ((gfp_t)___GFP_HIGH) | ||
138 | +#define ___GFP_KSWAPD_RECLAIM BIT(___GFP_KSWAPD_RECLAIM_BIT) | ||
139 | +#define __GFP_KSWAPD_RECLAIM ((gfp_t)___GFP_KSWAPD_RECLAIM) /* kswapd can wake */ | ||
140 | +#define GFP_ATOMIC (__GFP_HIGH|__GFP_KSWAPD_RECLAIM) | ||
141 | + | ||
142 | static __always_inline struct sock * | ||
143 | mptcp_subflow_tcp_sock(const struct mptcp_subflow_context *subflow) | ||
144 | { | ||
145 | @@ -XXX,XX +XXX,XX @@ extern void bpf_spin_unlock_bh(spinlock_t *lock) __ksym; | ||
146 | |||
147 | extern bool bpf_ipv4_is_private_10(__be32 addr) __ksym; | ||
148 | |||
149 | +extern struct mptcp_pm_addr_entry * | ||
150 | +bpf_sock_kmalloc_entry(struct sock *sk, int size, gfp_t priority) __ksym; | ||
151 | +extern void | ||
152 | +bpf_sock_kfree_entry(struct sock *sk, struct mptcp_pm_addr_entry *entry, | ||
153 | + int size) __ksym; | ||
154 | + | ||
155 | +extern bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, | ||
156 | + const struct mptcp_addr_info *addr) __ksym; | ||
157 | +extern int mptcp_pm_announce_addr(struct mptcp_sock *msk, | ||
158 | + const struct mptcp_addr_info *addr, | ||
159 | + bool echo) __ksym; | ||
160 | +extern void mptcp_pm_nl_addr_send_ack(struct mptcp_sock *msk) __ksym; | ||
161 | + | ||
162 | +extern void bpf_bitmap_zero(unsigned long *dst, unsigned int nbits) __ksym; | ||
163 | +extern void bpf_set_bit(unsigned long nr, unsigned long *addr) __ksym; | ||
164 | +extern u8 bpf_find_next_zero_bit(const unsigned long *addr, | ||
165 | + unsigned long size, unsigned long offset) __ksym; | ||
166 | + | ||
167 | +extern int mptcp_pm_remove_addr(struct mptcp_sock *msk, | ||
168 | + const struct mptcp_rm_list *rm_list) __ksym; | ||
169 | +extern void mptcp_pm_remove_addr_entry(struct mptcp_sock *msk, | ||
170 | + struct mptcp_pm_addr_entry *entry) __ksym; | ||
171 | + | ||
172 | +extern int bpf_mptcp_subflow_connect(struct sock *sk, | ||
173 | + const struct mptcp_pm_addr_entry *entry, | ||
174 | + const struct mptcp_addr_info *remote) __ksym; | ||
175 | + | ||
176 | +extern void | ||
177 | +mptcp_subflow_shutdown(struct sock *sk, struct sock *ssk, int how) __ksym; | ||
178 | +extern void mptcp_close_ssk(struct sock *sk, struct sock *ssk, | ||
179 | + struct mptcp_subflow_context *subflow) __ksym; | ||
180 | +extern struct net *bpf_sock_net(const struct sock *sk) __ksym; | ||
181 | +extern void BPF_MPTCP_INC_STATS(struct net *net, | ||
182 | + enum linux_mptcp_mib_field field) __ksym; | ||
183 | + | ||
184 | +extern int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk, | ||
185 | + struct mptcp_addr_info *addr, | ||
186 | + struct mptcp_addr_info *rem, | ||
187 | + u8 bkup) __ksym; | ||
188 | + | ||
189 | extern void mptcp_subflow_set_scheduled(struct mptcp_subflow_context *subflow, | ||
190 | bool scheduled) __ksym; | ||
191 | |||
192 | diff --git a/tools/testing/selftests/bpf/progs/mptcp_bpf_userspace_pm.c b/tools/testing/selftests/bpf/progs/mptcp_bpf_userspace_pm.c | ||
193 | new file mode 100644 | ||
194 | index XXXXXXX..XXXXXXX | ||
195 | --- /dev/null | ||
196 | +++ b/tools/testing/selftests/bpf/progs/mptcp_bpf_userspace_pm.c | ||
197 | @@ -XXX,XX +XXX,XX @@ | ||
198 | +// SPDX-License-Identifier: GPL-2.0 | ||
199 | +/* Copyright (c) 2025, Kylin Software */ | ||
200 | + | ||
201 | +#include "mptcp_bpf.h" | ||
202 | + | ||
203 | +char _license[] SEC("license") = "GPL"; | ||
204 | + | ||
205 | +extern bool CONFIG_MPTCP_IPV6 __kconfig __weak; | ||
206 | + | ||
207 | +extern void bpf_list_add_tail_rcu(struct list_head *new, | ||
208 | + struct list_head *head) __ksym; | ||
209 | +extern void bpf_list_del_rcu(struct list_head *entry) __ksym; | ||
210 | + | ||
211 | +SEC("struct_ops") | ||
212 | +void BPF_PROG(mptcp_userspace_pm_init, struct mptcp_sock *msk) | ||
213 | +{ | ||
214 | + bpf_printk("BPF userspace PM (%s)", | ||
215 | + CONFIG_MPTCP_IPV6 ? "IPv6" : "IPv4"); | ||
216 | +} | ||
217 | + | ||
218 | +SEC("struct_ops") | ||
219 | +void BPF_PROG(mptcp_userspace_pm_release, struct mptcp_sock *msk) | ||
220 | +{ | ||
221 | +} | ||
222 | + | ||
223 | +static struct mptcp_pm_addr_entry * | ||
224 | +mptcp_userspace_pm_lookup_addr(struct mptcp_sock *msk, | ||
225 | + const struct mptcp_addr_info *addr) | ||
226 | +{ | ||
227 | + struct mptcp_pm_addr_entry *entry; | ||
228 | + | ||
229 | + bpf_for_each(mptcp_userspace_pm_addr, entry, (struct sock *)msk) { | ||
230 | + if (mptcp_addresses_equal(&entry->addr, addr, false)) | ||
231 | + return entry; | ||
232 | + } | ||
233 | + return NULL; | ||
234 | +} | ||
235 | + | ||
236 | +static int mptcp_userspace_pm_append_new_local_addr(struct mptcp_sock *msk, | ||
237 | + struct mptcp_pm_addr_entry *entry, | ||
238 | + bool needs_id) | ||
239 | +{ | ||
240 | + struct sock *sk = (struct sock *)msk; | ||
241 | + unsigned long id_bitmap[4] = { 0 }; | ||
242 | + struct mptcp_pm_addr_entry *e; | ||
243 | + bool addr_match = false; | ||
244 | + bool id_match = false; | ||
245 | + int ret = -EINVAL; | ||
246 | + | ||
247 | + bpf_bitmap_zero(id_bitmap, MPTCP_PM_MAX_ADDR_ID + 1); | ||
248 | + | ||
249 | + bpf_spin_lock_bh(&msk->pm.lock); | ||
250 | + bpf_for_each(mptcp_userspace_pm_addr, e, sk) { | ||
251 | + addr_match = mptcp_addresses_equal(&e->addr, &entry->addr, true); | ||
252 | + if (addr_match && entry->addr.id == 0 && needs_id) | ||
253 | + entry->addr.id = e->addr.id; | ||
254 | + id_match = (e->addr.id == entry->addr.id); | ||
255 | + if (addr_match || id_match) | ||
256 | + break; | ||
257 | + bpf_set_bit(e->addr.id, id_bitmap); | ||
258 | + } | ||
259 | + | ||
260 | + if (!addr_match && !id_match) { | ||
261 | + /* Memory for the entry is allocated from the | ||
262 | + * sock option buffer. | ||
263 | + */ | ||
264 | + e = bpf_sock_kmalloc_entry(sk, sizeof(*e), GFP_ATOMIC); | ||
265 | + if (!e) { | ||
266 | + ret = -ENOMEM; | ||
267 | + goto append_err; | ||
268 | + } | ||
269 | + | ||
270 | + mptcp_pm_copy_entry(e, entry); | ||
271 | + if (!e->addr.id && needs_id) | ||
272 | + e->addr.id = bpf_find_next_zero_bit(id_bitmap, | ||
273 | + MPTCP_PM_MAX_ADDR_ID + 1, | ||
274 | + 1); | ||
275 | + bpf_list_add_tail_rcu(&e->list, &msk->pm.userspace_pm_local_addr_list); | ||
276 | + msk->pm.local_addr_used++; | ||
277 | + ret = e->addr.id; | ||
278 | + } else if (addr_match && id_match) { | ||
279 | + ret = entry->addr.id; | ||
280 | + } | ||
281 | + | ||
282 | +append_err: | ||
283 | + bpf_spin_unlock_bh(&msk->pm.lock); | ||
284 | + return ret; | ||
285 | +} | ||
286 | + | ||
287 | +SEC("struct_ops") | ||
288 | +int BPF_PROG(mptcp_userspace_pm_address_announced, struct mptcp_sock *msk, | ||
289 | + struct mptcp_pm_addr_entry *local) | ||
290 | +{ | ||
291 | + int err; | 27 | + int err; |
292 | + | 28 | + |
293 | + err = mptcp_userspace_pm_append_new_local_addr(msk, local, false); | 29 | + err = mptcp_userspace_pm_append_new_local_addr(msk, local, false); |
294 | + if (err < 0) | 30 | + if (err < 0) |
295 | + return err; | 31 | + return err; |
296 | + | 32 | + |
297 | + bpf_spin_lock_bh(&msk->pm.lock); | 33 | + spin_lock_bh(&msk->pm.lock); |
298 | + | 34 | + |
299 | + if (mptcp_pm_alloc_anno_list(msk, &local->addr)) { | 35 | + if (mptcp_pm_alloc_anno_list(msk, &local->addr)) { |
300 | + msk->pm.add_addr_signaled++; | 36 | + msk->pm.add_addr_signaled++; |
301 | + mptcp_pm_announce_addr(msk, &local->addr, false); | 37 | + mptcp_pm_announce_addr(msk, &local->addr, false); |
302 | + mptcp_pm_nl_addr_send_ack(msk); | 38 | + mptcp_pm_nl_addr_send_ack(msk); |
303 | + } | 39 | + } |
304 | + | 40 | + |
305 | + bpf_spin_unlock_bh(&msk->pm.lock); | 41 | + spin_unlock_bh(&msk->pm.lock); |
306 | + | 42 | + |
307 | + return 0; | 43 | + return 0; |
308 | +} | 44 | +} |
309 | + | 45 | + |
310 | +static struct mptcp_pm_addr_entry * | 46 | int mptcp_pm_nl_announce_doit(struct sk_buff *skb, struct genl_info *info) |
311 | +mptcp_userspace_pm_lookup_addr_by_id(struct mptcp_sock *msk, unsigned int id) | 47 | { |
312 | +{ | 48 | struct mptcp_pm_addr_entry addr_val; |
313 | + struct mptcp_pm_addr_entry *entry; | 49 | + struct mptcp_pm_param param; |
314 | + | 50 | struct mptcp_sock *msk; |
315 | + bpf_for_each(mptcp_userspace_pm_addr, entry, (struct sock *)msk) { | 51 | struct nlattr *addr; |
316 | + if (entry->addr.id == id) | 52 | int err = -EINVAL; |
317 | + return entry; | 53 | @@ -XXX,XX +XXX,XX @@ int mptcp_pm_nl_announce_doit(struct sk_buff *skb, struct genl_info *info) |
318 | + } | 54 | goto announce_err; |
319 | + return NULL; | 55 | } |
320 | +} | 56 | |
321 | + | 57 | - err = mptcp_userspace_pm_append_new_local_addr(msk, &addr_val, false); |
322 | +SEC("struct_ops") | 58 | - if (err < 0) { |
323 | +int BPF_PROG(mptcp_userspace_pm_address_removed, struct mptcp_sock *msk, u8 id) | 59 | - NL_SET_ERR_MSG_ATTR(info->extack, addr, |
324 | +{ | 60 | - "did not match address and id"); |
325 | + struct mptcp_pm_addr_entry *entry; | 61 | - goto announce_err; |
326 | + | 62 | - } |
327 | + bpf_spin_lock_bh(&msk->pm.lock); | 63 | - |
328 | + entry = mptcp_userspace_pm_lookup_addr_by_id(msk, id); | 64 | lock_sock(sk); |
329 | + if (!entry) { | 65 | - spin_lock_bh(&msk->pm.lock); |
330 | + bpf_spin_unlock_bh(&msk->pm.lock); | 66 | - |
331 | + return -EINVAL; | 67 | - if (mptcp_pm_alloc_anno_list(msk, &addr_val.addr)) { |
332 | + } | 68 | - msk->pm.add_addr_signaled++; |
333 | + | 69 | - mptcp_pm_announce_addr(msk, &addr_val.addr, false); |
334 | + bpf_list_del_rcu(&entry->list); | 70 | - mptcp_pm_nl_addr_send_ack(msk); |
335 | + bpf_spin_unlock_bh(&msk->pm.lock); | 71 | - } |
336 | + | 72 | - |
337 | + mptcp_pm_remove_addr_entry(msk, entry); | 73 | - spin_unlock_bh(&msk->pm.lock); |
338 | + | 74 | + mptcp_pm_param_set_contexts(¶m, &addr_val, NULL); |
339 | + bpf_sock_kfree_entry((struct sock *)msk, entry, sizeof(*entry)); | 75 | + err = msk->pm.ops && msk->pm.ops->address_announced ? |
340 | + | 76 | + msk->pm.ops->address_announced(msk, ¶m) : |
341 | + return 0; | 77 | + mptcp_userspace_pm_address_announced(msk, ¶m); |
342 | +} | 78 | release_sock(sk); |
343 | + | ||
344 | +static int mptcp_userspace_pm_delete_local_addr(struct mptcp_sock *msk, | ||
345 | + struct mptcp_pm_addr_entry *addr) | ||
346 | +{ | ||
347 | + struct sock *sk = (struct sock *)msk; | ||
348 | + struct mptcp_pm_addr_entry *entry; | ||
349 | + | ||
350 | + entry = mptcp_userspace_pm_lookup_addr(msk, &addr->addr); | ||
351 | + if (!entry) | ||
352 | + return -EINVAL; | ||
353 | + | ||
354 | + bpf_list_del_rcu(&entry->list); | ||
355 | + bpf_sock_kfree_entry(sk, entry, sizeof(*entry)); | ||
356 | + msk->pm.local_addr_used--; | ||
357 | + return 0; | ||
358 | +} | ||
359 | + | ||
360 | +SEC("struct_ops") | ||
361 | +int BPF_PROG(mptcp_userspace_pm_subflow_established, struct mptcp_sock *msk, | ||
362 | + struct mptcp_pm_addr_entry *local, struct mptcp_addr_info *remote) | ||
363 | +{ | ||
364 | + struct sock *sk = (struct sock *)msk; | ||
365 | + int err; | ||
366 | + | ||
367 | + err = mptcp_userspace_pm_append_new_local_addr(msk, local, false); | ||
368 | + if (err < 0) | ||
369 | + return err; | ||
370 | + | ||
371 | + err = bpf_mptcp_subflow_connect(sk, local, remote); | ||
372 | + bpf_spin_lock_bh(&msk->pm.lock); | ||
373 | + if (err) | 79 | + if (err) |
374 | + mptcp_userspace_pm_delete_local_addr(msk, local); | 80 | + NL_SET_ERR_MSG_ATTR(info->extack, addr, |
375 | + else | 81 | + "did not match address and id"); |
376 | + msk->pm.subflows++; | 82 | |
377 | + bpf_spin_unlock_bh(&msk->pm.lock); | 83 | - err = 0; |
378 | + | 84 | announce_err: |
379 | + return err; | 85 | sock_put(sk); |
380 | +} | 86 | return err; |
381 | + | 87 | @@ -XXX,XX +XXX,XX @@ int mptcp_userspace_pm_get_addr(u8 id, struct mptcp_pm_addr_entry *addr, |
382 | +SEC("struct_ops") | 88 | } |
383 | +int BPF_PROG(mptcp_userspace_pm_subflow_closed, struct mptcp_sock *msk, | 89 | |
384 | + struct mptcp_pm_addr_entry *local, struct mptcp_addr_info *remote) | 90 | static struct mptcp_pm_ops mptcp_userspace_pm = { |
385 | +{ | 91 | + .address_announced = mptcp_userspace_pm_address_announced, |
386 | + struct sock *ssk, *sk = (struct sock *)msk; | 92 | .get_local_id = mptcp_userspace_pm_get_local_id, |
387 | + struct mptcp_subflow_context *subflow; | 93 | .get_priority = mptcp_userspace_pm_get_priority, |
388 | + | 94 | .type = MPTCP_PM_TYPE_USERSPACE, |
389 | + ssk = mptcp_pm_find_ssk(msk, &local->addr, remote); | ||
390 | + if (!ssk) | ||
391 | + return -ESRCH; | ||
392 | + | ||
393 | + subflow = bpf_mptcp_subflow_ctx(ssk); | ||
394 | + if (!subflow) | ||
395 | + return -EINVAL; | ||
396 | + | ||
397 | + bpf_spin_lock_bh(&msk->pm.lock); | ||
398 | + mptcp_userspace_pm_delete_local_addr(msk, local); | ||
399 | + bpf_spin_unlock_bh(&msk->pm.lock); | ||
400 | + mptcp_subflow_shutdown(sk, ssk, RCV_SHUTDOWN | SEND_SHUTDOWN); | ||
401 | + mptcp_close_ssk(sk, ssk, subflow); | ||
402 | + BPF_MPTCP_INC_STATS(bpf_sock_net(sk), MPTCP_MIB_RMSUBFLOW); | ||
403 | + | ||
404 | + return 0; | ||
405 | +} | ||
406 | + | ||
407 | +SEC("struct_ops") | ||
408 | +int BPF_PROG(mptcp_userspace_pm_get_local_id, struct mptcp_sock *msk, | ||
409 | + struct mptcp_pm_addr_entry *skc) | ||
410 | +{ | ||
411 | + struct mptcp_pm_addr_entry *entry; | ||
412 | + | ||
413 | + bpf_spin_lock_bh(&msk->pm.lock); | ||
414 | + entry = mptcp_userspace_pm_lookup_addr(msk, &skc->addr); | ||
415 | + bpf_spin_unlock_bh(&msk->pm.lock); | ||
416 | + if (entry) | ||
417 | + return entry->addr.id; | ||
418 | + | ||
419 | + return mptcp_userspace_pm_append_new_local_addr(msk, skc, true); | ||
420 | +} | ||
421 | + | ||
422 | +SEC("struct_ops") | ||
423 | +bool BPF_PROG(mptcp_userspace_pm_get_priority, struct mptcp_sock *msk, | ||
424 | + struct mptcp_addr_info *skc) | ||
425 | +{ | ||
426 | + struct mptcp_pm_addr_entry *entry; | ||
427 | + bool backup; | ||
428 | + | ||
429 | + bpf_spin_lock_bh(&msk->pm.lock); | ||
430 | + entry = mptcp_userspace_pm_lookup_addr(msk, skc); | ||
431 | + backup = entry && !!(entry->flags & MPTCP_PM_ADDR_FLAG_BACKUP); | ||
432 | + bpf_spin_unlock_bh(&msk->pm.lock); | ||
433 | + | ||
434 | + return backup; | ||
435 | +} | ||
436 | + | ||
437 | +SEC("struct_ops") | ||
438 | +int BPF_PROG(mptcp_userspace_pm_set_priority, struct mptcp_sock *msk, | ||
439 | + struct mptcp_pm_addr_entry *local, struct mptcp_addr_info *remote) | ||
440 | +{ | ||
441 | + struct mptcp_pm_addr_entry *entry; | ||
442 | + u8 bkup = 0; | ||
443 | + | ||
444 | + if (local->flags & MPTCP_PM_ADDR_FLAG_BACKUP) | ||
445 | + bkup = 1; | ||
446 | + | ||
447 | + bpf_spin_lock_bh(&msk->pm.lock); | ||
448 | + entry = mptcp_userspace_pm_lookup_addr(msk, &local->addr); | ||
449 | + if (entry) { | ||
450 | + if (bkup) | ||
451 | + entry->flags |= MPTCP_PM_ADDR_FLAG_BACKUP; | ||
452 | + else | ||
453 | + entry->flags &= ~MPTCP_PM_ADDR_FLAG_BACKUP; | ||
454 | + } | ||
455 | + bpf_spin_unlock_bh(&msk->pm.lock); | ||
456 | + | ||
457 | + return mptcp_pm_nl_mp_prio_send_ack(msk, &local->addr, remote, bkup); | ||
458 | +} | ||
459 | + | ||
460 | +SEC(".struct_ops.link") | ||
461 | +struct mptcp_pm_ops userspace_pm = { | ||
462 | + .address_announced = (void *)mptcp_userspace_pm_address_announced, | ||
463 | + .address_removed = (void *)mptcp_userspace_pm_address_removed, | ||
464 | + .subflow_established = (void *)mptcp_userspace_pm_subflow_established, | ||
465 | + .subflow_closed = (void *)mptcp_userspace_pm_subflow_closed, | ||
466 | + .get_local_id = (void *)mptcp_userspace_pm_get_local_id, | ||
467 | + .get_priority = (void *)mptcp_userspace_pm_get_priority, | ||
468 | + .set_priority = (void *)mptcp_userspace_pm_set_priority, | ||
469 | + .init = (void *)mptcp_userspace_pm_init, | ||
470 | + .release = (void *)mptcp_userspace_pm_release, | ||
471 | + .type = MPTCP_PM_TYPE_BPF_USERSPACE, | ||
472 | +}; | ||
473 | -- | 95 | -- |
474 | 2.43.0 | 96 | 2.43.0 | diff view generated by jsdifflib |
1 | From: Geliang Tang <tanggeliang@kylinos.cn> | 1 | From: Geliang Tang <tanggeliang@kylinos.cn> |
---|---|---|---|
2 | 2 | ||
3 | This patch implements a new struct bpf_struct_ops for MPTCP BPF path | 3 | Extract address_removed() interface of the userspace PM from the handler |
4 | manager: bpf_mptcp_pm_ops. Register and unregister the bpf path manager | 4 | of netlink command MPTCP_PM_CMD_REMOVE mptcp_pm_nl_remove_doit(), only |
5 | in .reg and .unreg. | 5 | leave the code for parsing address id and obtaining msk through "info" |
6 | in the handler. | ||
6 | 7 | ||
7 | Add write access for some fields of struct mptcp_addr_info, struct | 8 | This interface is invoked under holding the msk socket lock. |
8 | mptcp_pm_addr_entry and struct mptcp_sock in .btf_struct_access. | ||
9 | |||
10 | This MPTCP BPF path manager implementation is similar to BPF TCP CC. And | ||
11 | net/ipv4/bpf_tcp_ca.c is a frame of reference for this patch. | ||
12 | 9 | ||
13 | Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> | 10 | Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> |
14 | --- | 11 | --- |
15 | net/mptcp/bpf.c | 276 +++++++++++++++++++++++++++++++++++++++++++++++- | 12 | net/mptcp/pm_userspace.c | 74 ++++++++++++++++++++-------------------- |
16 | 1 file changed, 275 insertions(+), 1 deletion(-) | 13 | 1 file changed, 37 insertions(+), 37 deletions(-) |
17 | 14 | ||
18 | diff --git a/net/mptcp/bpf.c b/net/mptcp/bpf.c | 15 | diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c |
19 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/net/mptcp/bpf.c | 17 | --- a/net/mptcp/pm_userspace.c |
21 | +++ b/net/mptcp/bpf.c | 18 | +++ b/net/mptcp/pm_userspace.c |
22 | @@ -XXX,XX +XXX,XX @@ | 19 | @@ -XXX,XX +XXX,XX @@ static int mptcp_userspace_pm_remove_id_zero_address(struct mptcp_sock *msk) |
23 | #include "protocol.h" | 20 | { |
24 | 21 | struct mptcp_rm_list list = { .nr = 0 }; | |
25 | #ifdef CONFIG_BPF_JIT | 22 | struct mptcp_subflow_context *subflow; |
26 | +static struct bpf_struct_ops bpf_mptcp_pm_ops; | 23 | - struct sock *sk = (struct sock *)msk; |
27 | +static u32 mptcp_sock_id, | 24 | bool has_id_0 = false; |
28 | + mptcp_entry_id; | 25 | - int err = -EINVAL; |
26 | |||
27 | - lock_sock(sk); | ||
28 | mptcp_for_each_subflow(msk, subflow) { | ||
29 | if (READ_ONCE(subflow->local_id) == 0) { | ||
30 | has_id_0 = true; | ||
31 | @@ -XXX,XX +XXX,XX @@ static int mptcp_userspace_pm_remove_id_zero_address(struct mptcp_sock *msk) | ||
32 | } | ||
33 | } | ||
34 | if (!has_id_0) | ||
35 | - goto remove_err; | ||
36 | + return -EINVAL; | ||
37 | |||
38 | list.ids[list.nr++] = 0; | ||
39 | |||
40 | @@ -XXX,XX +XXX,XX @@ static int mptcp_userspace_pm_remove_id_zero_address(struct mptcp_sock *msk) | ||
41 | mptcp_pm_remove_addr(msk, &list); | ||
42 | spin_unlock_bh(&msk->pm.lock); | ||
43 | |||
44 | - err = 0; | ||
45 | - | ||
46 | -remove_err: | ||
47 | - release_sock(sk); | ||
48 | - return err; | ||
49 | + return 0; | ||
50 | } | ||
51 | |||
52 | void mptcp_pm_remove_addr_entry(struct mptcp_sock *msk, | ||
53 | @@ -XXX,XX +XXX,XX @@ void mptcp_pm_remove_addr_entry(struct mptcp_sock *msk, | ||
54 | spin_unlock_bh(&msk->pm.lock); | ||
55 | } | ||
56 | |||
57 | +static int mptcp_userspace_pm_address_removed(struct mptcp_sock *msk, | ||
58 | + struct mptcp_pm_param *param) | ||
59 | +{ | ||
60 | + struct mptcp_pm_addr_entry *entry; | ||
61 | + u8 id = param->addr.id; | ||
29 | + | 62 | + |
30 | +/* MPTCP BPF path manager */ | 63 | + if (id == 0) |
64 | + return mptcp_userspace_pm_remove_id_zero_address(msk); | ||
31 | + | 65 | + |
32 | +static const struct bpf_func_proto * | 66 | + spin_lock_bh(&msk->pm.lock); |
33 | +bpf_mptcp_pm_get_func_proto(enum bpf_func_id func_id, | 67 | + entry = mptcp_userspace_pm_lookup_addr_by_id(msk, id); |
34 | + const struct bpf_prog *prog) | 68 | + if (!entry) { |
35 | +{ | 69 | + spin_unlock_bh(&msk->pm.lock); |
36 | + switch (func_id) { | 70 | + return -EINVAL; |
37 | + case BPF_FUNC_sk_storage_get: | ||
38 | + return &bpf_sk_storage_get_proto; | ||
39 | + case BPF_FUNC_sk_storage_delete: | ||
40 | + return &bpf_sk_storage_delete_proto; | ||
41 | + default: | ||
42 | + return bpf_base_func_proto(func_id, prog); | ||
43 | + } | ||
44 | +} | ||
45 | + | ||
46 | +static int bpf_mptcp_pm_btf_struct_access(struct bpf_verifier_log *log, | ||
47 | + const struct bpf_reg_state *reg, | ||
48 | + int off, int size) | ||
49 | +{ | ||
50 | + u32 id = reg->btf_id; | ||
51 | + size_t end; | ||
52 | + | ||
53 | + if (id == mptcp_sock_id) { | ||
54 | + switch (off) { | ||
55 | + case offsetof(struct mptcp_sock, pm.add_addr_signaled): | ||
56 | + end = offsetofend(struct mptcp_sock, pm.add_addr_signaled); | ||
57 | + break; | ||
58 | + case offsetof(struct mptcp_sock, pm.local_addr_used): | ||
59 | + end = offsetofend(struct mptcp_sock, pm.local_addr_used); | ||
60 | + break; | ||
61 | + case offsetof(struct mptcp_sock, pm.subflows): | ||
62 | + end = offsetofend(struct mptcp_sock, pm.subflows); | ||
63 | + break; | ||
64 | + default: | ||
65 | + bpf_log(log, "no write support to mptcp_sock at off %d\n", | ||
66 | + off); | ||
67 | + return -EACCES; | ||
68 | + } | ||
69 | + } else if (id == mptcp_entry_id) { | ||
70 | + switch (off) { | ||
71 | + case offsetof(struct mptcp_pm_addr_entry, addr.id): | ||
72 | + end = offsetofend(struct mptcp_pm_addr_entry, addr.id); | ||
73 | + break; | ||
74 | + case offsetof(struct mptcp_pm_addr_entry, addr.family): | ||
75 | + end = offsetofend(struct mptcp_pm_addr_entry, addr.family); | ||
76 | + break; | ||
77 | + case offsetof(struct mptcp_pm_addr_entry, addr.port): | ||
78 | + end = offsetofend(struct mptcp_pm_addr_entry, addr.port); | ||
79 | + break; | ||
80 | +#if IS_ENABLED(CONFIG_MPTCP_IPV6) | ||
81 | + case offsetof(struct mptcp_pm_addr_entry, addr.addr6.s6_addr32[0]): | ||
82 | + end = offsetofend(struct mptcp_pm_addr_entry, addr.addr6.s6_addr32[0]); | ||
83 | + break; | ||
84 | + case offsetof(struct mptcp_pm_addr_entry, addr.addr6.s6_addr32[1]): | ||
85 | + end = offsetofend(struct mptcp_pm_addr_entry, addr.addr6.s6_addr32[1]); | ||
86 | + break; | ||
87 | + case offsetof(struct mptcp_pm_addr_entry, addr.addr6.s6_addr32[2]): | ||
88 | + end = offsetofend(struct mptcp_pm_addr_entry, addr.addr6.s6_addr32[2]); | ||
89 | + break; | ||
90 | + case offsetof(struct mptcp_pm_addr_entry, addr.addr6.s6_addr32[3]): | ||
91 | + end = offsetofend(struct mptcp_pm_addr_entry, addr.addr6.s6_addr32[3]); | ||
92 | + break; | ||
93 | +#else | ||
94 | + case offsetof(struct mptcp_pm_addr_entry, addr.addr.s_addr): | ||
95 | + end = offsetofend(struct mptcp_pm_addr_entry, addr.addr.s_addr); | ||
96 | + break; | ||
97 | +#endif | ||
98 | + case offsetof(struct mptcp_pm_addr_entry, flags): | ||
99 | + end = offsetofend(struct mptcp_pm_addr_entry, flags); | ||
100 | + break; | ||
101 | + case offsetof(struct mptcp_pm_addr_entry, ifindex): | ||
102 | + end = offsetofend(struct mptcp_pm_addr_entry, ifindex); | ||
103 | + break; | ||
104 | + default: | ||
105 | + bpf_log(log, "no write support to mptcp_pm_addr_entry at off %d\n", | ||
106 | + off); | ||
107 | + return -EACCES; | ||
108 | + } | ||
109 | + } else { | ||
110 | + bpf_log(log, "only access to mptcp sock or addr or entry is supported\n"); | ||
111 | + return -EACCES; | ||
112 | + } | 71 | + } |
113 | + | 72 | + |
114 | + if (off + size > end) { | 73 | + list_del_rcu(&entry->list); |
115 | + bpf_log(log, "access beyond %s at off %u size %u ended at %zu", | 74 | + spin_unlock_bh(&msk->pm.lock); |
116 | + id == mptcp_sock_id ? "mptcp_sock" : | ||
117 | + (id == mptcp_entry_id ? "mptcp_pm_addr_entry" : "mptcp_addr_info"), | ||
118 | + off, size, end); | ||
119 | + return -EACCES; | ||
120 | + } | ||
121 | + | 75 | + |
122 | + return NOT_INIT; | 76 | + mptcp_pm_remove_addr_entry(msk, entry); |
123 | +} | ||
124 | + | 77 | + |
125 | +static const struct bpf_verifier_ops bpf_mptcp_pm_verifier_ops = { | 78 | + sock_kfree_s((struct sock *)msk, entry, sizeof(*entry)); |
126 | + .get_func_proto = bpf_mptcp_pm_get_func_proto, | ||
127 | + .is_valid_access = bpf_tracing_btf_ctx_access, | ||
128 | + .btf_struct_access = bpf_mptcp_pm_btf_struct_access, | ||
129 | +}; | ||
130 | + | ||
131 | +static int bpf_mptcp_pm_reg(void *kdata, struct bpf_link *link) | ||
132 | +{ | ||
133 | + return mptcp_pm_register(kdata); | ||
134 | +} | ||
135 | + | ||
136 | +static void bpf_mptcp_pm_unreg(void *kdata, struct bpf_link *link) | ||
137 | +{ | ||
138 | + mptcp_pm_unregister(kdata); | ||
139 | +} | ||
140 | + | ||
141 | +static int bpf_mptcp_pm_check_member(const struct btf_type *t, | ||
142 | + const struct btf_member *member, | ||
143 | + const struct bpf_prog *prog) | ||
144 | +{ | ||
145 | + return 0; | ||
146 | +} | ||
147 | + | ||
148 | +static int bpf_mptcp_pm_init_member(const struct btf_type *t, | ||
149 | + const struct btf_member *member, | ||
150 | + void *kdata, const void *udata) | ||
151 | +{ | ||
152 | + const struct mptcp_pm_ops *upm; | ||
153 | + struct mptcp_pm_ops *pm; | ||
154 | + u32 moff; | ||
155 | + | ||
156 | + upm = (const struct mptcp_pm_ops *)udata; | ||
157 | + pm = (struct mptcp_pm_ops *)kdata; | ||
158 | + | ||
159 | + moff = __btf_member_bit_offset(t, member) / 8; | ||
160 | + switch (moff) { | ||
161 | + case offsetof(struct mptcp_pm_ops, type): | ||
162 | + pm->type = upm->type; | ||
163 | + return 1; | ||
164 | + } | ||
165 | + | 79 | + |
166 | + return 0; | 80 | + return 0; |
167 | +} | 81 | +} |
168 | + | 82 | + |
169 | +static int bpf_mptcp_pm_init(struct btf *btf) | 83 | int mptcp_pm_nl_remove_doit(struct sk_buff *skb, struct genl_info *info) |
170 | +{ | 84 | { |
171 | + s32 type_id; | 85 | - struct mptcp_pm_addr_entry *match; |
172 | + | 86 | + struct mptcp_addr_info addr; |
173 | + type_id = btf_find_by_name_kind(btf, "mptcp_sock", | 87 | + struct mptcp_pm_param param; |
174 | + BTF_KIND_STRUCT); | 88 | struct mptcp_sock *msk; |
175 | + if (type_id < 0) | 89 | struct nlattr *id; |
176 | + return -EINVAL; | 90 | int err = -EINVAL; |
177 | + mptcp_sock_id = type_id; | 91 | struct sock *sk; |
178 | + | 92 | - u8 id_val; |
179 | + type_id = btf_find_by_name_kind(btf, "mptcp_pm_addr_entry", | 93 | |
180 | + BTF_KIND_STRUCT); | 94 | if (GENL_REQ_ATTR_CHECK(info, MPTCP_PM_ATTR_LOC_ID)) |
181 | + if (type_id < 0) | 95 | return err; |
182 | + return -EINVAL; | 96 | |
183 | + mptcp_entry_id = type_id; | 97 | id = info->attrs[MPTCP_PM_ATTR_LOC_ID]; |
184 | + | 98 | - id_val = nla_get_u8(id); |
185 | + return 0; | 99 | + addr.id = nla_get_u8(id); |
186 | +} | 100 | |
187 | + | 101 | msk = mptcp_userspace_pm_get_sock(info); |
188 | +static int bpf_mptcp_pm_validate(void *kdata) | 102 | if (!msk) |
189 | +{ | 103 | @@ -XXX,XX +XXX,XX @@ int mptcp_pm_nl_remove_doit(struct sk_buff *skb, struct genl_info *info) |
190 | + return mptcp_pm_validate(kdata); | 104 | |
191 | +} | 105 | sk = (struct sock *)msk; |
192 | + | 106 | |
193 | +static int __bpf_mptcp_pm_address_created(struct mptcp_sock *msk) | 107 | - if (id_val == 0) { |
194 | +{ | 108 | - err = mptcp_userspace_pm_remove_id_zero_address(msk); |
195 | + return 0; | 109 | - goto out; |
196 | +} | 110 | - } |
197 | + | 111 | - |
198 | +static int __bpf_mptcp_pm_address_established(struct mptcp_sock *msk) | 112 | lock_sock(sk); |
199 | +{ | 113 | - |
200 | + return 0; | 114 | - spin_lock_bh(&msk->pm.lock); |
201 | +} | 115 | - match = mptcp_userspace_pm_lookup_addr_by_id(msk, id_val); |
202 | + | 116 | - if (!match) { |
203 | +static int __bpf_mptcp_pm_address_closed(struct mptcp_sock *msk) | 117 | - spin_unlock_bh(&msk->pm.lock); |
204 | +{ | 118 | - release_sock(sk); |
205 | + return 0; | 119 | - goto out; |
206 | +} | 120 | - } |
207 | + | 121 | - |
208 | +static int __bpf_mptcp_pm_address_announced(struct mptcp_sock *msk, | 122 | - list_del_rcu(&match->list); |
209 | + struct mptcp_pm_addr_entry *addr) | 123 | - spin_unlock_bh(&msk->pm.lock); |
210 | +{ | 124 | - |
211 | + return 0; | 125 | - mptcp_pm_remove_addr_entry(msk, match); |
212 | +} | 126 | - |
213 | + | 127 | + mptcp_pm_param_set_contexts(¶m, NULL, &addr); |
214 | +static int __bpf_mptcp_pm_address_removed(struct mptcp_sock *msk, u8 id) | 128 | + err = msk->pm.ops && msk->pm.ops->address_removed ? |
215 | +{ | 129 | + msk->pm.ops->address_removed(msk, ¶m) : |
216 | + return 0; | 130 | + mptcp_userspace_pm_address_removed(msk, ¶m); |
217 | +} | 131 | release_sock(sk); |
218 | + | 132 | - |
219 | +static int __bpf_mptcp_pm_subflow_established(struct mptcp_sock *msk, | 133 | - sock_kfree_s(sk, match, sizeof(*match)); |
220 | + struct mptcp_pm_addr_entry *local, | 134 | - |
221 | + struct mptcp_addr_info *remote) | 135 | - err = 0; |
222 | +{ | 136 | -out: |
223 | + return 0; | 137 | if (err) |
224 | +} | 138 | NL_SET_ERR_MSG_ATTR_FMT(info->extack, id, |
225 | + | 139 | "address with id %u not found", |
226 | +static int __bpf_mptcp_pm_subflow_closed(struct mptcp_sock *msk, | 140 | - id_val); |
227 | + struct mptcp_pm_addr_entry *local, | 141 | + addr.id); |
228 | + struct mptcp_addr_info *remote) | 142 | |
229 | +{ | 143 | sock_put(sk); |
230 | + return 0; | 144 | return err; |
231 | +} | 145 | @@ -XXX,XX +XXX,XX @@ int mptcp_userspace_pm_get_addr(u8 id, struct mptcp_pm_addr_entry *addr, |
232 | + | 146 | |
233 | +static int __bpf_mptcp_pm_get_local_id(struct mptcp_sock *msk, | 147 | static struct mptcp_pm_ops mptcp_userspace_pm = { |
234 | + struct mptcp_pm_addr_entry *skc) | 148 | .address_announced = mptcp_userspace_pm_address_announced, |
235 | +{ | 149 | + .address_removed = mptcp_userspace_pm_address_removed, |
236 | + return 0; | 150 | .get_local_id = mptcp_userspace_pm_get_local_id, |
237 | +} | 151 | .get_priority = mptcp_userspace_pm_get_priority, |
238 | + | 152 | .type = MPTCP_PM_TYPE_USERSPACE, |
239 | +static bool __bpf_mptcp_pm_get_priority(struct mptcp_sock *msk, | ||
240 | + struct mptcp_addr_info *skc) | ||
241 | +{ | ||
242 | + return 0; | ||
243 | +} | ||
244 | + | ||
245 | +static int __bpf_mptcp_pm_set_priority(struct mptcp_sock *msk, | ||
246 | + struct mptcp_pm_addr_entry *local, | ||
247 | + struct mptcp_addr_info *remote) | ||
248 | +{ | ||
249 | + return 0; | ||
250 | +} | ||
251 | + | ||
252 | +static int __bpf_mptcp_pm_address_listener_created(struct mptcp_sock *msk) | ||
253 | +{ | ||
254 | + return 0; | ||
255 | +} | ||
256 | + | ||
257 | +static int __bpf_mptcp_pm_address_listener_closed(struct mptcp_sock *msk) | ||
258 | +{ | ||
259 | + return 0; | ||
260 | +} | ||
261 | + | ||
262 | +static void __bpf_mptcp_pm_init(struct mptcp_sock *msk) | ||
263 | +{ | ||
264 | +} | ||
265 | + | ||
266 | +static void __bpf_mptcp_pm_release(struct mptcp_sock *msk) | ||
267 | +{ | ||
268 | +} | ||
269 | + | ||
270 | +static struct mptcp_pm_ops __bpf_mptcp_pm_ops = { | ||
271 | + .created = __bpf_mptcp_pm_address_created, | ||
272 | + .established = __bpf_mptcp_pm_address_established, | ||
273 | + .closed = __bpf_mptcp_pm_address_closed, | ||
274 | + .address_announced = __bpf_mptcp_pm_address_announced, | ||
275 | + .address_removed = __bpf_mptcp_pm_address_removed, | ||
276 | + .subflow_established = __bpf_mptcp_pm_subflow_established, | ||
277 | + .subflow_closed = __bpf_mptcp_pm_subflow_closed, | ||
278 | + .get_local_id = __bpf_mptcp_pm_get_local_id, | ||
279 | + .get_priority = __bpf_mptcp_pm_get_priority, | ||
280 | + .set_priority = __bpf_mptcp_pm_set_priority, | ||
281 | + .listener_created = __bpf_mptcp_pm_address_listener_created, | ||
282 | + .listener_closed = __bpf_mptcp_pm_address_listener_closed, | ||
283 | + .init = __bpf_mptcp_pm_init, | ||
284 | + .release = __bpf_mptcp_pm_release, | ||
285 | +}; | ||
286 | + | ||
287 | +static struct bpf_struct_ops bpf_mptcp_pm_ops = { | ||
288 | + .verifier_ops = &bpf_mptcp_pm_verifier_ops, | ||
289 | + .reg = bpf_mptcp_pm_reg, | ||
290 | + .unreg = bpf_mptcp_pm_unreg, | ||
291 | + .check_member = bpf_mptcp_pm_check_member, | ||
292 | + .init_member = bpf_mptcp_pm_init_member, | ||
293 | + .init = bpf_mptcp_pm_init, | ||
294 | + .validate = bpf_mptcp_pm_validate, | ||
295 | + .name = "mptcp_pm_ops", | ||
296 | + .cfi_stubs = &__bpf_mptcp_pm_ops, | ||
297 | +}; | ||
298 | + | ||
299 | static struct bpf_struct_ops bpf_mptcp_sched_ops; | ||
300 | static const struct btf_type *mptcp_sock_type, *mptcp_subflow_type __read_mostly; | ||
301 | -static u32 mptcp_sock_id, mptcp_subflow_id; | ||
302 | +static u32 mptcp_subflow_id; | ||
303 | |||
304 | static const struct bpf_func_proto * | ||
305 | bpf_mptcp_sched_get_func_proto(enum bpf_func_id func_id, | ||
306 | @@ -XXX,XX +XXX,XX @@ static int __init bpf_mptcp_kfunc_init(void) | ||
307 | ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, | ||
308 | &bpf_mptcp_sched_kfunc_set); | ||
309 | #ifdef CONFIG_BPF_JIT | ||
310 | + ret = ret ?: register_bpf_struct_ops(&bpf_mptcp_pm_ops, mptcp_pm_ops); | ||
311 | ret = ret ?: register_bpf_struct_ops(&bpf_mptcp_sched_ops, mptcp_sched_ops); | ||
312 | #endif | ||
313 | |||
314 | -- | 153 | -- |
315 | 2.43.0 | 154 | 2.43.0 | diff view generated by jsdifflib |
1 | From: Geliang Tang <tanggeliang@kylinos.cn> | 1 | From: Geliang Tang <tanggeliang@kylinos.cn> |
---|---|---|---|
2 | 2 | ||
3 | This patch exports mptcp path manager helpers into BPF, adds these | 3 | Extract subflow_established() interface of the userspace PM from the |
4 | kfunc names into struct_ops kfunc_set and register this set with | 4 | handler of netlink command MPTCP_PM_CMD_SUBFLOW_CREATE |
5 | BPF_PROG_TYPE_STRUCT_OPS type. | 5 | |
6 | mptcp_pm_nl_subflow_create_doit(), | ||
7 | |||
8 | only leave the code for obtaining msk through "info", parsing local address | ||
9 | entry and parsing remote address info in the handler. | ||
10 | |||
11 | This interface is invoked under holding the msk socket lock. | ||
6 | 12 | ||
7 | Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> | 13 | Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> |
8 | --- | 14 | --- |
9 | net/mptcp/bpf.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++ | 15 | net/mptcp/pm_userspace.c | 54 +++++++++++++++++++++++++--------------- |
10 | 1 file changed, 96 insertions(+) | 16 | 1 file changed, 34 insertions(+), 20 deletions(-) |
11 | 17 | ||
12 | diff --git a/net/mptcp/bpf.c b/net/mptcp/bpf.c | 18 | diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c |
13 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/net/mptcp/bpf.c | 20 | --- a/net/mptcp/pm_userspace.c |
15 | +++ b/net/mptcp/bpf.c | 21 | +++ b/net/mptcp/pm_userspace.c |
16 | @@ -XXX,XX +XXX,XX @@ | 22 | @@ -XXX,XX +XXX,XX @@ int mptcp_pm_nl_remove_doit(struct sk_buff *skb, struct genl_info *info) |
17 | #include <linux/btf_ids.h> | 23 | return err; |
18 | #include <net/bpf_sk_storage.h> | ||
19 | #include "protocol.h" | ||
20 | +#include "mib.h" | ||
21 | |||
22 | #ifdef CONFIG_BPF_JIT | ||
23 | static struct bpf_struct_ops bpf_mptcp_pm_ops; | ||
24 | @@ -XXX,XX +XXX,XX @@ bpf_mptcp_subflow_ctx(const struct sock *sk) | ||
25 | return NULL; | ||
26 | } | 24 | } |
27 | 25 | ||
28 | +__bpf_kfunc static struct sock * | 26 | +static int mptcp_userspace_pm_subflow_established(struct mptcp_sock *msk, |
29 | +bpf_mptcp_subflow_tcp_sock(const struct mptcp_subflow_context *subflow) | 27 | + struct mptcp_pm_param *param) |
30 | +{ | 28 | +{ |
31 | + if (!subflow) | 29 | + struct mptcp_pm_addr_entry *entry = ¶m->entry; |
32 | + return NULL; | 30 | + struct mptcp_addr_info *remote = ¶m->addr; |
31 | + struct sock *sk = (struct sock *)msk; | ||
32 | + struct mptcp_pm_local local; | ||
33 | + int err; | ||
33 | + | 34 | + |
34 | + return mptcp_subflow_tcp_sock(subflow); | 35 | + err = mptcp_userspace_pm_append_new_local_addr(msk, entry, false); |
35 | +} | 36 | + if (err < 0) |
36 | + | 37 | + return err; |
37 | __bpf_kfunc static int | ||
38 | bpf_iter_mptcp_subflow_new(struct bpf_iter_mptcp_subflow *it, | ||
39 | struct mptcp_sock *msk) | ||
40 | @@ -XXX,XX +XXX,XX @@ __bpf_kfunc static bool bpf_ipv4_is_private_10(__be32 addr) | ||
41 | return ipv4_is_private_10(addr); | ||
42 | } | ||
43 | |||
44 | +__bpf_kfunc static void bpf_list_add_tail_rcu(struct list_head *new, | ||
45 | + struct list_head *head) | ||
46 | +{ | ||
47 | + list_add_tail_rcu(new, head); | ||
48 | +} | ||
49 | + | ||
50 | +__bpf_kfunc static void bpf_list_del_rcu(struct list_head *entry) | ||
51 | +{ | ||
52 | + list_del_rcu(entry); | ||
53 | +} | ||
54 | + | ||
55 | +__bpf_kfunc static struct mptcp_pm_addr_entry * | ||
56 | +bpf_sock_kmalloc_entry(struct sock *sk, int size, gfp_t priority) | ||
57 | +{ | ||
58 | + return sock_kmalloc(sk, size, priority); | ||
59 | +} | ||
60 | + | ||
61 | +__bpf_kfunc static void | ||
62 | +bpf_sock_kfree_entry(struct sock *sk, struct mptcp_pm_addr_entry *entry, | ||
63 | + int size) | ||
64 | +{ | ||
65 | + sock_kfree_s(sk, entry, size); | ||
66 | +} | ||
67 | + | ||
68 | +__bpf_kfunc static void bpf_bitmap_zero(unsigned long *dst__ign, unsigned int nbits) | ||
69 | +{ | ||
70 | + bitmap_zero(dst__ign, nbits); | ||
71 | +} | ||
72 | + | ||
73 | +__bpf_kfunc static void bpf_set_bit(unsigned long nr, unsigned long *addr__ign) | ||
74 | +{ | ||
75 | + __set_bit(nr, addr__ign); | ||
76 | +} | ||
77 | + | ||
78 | +__bpf_kfunc static __u8 bpf_find_next_zero_bit(const unsigned long *addr__ign, | ||
79 | + unsigned long size, unsigned long offset) | ||
80 | +{ | ||
81 | + return find_next_zero_bit(addr__ign, size, offset); | ||
82 | +} | ||
83 | + | ||
84 | +__bpf_kfunc static int | ||
85 | +bpf_mptcp_subflow_connect(struct sock *sk, | ||
86 | + const struct mptcp_pm_addr_entry *entry, | ||
87 | + const struct mptcp_addr_info *remote) | ||
88 | +{ | ||
89 | + struct mptcp_pm_local local; | ||
90 | + | 38 | + |
91 | + local.addr = entry->addr; | 39 | + local.addr = entry->addr; |
92 | + local.flags = entry->flags; | 40 | + local.flags = entry->flags; |
93 | + local.ifindex = entry->ifindex; | 41 | + local.ifindex = entry->ifindex; |
94 | + | 42 | + |
95 | + return __mptcp_subflow_connect(sk, &local, remote); | 43 | + err = __mptcp_subflow_connect(sk, &local, remote); |
44 | + spin_lock_bh(&msk->pm.lock); | ||
45 | + if (err) | ||
46 | + mptcp_userspace_pm_delete_local_addr(msk, entry); | ||
47 | + else | ||
48 | + msk->pm.subflows++; | ||
49 | + spin_unlock_bh(&msk->pm.lock); | ||
50 | + | ||
51 | + return err; | ||
96 | +} | 52 | +} |
97 | + | 53 | + |
98 | +__bpf_kfunc static struct net *bpf_sock_net(const struct sock *sk) | 54 | int mptcp_pm_nl_subflow_create_doit(struct sk_buff *skb, struct genl_info *info) |
99 | +{ | ||
100 | + return sock_net(sk); | ||
101 | +} | ||
102 | + | ||
103 | +__bpf_kfunc static void BPF_MPTCP_INC_STATS(struct net *net, | ||
104 | + enum linux_mptcp_mib_field field) | ||
105 | +{ | ||
106 | + MPTCP_INC_STATS(net, field); | ||
107 | +} | ||
108 | + | ||
109 | __bpf_kfunc static bool bpf_mptcp_subflow_queues_empty(struct sock *sk) | ||
110 | { | 55 | { |
111 | return tcp_rtx_queue_empty(sk); | 56 | struct mptcp_pm_addr_entry entry = { 0 }; |
112 | @@ -XXX,XX +XXX,XX @@ __bpf_kfunc_end_defs(); | 57 | struct mptcp_addr_info addr_r; |
113 | 58 | struct nlattr *raddr, *laddr; | |
114 | BTF_KFUNCS_START(bpf_mptcp_common_kfunc_ids) | 59 | - struct mptcp_pm_local local; |
115 | BTF_ID_FLAGS(func, bpf_mptcp_subflow_ctx, KF_RET_NULL) | 60 | + struct mptcp_pm_param param; |
116 | +BTF_ID_FLAGS(func, bpf_mptcp_subflow_tcp_sock, KF_RET_NULL) | 61 | struct mptcp_sock *msk; |
117 | BTF_ID_FLAGS(func, bpf_iter_mptcp_subflow_new, KF_ITER_NEW | KF_TRUSTED_ARGS) | 62 | int err = -EINVAL; |
118 | BTF_ID_FLAGS(func, bpf_iter_mptcp_subflow_next, KF_ITER_NEXT | KF_RET_NULL) | 63 | struct sock *sk; |
119 | BTF_ID_FLAGS(func, bpf_iter_mptcp_subflow_destroy, KF_ITER_DESTROY) | 64 | @@ -XXX,XX +XXX,XX @@ int mptcp_pm_nl_subflow_create_doit(struct sk_buff *skb, struct genl_info *info) |
120 | @@ -XXX,XX +XXX,XX @@ BTF_ID_FLAGS(func, bpf_iter_mptcp_userspace_pm_addr_destroy, KF_ITER_DESTROY) | 65 | goto create_err; |
121 | BTF_ID_FLAGS(func, bpf_spin_lock_bh) | 66 | } |
122 | BTF_ID_FLAGS(func, bpf_spin_unlock_bh) | 67 | |
123 | BTF_ID_FLAGS(func, bpf_ipv4_is_private_10) | 68 | - err = mptcp_userspace_pm_append_new_local_addr(msk, &entry, false); |
124 | +BTF_ID_FLAGS(func, bpf_list_add_tail_rcu) | 69 | - if (err < 0) { |
125 | +BTF_ID_FLAGS(func, bpf_list_del_rcu) | 70 | - NL_SET_ERR_MSG_ATTR(info->extack, laddr, |
126 | +BTF_ID_FLAGS(func, bpf_sock_kmalloc_entry) | 71 | - "did not match address and id"); |
127 | +BTF_ID_FLAGS(func, bpf_sock_kfree_entry) | 72 | - goto create_err; |
128 | +BTF_ID_FLAGS(func, mptcp_pm_alloc_anno_list) | 73 | - } |
129 | +BTF_ID_FLAGS(func, mptcp_pm_announce_addr) | 74 | - |
130 | +BTF_ID_FLAGS(func, mptcp_pm_nl_addr_send_ack, KF_SLEEPABLE) | 75 | - local.addr = entry.addr; |
131 | +BTF_ID_FLAGS(func, bpf_bitmap_zero) | 76 | - local.flags = entry.flags; |
132 | +BTF_ID_FLAGS(func, bpf_set_bit) | 77 | - local.ifindex = entry.ifindex; |
133 | +BTF_ID_FLAGS(func, bpf_find_next_zero_bit) | 78 | - |
134 | +BTF_ID_FLAGS(func, mptcp_pm_remove_addr) | 79 | lock_sock(sk); |
135 | +BTF_ID_FLAGS(func, mptcp_pm_remove_addr_entry, KF_SLEEPABLE) | 80 | - err = __mptcp_subflow_connect(sk, &local, &addr_r); |
136 | +BTF_ID_FLAGS(func, bpf_mptcp_subflow_connect, KF_SLEEPABLE) | 81 | + mptcp_pm_param_set_contexts(¶m, &entry, &addr_r); |
137 | +BTF_ID_FLAGS(func, mptcp_subflow_shutdown, KF_SLEEPABLE) | 82 | + err = msk->pm.ops && msk->pm.ops->subflow_established ? |
138 | +BTF_ID_FLAGS(func, mptcp_close_ssk, KF_SLEEPABLE) | 83 | + msk->pm.ops->subflow_established(msk, ¶m) : |
139 | +BTF_ID_FLAGS(func, bpf_sock_net) | 84 | + mptcp_userspace_pm_subflow_established(msk, ¶m); |
140 | +BTF_ID_FLAGS(func, BPF_MPTCP_INC_STATS) | 85 | release_sock(sk); |
141 | +BTF_ID_FLAGS(func, mptcp_pm_nl_mp_prio_send_ack, KF_SLEEPABLE) | 86 | |
142 | BTF_ID_FLAGS(func, bpf_mptcp_sock_acquire, KF_ACQUIRE | KF_RET_NULL) | 87 | if (err) |
143 | BTF_ID_FLAGS(func, bpf_mptcp_sock_release, KF_RELEASE) | 88 | GENL_SET_ERR_MSG_FMT(info, "connect error: %d", err); |
144 | BTF_KFUNCS_END(bpf_mptcp_common_kfunc_ids) | 89 | |
145 | @@ -XXX,XX +XXX,XX @@ static int __init bpf_mptcp_kfunc_init(void) | 90 | - spin_lock_bh(&msk->pm.lock); |
146 | ret = register_btf_fmodret_id_set(&bpf_mptcp_fmodret_set); | 91 | - if (err) |
147 | ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_CGROUP_SOCKOPT, | 92 | - mptcp_userspace_pm_delete_local_addr(msk, &entry); |
148 | &bpf_mptcp_common_kfunc_set); | 93 | - else |
149 | + ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, | 94 | - msk->pm.subflows++; |
150 | + &bpf_mptcp_common_kfunc_set); | 95 | - spin_unlock_bh(&msk->pm.lock); |
151 | ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, | 96 | - |
152 | &bpf_mptcp_sched_kfunc_set); | 97 | create_err: |
153 | #ifdef CONFIG_BPF_JIT | 98 | sock_put(sk); |
99 | return err; | ||
100 | @@ -XXX,XX +XXX,XX @@ int mptcp_userspace_pm_get_addr(u8 id, struct mptcp_pm_addr_entry *addr, | ||
101 | static struct mptcp_pm_ops mptcp_userspace_pm = { | ||
102 | .address_announced = mptcp_userspace_pm_address_announced, | ||
103 | .address_removed = mptcp_userspace_pm_address_removed, | ||
104 | + .subflow_established = mptcp_userspace_pm_subflow_established, | ||
105 | .get_local_id = mptcp_userspace_pm_get_local_id, | ||
106 | .get_priority = mptcp_userspace_pm_get_priority, | ||
107 | .type = MPTCP_PM_TYPE_USERSPACE, | ||
154 | -- | 108 | -- |
155 | 2.43.0 | 109 | 2.43.0 | diff view generated by jsdifflib |
1 | From: Geliang Tang <tanggeliang@kylinos.cn> | 1 | From: Geliang Tang <tanggeliang@kylinos.cn> |
---|---|---|---|
2 | 2 | ||
3 | This patch implements MPTCP path manager helpers mptcp_pm_copy_addr(), | 3 | Extract subflow_closed() interface of the userspace PM from the handler of |
4 | mptcp_pm_copy_entry(), ipv6_addr_equal(), mptcp_addresses_equal() and | 4 | netlink command MPTCP_PM_CMD_SUBFLOW_DESTROY |
5 | mptcp_pm_find_ssk() in BPF. | 5 | |
6 | mptcp_pm_nl_subflow_destroy_doit(), | ||
7 | |||
8 | only leave the code for obtaining msk through "info", parsing local address | ||
9 | entry and parsing remote address info in the handler. | ||
10 | |||
11 | This interface is invoked under holding the msk socket lock. | ||
6 | 12 | ||
7 | Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> | 13 | Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> |
8 | --- | 14 | --- |
9 | tools/testing/selftests/bpf/progs/mptcp_bpf.h | 110 ++++++++++++++++++ | 15 | net/mptcp/pm_userspace.c | 45 ++++++++++++++++++++++++++-------------- |
10 | 1 file changed, 110 insertions(+) | 16 | 1 file changed, 30 insertions(+), 15 deletions(-) |
11 | 17 | ||
12 | diff --git a/tools/testing/selftests/bpf/progs/mptcp_bpf.h b/tools/testing/selftests/bpf/progs/mptcp_bpf.h | 18 | diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c |
13 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/tools/testing/selftests/bpf/progs/mptcp_bpf.h | 20 | --- a/net/mptcp/pm_userspace.c |
15 | +++ b/tools/testing/selftests/bpf/progs/mptcp_bpf.h | 21 | +++ b/net/mptcp/pm_userspace.c |
16 | @@ -XXX,XX +XXX,XX @@ | 22 | @@ -XXX,XX +XXX,XX @@ static struct sock *mptcp_nl_find_ssk(struct mptcp_sock *msk, |
17 | #define __MPTCP_BPF_H__ | 23 | return NULL; |
18 | 24 | } | |
19 | #include "bpf_experimental.h" | 25 | |
20 | +#include "bpf_tracing_net.h" | 26 | +static int mptcp_userspace_pm_subflow_closed(struct mptcp_sock *msk, |
21 | 27 | + struct mptcp_pm_param *param) | |
22 | /* mptcp helpers from include/net/mptcp.h */ | 28 | +{ |
23 | #define MPTCP_SUBFLOWS_MAX 8 | 29 | + struct mptcp_pm_addr_entry *local = ¶m->entry; |
24 | @@ -XXX,XX +XXX,XX @@ static inline int list_is_head(const struct list_head *list, | 30 | + struct mptcp_addr_info *remote = ¶m->addr; |
25 | #define mptcp_for_each_subflow(__msk, __subflow) \ | 31 | + struct sock *ssk, *sk = (struct sock *)msk; |
26 | list_for_each_entry(__subflow, &((__msk)->conn_list), node) | ||
27 | |||
28 | +/* errno macros from include/uapi/asm-generic/errno-base.h */ | ||
29 | +#define ESRCH 3 /* No such process */ | ||
30 | +#define ENOMEM 12 /* Out of Memory */ | ||
31 | +#define EINVAL 22 /* Invalid argument */ | ||
32 | + | 32 | + |
33 | static __always_inline struct sock * | 33 | + ssk = mptcp_nl_find_ssk(msk, &local->addr, remote); |
34 | mptcp_subflow_tcp_sock(const struct mptcp_subflow_context *subflow) | 34 | + if (!ssk) |
35 | { | 35 | + return -ESRCH; |
36 | @@ -XXX,XX +XXX,XX @@ extern void mptcp_subflow_set_scheduled(struct mptcp_subflow_context *subflow, | ||
37 | extern struct mptcp_subflow_context * | ||
38 | bpf_mptcp_subflow_ctx_by_pos(const struct mptcp_sched_data *data, unsigned int pos) __ksym; | ||
39 | |||
40 | +/* reimplemented BPF helpers */ | ||
41 | +static __always_inline void | ||
42 | +mptcp_pm_copy_addr(struct mptcp_addr_info *dst, | ||
43 | + struct mptcp_addr_info *src) | ||
44 | +{ | ||
45 | + dst->id = src->id; | ||
46 | + dst->family = src->family; | ||
47 | + dst->port = src->port; | ||
48 | + | 36 | + |
49 | + if (src->family == AF_INET) { | 37 | + spin_lock_bh(&msk->pm.lock); |
50 | + dst->addr.s_addr = src->addr.s_addr; | 38 | + mptcp_userspace_pm_delete_local_addr(msk, local); |
51 | + } else if (src->family == AF_INET6) { | 39 | + spin_unlock_bh(&msk->pm.lock); |
52 | + dst->addr6.s6_addr32[0] = src->addr6.s6_addr32[0]; | 40 | + mptcp_subflow_shutdown(sk, ssk, RCV_SHUTDOWN | SEND_SHUTDOWN); |
53 | + dst->addr6.s6_addr32[1] = src->addr6.s6_addr32[1]; | 41 | + mptcp_close_ssk(sk, ssk, mptcp_subflow_ctx(ssk)); |
54 | + dst->addr6.s6_addr32[2] = src->addr6.s6_addr32[2]; | 42 | + MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RMSUBFLOW); |
55 | + dst->addr6.s6_addr32[3] = src->addr6.s6_addr32[3]; | 43 | + |
56 | + } | 44 | + return 0; |
57 | +} | 45 | +} |
58 | + | 46 | + |
59 | +static __always_inline void | 47 | int mptcp_pm_nl_subflow_destroy_doit(struct sk_buff *skb, struct genl_info *info) |
60 | +mptcp_pm_copy_entry(struct mptcp_pm_addr_entry *dst, | 48 | { |
61 | + struct mptcp_pm_addr_entry *src) | 49 | struct mptcp_pm_addr_entry addr_l; |
62 | +{ | 50 | struct mptcp_addr_info addr_r; |
63 | + mptcp_pm_copy_addr(&dst->addr, &src->addr); | 51 | struct nlattr *raddr, *laddr; |
64 | + | 52 | + struct mptcp_pm_param param; |
65 | + dst->flags = src->flags; | 53 | struct mptcp_sock *msk; |
66 | + dst->ifindex = src->ifindex; | 54 | - struct sock *sk, *ssk; |
67 | +} | 55 | int err = -EINVAL; |
68 | + | 56 | + struct sock *sk; |
69 | +#define inet_sk(ptr) container_of(ptr, struct inet_sock, sk) | 57 | |
70 | + | 58 | if (GENL_REQ_ATTR_CHECK(info, MPTCP_PM_ATTR_ADDR) || |
71 | +#define ipv6_addr_equal(a, b) ((a).s6_addr32[0] == (b).s6_addr32[0] && \ | 59 | GENL_REQ_ATTR_CHECK(info, MPTCP_PM_ATTR_ADDR_REMOTE)) |
72 | + (a).s6_addr32[1] == (b).s6_addr32[1] && \ | 60 | @@ -XXX,XX +XXX,XX @@ int mptcp_pm_nl_subflow_destroy_doit(struct sk_buff *skb, struct genl_info *info |
73 | + (a).s6_addr32[2] == (b).s6_addr32[2] && \ | 61 | } |
74 | + (a).s6_addr32[3] == (b).s6_addr32[3]) | 62 | |
75 | + | 63 | lock_sock(sk); |
76 | +static __always_inline bool | 64 | - ssk = mptcp_nl_find_ssk(msk, &addr_l.addr, &addr_r); |
77 | +mptcp_addresses_equal(const struct mptcp_addr_info *a, | 65 | - if (!ssk) { |
78 | + const struct mptcp_addr_info *b, bool use_port) | 66 | - GENL_SET_ERR_MSG(info, "subflow not found"); |
79 | +{ | 67 | - err = -ESRCH; |
80 | + bool addr_equals = false; | 68 | - goto release_sock; |
81 | + | 69 | - } |
82 | + if (a->family == b->family) { | 70 | - |
83 | + if (a->family == AF_INET) | 71 | - spin_lock_bh(&msk->pm.lock); |
84 | + addr_equals = a->addr.s_addr == b->addr.s_addr; | 72 | - mptcp_userspace_pm_delete_local_addr(msk, &addr_l); |
85 | + else | 73 | - spin_unlock_bh(&msk->pm.lock); |
86 | + addr_equals = ipv6_addr_equal(a->addr6, b->addr6); | 74 | - mptcp_subflow_shutdown(sk, ssk, RCV_SHUTDOWN | SEND_SHUTDOWN); |
87 | + } | 75 | - mptcp_close_ssk(sk, ssk, mptcp_subflow_ctx(ssk)); |
88 | + | 76 | - MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RMSUBFLOW); |
89 | + if (!addr_equals) | 77 | -release_sock: |
90 | + return false; | 78 | + mptcp_pm_param_set_contexts(¶m, &addr_l, &addr_r); |
91 | + if (!use_port) | 79 | + err = msk->pm.ops && msk->pm.ops->subflow_closed ? |
92 | + return true; | 80 | + msk->pm.ops->subflow_closed(msk, ¶m) : |
93 | + | 81 | + mptcp_userspace_pm_subflow_closed(msk, ¶m); |
94 | + return a->port == b->port; | 82 | release_sock(sk); |
95 | +} | 83 | + if (err) |
96 | + | 84 | + GENL_SET_ERR_MSG(info, "subflow not found"); |
97 | +static __always_inline struct sock * | 85 | |
98 | +mptcp_pm_find_ssk(struct mptcp_sock *msk, | 86 | destroy_err: |
99 | + const struct mptcp_addr_info *local, | 87 | sock_put(sk); |
100 | + const struct mptcp_addr_info *remote) | 88 | @@ -XXX,XX +XXX,XX @@ static struct mptcp_pm_ops mptcp_userspace_pm = { |
101 | +{ | 89 | .address_announced = mptcp_userspace_pm_address_announced, |
102 | + struct mptcp_subflow_context *subflow; | 90 | .address_removed = mptcp_userspace_pm_address_removed, |
103 | + | 91 | .subflow_established = mptcp_userspace_pm_subflow_established, |
104 | + if (local->family != remote->family) | 92 | + .subflow_closed = mptcp_userspace_pm_subflow_closed, |
105 | + return NULL; | 93 | .get_local_id = mptcp_userspace_pm_get_local_id, |
106 | + | 94 | .get_priority = mptcp_userspace_pm_get_priority, |
107 | + bpf_for_each(mptcp_subflow, subflow, msk) { | 95 | .type = MPTCP_PM_TYPE_USERSPACE, |
108 | + const struct inet_sock *issk; | ||
109 | + struct sock *ssk; | ||
110 | + | ||
111 | + ssk = bpf_mptcp_subflow_tcp_sock(subflow); | ||
112 | + if (!ssk) | ||
113 | + continue; | ||
114 | + | ||
115 | + if (local->family != ssk->sk_family) | ||
116 | + continue; | ||
117 | + | ||
118 | + issk = bpf_core_cast(inet_sk(ssk), struct inet_sock); | ||
119 | + | ||
120 | + switch (ssk->sk_family) { | ||
121 | + case AF_INET: | ||
122 | + if (issk->inet_saddr != local->addr.s_addr || | ||
123 | + issk->inet_daddr != remote->addr.s_addr) | ||
124 | + continue; | ||
125 | + break; | ||
126 | + case AF_INET6: { | ||
127 | + if (!ipv6_addr_equal(local->addr6, issk->pinet6->saddr) || | ||
128 | + !ipv6_addr_equal(remote->addr6, ssk->sk_v6_daddr)) | ||
129 | + continue; | ||
130 | + break; | ||
131 | + } | ||
132 | + default: | ||
133 | + continue; | ||
134 | + } | ||
135 | + | ||
136 | + if (issk->inet_sport == local->port && | ||
137 | + issk->inet_dport == remote->port) | ||
138 | + return ssk; | ||
139 | + } | ||
140 | + | ||
141 | + return NULL; | ||
142 | +} | ||
143 | + | ||
144 | #endif | ||
145 | -- | 96 | -- |
146 | 2.43.0 | 97 | 2.43.0 | diff view generated by jsdifflib |