* Re: [MPTCP] [RFC PATCH] mptcp:pm: sysctl to announce an addr
@ 2019-08-22 22:49 Peter Krystad
0 siblings, 0 replies; 4+ messages in thread
From: Peter Krystad @ 2019-08-22 22:49 UTC (permalink / raw)
To: mptcp
[-- Attachment #1: Type: text/plain, Size: 7016 bytes --]
Hi Matthieu -
Thanks for this patch, I tested it in my setup and it works fine except for
the endianess issue noted below.
I am OK with merging this with my RFC patch into a single interim path manager
commit. The idea of moving the interim pm to a separate file is good, I think
just the two triggering hooks in pm_fully_established() and
pm_new_connection() plus an init hook need to be in pm.c.
I don't care what the file name is...
Regards,
Peter.
On Tue, 2019-08-20 at 17:16 +0200, Matthieu Baerts wrote:
> Instead of hard-coding the address in the code, we can now dynamically
> pass the value and allow tests.
>
> Signed-off-by: Matthieu Baerts <matthieu.baerts(a)tessares.net>
> ---
>
> Notes:
> Here is an RFC patch that I built on top of Peter's patch. This patch
> (mptcp: Implement interim path manager) is also marked as RFC.
>
> So far, I only tested that the sysctl was OK, I didn't validate that the
> address was correctly announced.
>
> net/mptcp/pm.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 166 insertions(+), 3 deletions(-)
>
> diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
> index d43d05511e69..b3c83e3cadb1 100644
> --- a/net/mptcp/pm.c
> +++ b/net/mptcp/pm.c
> @@ -3,11 +3,28 @@
> *
> * Copyright (c) 2019, Intel Corporation.
> */
> +#include <linux/inet.h>
> #include <linux/kernel.h>
> #include <net/tcp.h>
> +#include <net/netns/generic.h>
> #include <net/mptcp.h>
> #include "protocol.h"
>
> +static int pm_pernet_id;
> +
> +struct pm_pernet {
> + struct ctl_table_header *ctl_table_hdr;
> +
> + union {
> + struct in_addr announce_v4_addr;
> +#if IS_ENABLED(CONFIG_IPV6)
> + struct in6_addr announce_v6_addr;
> +#endif
> + };
> + u8 has_announce_v4 : 1,
> + has_announce_v6 : 1;
> +};
> +
> struct workqueue_struct *mptcp_wq;
> static void announce_addr_worker(struct work_struct *work);
> static void create_subflow_worker(struct work_struct *work);
> @@ -203,8 +220,150 @@ int pm_get_local_id(struct request_sock *req, struct sock *sk,
> return 0;
> }
>
> +static int pm_parse_addr(struct pm_pernet *pernet, const char *addr)
> +{
> +#if IS_ENABLED(CONFIG_IPV6)
> + if (in6_pton(addr, -1, (u8 *)&pernet->announce_v6_addr.s6_addr, '\0',
> + NULL) > 0) {
> + pernet->has_announce_v4 = 0;
> + pernet->has_announce_v6 = 1;
> + return 0;
> + }
> +#endif
> +
> + if (in4_pton(addr, -1, (u8 *)&pernet->announce_v4_addr.s_addr, '\0',
> + NULL) > 0) {
pm_announce_addr() [and code for OPTION_MPTCP_ADD_ADDR in
mptcp_write_options()] is expecting this address to be in host byte order. We
used host byte order for everything in mptcp_pm_data and subflow_context.
In my tests the address is reversed in the ADD_ADDR option over the wire..
Peter.
> + pernet->has_announce_v4 = 1;
> + pernet->has_announce_v6 = 0;
> + return 0;
> + }
> +
> + pernet->has_announce_v4 = 0;
> + pernet->has_announce_v6 = 0;
> +
> + return -1;
> +}
> +
> +static int pm_proc_parse_addr(struct ctl_table *ctl, int write,
> + void __user *buffer, size_t *lenp, loff_t *ppos)
> +{
> + struct net *net = current->nsproxy->net_ns;
> + struct pm_pernet *pernet = net_generic(net, pm_pernet_id);
> + struct ctl_table tbl;
> +
> + char *none = "none";
> + char tmp[INET6_ADDRSTRLEN] = { 0 };
> + int ret;
> +
> + memset(&tbl, 0, sizeof(struct ctl_table));
> +
> + if (write) {
> + tbl.data = tmp;
> + tbl.maxlen = sizeof(tmp);
> + } else {
> +#if IS_ENABLED(CONFIG_IPV6)
> + if (pernet->has_announce_v6) {
> + snprintf(tmp, INET6_ADDRSTRLEN, "%pI6c",
> + &pernet->announce_v6_addr);
> + tbl.data = tmp;
> + } else
> +#endif
> + if (pernet->has_announce_v4) {
> + snprintf(tmp, INET_ADDRSTRLEN, "%pI4",
> + &pernet->announce_v4_addr);
> + tbl.data = tmp;
> + } else {
> + tbl.data = none;
> + }
> + tbl.maxlen = strlen(tbl.data);
> + }
> +
> + ret = proc_dostring(&tbl, write, buffer, lenp, ppos);
> + if (write && ret == 0) {
> + /* "none" string: we want to remove it */
> + if (strncmp(none, tmp, 5) == 0) {
> + pernet->has_announce_v4 = 0;
> + pernet->has_announce_v6 = 0;
> + } else if (pm_parse_addr(pernet, tmp) < 0) {
> + ret = -EINVAL;
> + }
> + }
> +
> + return ret;
> +}
> +
> +static struct ctl_table pm_sysctl_table[] = {
> + {
> + .procname = "announce_addr",
> + .maxlen = sizeof(char) * (INET6_ADDRSTRLEN),
> + .mode = 0644,
> + .proc_handler = pm_proc_parse_addr
> + },
> + {}
> +};
> +
> +static int pm_pernet_create_table(struct net *net, struct pm_pernet *pernet)
> +{
> + struct ctl_table *table;
> + struct ctl_table_header *hdr;
> +
> + table = pm_sysctl_table;
> + if (!net_eq(net, &init_net)) {
> + table = kmemdup(table, sizeof(pm_sysctl_table), GFP_KERNEL);
> + if (!table)
> + goto err_alloc;
> + }
> +
> + hdr = register_net_sysctl(net, "net/mptcp/pm", table);
> + if (!hdr)
> + goto err_reg;
> +
> + pernet->ctl_table_hdr = hdr;
> +
> + return 0;
> +
> +err_reg:
> + if (!net_eq(net, &init_net))
> + kfree(table);
> +err_alloc:
> + return -ENOMEM;
> +}
> +
> +static int __net_init pm_init_net(struct net *net)
> +{
> + struct pm_pernet *pernet = net_generic(net, pm_pernet_id);
> + int ret;
> +
> + ret = pm_pernet_create_table(net, pernet);
> + if (ret < 0)
> + return ret;
> +
> + return 0;
> +}
> +
> +static void __net_exit pm_exit_net(struct net *net)
> +{
> + struct pm_pernet *pernet = net_generic(net, pm_pernet_id);
> + struct ctl_table *table = pernet->ctl_table_hdr->ctl_table_arg;
> +
> + unregister_net_sysctl_table(pernet->ctl_table_hdr);
> +
> + /* Note: the callback will only be called per extra netns */
> + kfree(table);
> +}
> +
> +static struct pernet_operations pm_pernet_ops = {
> + .init = pm_init_net,
> + .exit = pm_exit_net,
> + .id = &pm_pernet_id,
> + .size = sizeof(struct pm_pernet),
> +};
> +
> void pm_init(void)
> {
> + if (register_pernet_subsys(&pm_pernet_ops) < 0)
> + panic("Failed to register MPTCP PM pernet subsystem.\n");
> +
> mptcp_wq = alloc_workqueue("mptcp_wq", WQ_UNBOUND | WQ_MEM_RECLAIM, 8);
> if (!mptcp_wq)
> panic("Failed to allocate workqueue");
> @@ -214,10 +373,14 @@ static void announce_addr_worker(struct work_struct *work)
> {
> struct mptcp_pm_data *pm = container_of(work, struct mptcp_pm_data,
> addr_work);
> - struct in_addr addr;
> + struct mptcp_sock *msk = container_of(pm, struct mptcp_sock, pm);
> + struct pm_pernet *pernet;
> +
> + pernet = net_generic(sock_net((struct sock *)msk), pm_pernet_id);
>
> - /* @@ hard-code address to announce here... */
> - pm_announce_addr(pm->token, AF_INET, 1, &addr);
> + if (pernet->has_announce_v4)
> + pm_announce_addr(pm->token, AF_INET, 1,
> + &pernet->announce_v4_addr);
> }
>
> static void create_subflow_worker(struct work_struct *work)
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [MPTCP] [RFC PATCH] mptcp:pm: sysctl to announce an addr
@ 2019-08-23 14:36 Peter Krystad
0 siblings, 0 replies; 4+ messages in thread
From: Peter Krystad @ 2019-08-23 14:36 UTC (permalink / raw)
To: mptcp
[-- Attachment #1: Type: text/plain, Size: 2359 bytes --]
Hi Florian -
On Fri, 2019-08-23 at 15:55 +0200, Florian Westphal wrote:
> Peter Krystad <peter.krystad(a)linux.intel.com> wrote:
> > Hi Matthieu -
> >
> > Thanks for this patch, I tested it in my setup and it works fine except for
> > the endianess issue noted below.
>
> [..]
>
> > > + if (in4_pton(addr, -1, (u8 *)&pernet->announce_v4_addr.s_addr, '\0',
> > > + NULL) > 0) {
> >
> > pm_announce_addr() [and code for OPTION_MPTCP_ADD_ADDR in
> > mptcp_write_options()] is expecting this address to be in host byte order. We
> > used host byte order for everything in mptcp_pm_data and subflow_context.
> > In my tests the address is reversed in the ADD_ADDR option over the wire..
>
> That looks like a bug in pm and options however -- when I see a struct
> inaddr I expect it to store network byte order.
Fair enough, I'll revise pm/option to use network order for addresses.
Peter.
>
> So, either those should use u32, or pm/option handling should assume
> network byte order, i.e.:
>
> diff --git a/net/mptcp/options.c b/net/mptcp/options.c
> index 4a9aac4710be..9f892478d336 100644
> --- a/net/mptcp/options.c
> +++ b/net/mptcp/options.c
> @@ -603,7 +603,7 @@ void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts)
> if (OPTION_MPTCP_ADD_ADDR & opts->suboptions) {
> *ptr++ = mptcp_option(MPTCPOPT_ADD_ADDR, TCPOLEN_MPTCP_ADD_ADDR,
> MPTCP_ADDR_IPVERSION_4, opts->addr_id);
> - *ptr++ = htonl(opts->addr.s_addr);
> + *ptr++ = opts->addr.s_addr;
> }
>
> #if IS_ENABLED(CONFIG_IPV6)
> diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
> index 501ff67284a4..32be34a5f951 100644
> --- a/net/mptcp/pm.c
> +++ b/net/mptcp/pm.c
> @@ -93,7 +93,7 @@ int pm_create_subflow(u32 token, u8 remote_id)
>
> remote.sin_family = msk->pm.remote_family;
> remote.sin_port = htons(msk->dport);
> - remote.sin_addr.s_addr = htonl(msk->pm.remote_addr.s_addr);
> + remote.sin_addr = msk->pm.remote_addr;
>
> err = subflow_connect((struct sock *)msk, &local, &remote, remote_id);
>
>
>
> The ipv6 ADD_ADDR handling uses memcpy, so assumes network
> byte order, so I think the above makes more sense than to tweak
> Mathieus patch (thanks!).
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [MPTCP] [RFC PATCH] mptcp:pm: sysctl to announce an addr
@ 2019-08-23 13:55 Florian Westphal
0 siblings, 0 replies; 4+ messages in thread
From: Florian Westphal @ 2019-08-23 13:55 UTC (permalink / raw)
To: mptcp
[-- Attachment #1: Type: text/plain, Size: 2091 bytes --]
Peter Krystad <peter.krystad(a)linux.intel.com> wrote:
>
> Hi Matthieu -
>
> Thanks for this patch, I tested it in my setup and it works fine except for
> the endianess issue noted below.
[..]
> > + if (in4_pton(addr, -1, (u8 *)&pernet->announce_v4_addr.s_addr, '\0',
> > + NULL) > 0) {
>
> pm_announce_addr() [and code for OPTION_MPTCP_ADD_ADDR in
> mptcp_write_options()] is expecting this address to be in host byte order. We
> used host byte order for everything in mptcp_pm_data and subflow_context.
> In my tests the address is reversed in the ADD_ADDR option over the wire..
That looks like a bug in pm and options however -- when I see a struct
inaddr I expect it to store network byte order.
So, either those should use u32, or pm/option handling should assume
network byte order, i.e.:
diff --git a/net/mptcp/options.c b/net/mptcp/options.c
index 4a9aac4710be..9f892478d336 100644
--- a/net/mptcp/options.c
+++ b/net/mptcp/options.c
@@ -603,7 +603,7 @@ void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts)
if (OPTION_MPTCP_ADD_ADDR & opts->suboptions) {
*ptr++ = mptcp_option(MPTCPOPT_ADD_ADDR, TCPOLEN_MPTCP_ADD_ADDR,
MPTCP_ADDR_IPVERSION_4, opts->addr_id);
- *ptr++ = htonl(opts->addr.s_addr);
+ *ptr++ = opts->addr.s_addr;
}
#if IS_ENABLED(CONFIG_IPV6)
diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
index 501ff67284a4..32be34a5f951 100644
--- a/net/mptcp/pm.c
+++ b/net/mptcp/pm.c
@@ -93,7 +93,7 @@ int pm_create_subflow(u32 token, u8 remote_id)
remote.sin_family = msk->pm.remote_family;
remote.sin_port = htons(msk->dport);
- remote.sin_addr.s_addr = htonl(msk->pm.remote_addr.s_addr);
+ remote.sin_addr = msk->pm.remote_addr;
err = subflow_connect((struct sock *)msk, &local, &remote, remote_id);
The ipv6 ADD_ADDR handling uses memcpy, so assumes network
byte order, so I think the above makes more sense than to tweak
Mathieus patch (thanks!).
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [MPTCP] [RFC PATCH] mptcp:pm: sysctl to announce an addr
@ 2019-08-20 15:16 Matthieu Baerts
0 siblings, 0 replies; 4+ messages in thread
From: Matthieu Baerts @ 2019-08-20 15:16 UTC (permalink / raw)
To: mptcp
[-- Attachment #1: Type: text/plain, Size: 5752 bytes --]
Instead of hard-coding the address in the code, we can now dynamically
pass the value and allow tests.
Signed-off-by: Matthieu Baerts <matthieu.baerts(a)tessares.net>
---
Notes:
Here is an RFC patch that I built on top of Peter's patch. This patch
(mptcp: Implement interim path manager) is also marked as RFC.
So far, I only tested that the sysctl was OK, I didn't validate that the
address was correctly announced.
net/mptcp/pm.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 166 insertions(+), 3 deletions(-)
diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
index d43d05511e69..b3c83e3cadb1 100644
--- a/net/mptcp/pm.c
+++ b/net/mptcp/pm.c
@@ -3,11 +3,28 @@
*
* Copyright (c) 2019, Intel Corporation.
*/
+#include <linux/inet.h>
#include <linux/kernel.h>
#include <net/tcp.h>
+#include <net/netns/generic.h>
#include <net/mptcp.h>
#include "protocol.h"
+static int pm_pernet_id;
+
+struct pm_pernet {
+ struct ctl_table_header *ctl_table_hdr;
+
+ union {
+ struct in_addr announce_v4_addr;
+#if IS_ENABLED(CONFIG_IPV6)
+ struct in6_addr announce_v6_addr;
+#endif
+ };
+ u8 has_announce_v4 : 1,
+ has_announce_v6 : 1;
+};
+
struct workqueue_struct *mptcp_wq;
static void announce_addr_worker(struct work_struct *work);
static void create_subflow_worker(struct work_struct *work);
@@ -203,8 +220,150 @@ int pm_get_local_id(struct request_sock *req, struct sock *sk,
return 0;
}
+static int pm_parse_addr(struct pm_pernet *pernet, const char *addr)
+{
+#if IS_ENABLED(CONFIG_IPV6)
+ if (in6_pton(addr, -1, (u8 *)&pernet->announce_v6_addr.s6_addr, '\0',
+ NULL) > 0) {
+ pernet->has_announce_v4 = 0;
+ pernet->has_announce_v6 = 1;
+ return 0;
+ }
+#endif
+
+ if (in4_pton(addr, -1, (u8 *)&pernet->announce_v4_addr.s_addr, '\0',
+ NULL) > 0) {
+ pernet->has_announce_v4 = 1;
+ pernet->has_announce_v6 = 0;
+ return 0;
+ }
+
+ pernet->has_announce_v4 = 0;
+ pernet->has_announce_v6 = 0;
+
+ return -1;
+}
+
+static int pm_proc_parse_addr(struct ctl_table *ctl, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ struct net *net = current->nsproxy->net_ns;
+ struct pm_pernet *pernet = net_generic(net, pm_pernet_id);
+ struct ctl_table tbl;
+
+ char *none = "none";
+ char tmp[INET6_ADDRSTRLEN] = { 0 };
+ int ret;
+
+ memset(&tbl, 0, sizeof(struct ctl_table));
+
+ if (write) {
+ tbl.data = tmp;
+ tbl.maxlen = sizeof(tmp);
+ } else {
+#if IS_ENABLED(CONFIG_IPV6)
+ if (pernet->has_announce_v6) {
+ snprintf(tmp, INET6_ADDRSTRLEN, "%pI6c",
+ &pernet->announce_v6_addr);
+ tbl.data = tmp;
+ } else
+#endif
+ if (pernet->has_announce_v4) {
+ snprintf(tmp, INET_ADDRSTRLEN, "%pI4",
+ &pernet->announce_v4_addr);
+ tbl.data = tmp;
+ } else {
+ tbl.data = none;
+ }
+ tbl.maxlen = strlen(tbl.data);
+ }
+
+ ret = proc_dostring(&tbl, write, buffer, lenp, ppos);
+ if (write && ret == 0) {
+ /* "none" string: we want to remove it */
+ if (strncmp(none, tmp, 5) == 0) {
+ pernet->has_announce_v4 = 0;
+ pernet->has_announce_v6 = 0;
+ } else if (pm_parse_addr(pernet, tmp) < 0) {
+ ret = -EINVAL;
+ }
+ }
+
+ return ret;
+}
+
+static struct ctl_table pm_sysctl_table[] = {
+ {
+ .procname = "announce_addr",
+ .maxlen = sizeof(char) * (INET6_ADDRSTRLEN),
+ .mode = 0644,
+ .proc_handler = pm_proc_parse_addr
+ },
+ {}
+};
+
+static int pm_pernet_create_table(struct net *net, struct pm_pernet *pernet)
+{
+ struct ctl_table *table;
+ struct ctl_table_header *hdr;
+
+ table = pm_sysctl_table;
+ if (!net_eq(net, &init_net)) {
+ table = kmemdup(table, sizeof(pm_sysctl_table), GFP_KERNEL);
+ if (!table)
+ goto err_alloc;
+ }
+
+ hdr = register_net_sysctl(net, "net/mptcp/pm", table);
+ if (!hdr)
+ goto err_reg;
+
+ pernet->ctl_table_hdr = hdr;
+
+ return 0;
+
+err_reg:
+ if (!net_eq(net, &init_net))
+ kfree(table);
+err_alloc:
+ return -ENOMEM;
+}
+
+static int __net_init pm_init_net(struct net *net)
+{
+ struct pm_pernet *pernet = net_generic(net, pm_pernet_id);
+ int ret;
+
+ ret = pm_pernet_create_table(net, pernet);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static void __net_exit pm_exit_net(struct net *net)
+{
+ struct pm_pernet *pernet = net_generic(net, pm_pernet_id);
+ struct ctl_table *table = pernet->ctl_table_hdr->ctl_table_arg;
+
+ unregister_net_sysctl_table(pernet->ctl_table_hdr);
+
+ /* Note: the callback will only be called per extra netns */
+ kfree(table);
+}
+
+static struct pernet_operations pm_pernet_ops = {
+ .init = pm_init_net,
+ .exit = pm_exit_net,
+ .id = &pm_pernet_id,
+ .size = sizeof(struct pm_pernet),
+};
+
void pm_init(void)
{
+ if (register_pernet_subsys(&pm_pernet_ops) < 0)
+ panic("Failed to register MPTCP PM pernet subsystem.\n");
+
mptcp_wq = alloc_workqueue("mptcp_wq", WQ_UNBOUND | WQ_MEM_RECLAIM, 8);
if (!mptcp_wq)
panic("Failed to allocate workqueue");
@@ -214,10 +373,14 @@ static void announce_addr_worker(struct work_struct *work)
{
struct mptcp_pm_data *pm = container_of(work, struct mptcp_pm_data,
addr_work);
- struct in_addr addr;
+ struct mptcp_sock *msk = container_of(pm, struct mptcp_sock, pm);
+ struct pm_pernet *pernet;
+
+ pernet = net_generic(sock_net((struct sock *)msk), pm_pernet_id);
- /* @@ hard-code address to announce here... */
- pm_announce_addr(pm->token, AF_INET, 1, &addr);
+ if (pernet->has_announce_v4)
+ pm_announce_addr(pm->token, AF_INET, 1,
+ &pernet->announce_v4_addr);
}
static void create_subflow_worker(struct work_struct *work)
--
2.20.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2019-08-23 14:36 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-22 22:49 [MPTCP] [RFC PATCH] mptcp:pm: sysctl to announce an addr Peter Krystad
-- strict thread matches above, loose matches on Subject: below --
2019-08-23 14:36 Peter Krystad
2019-08-23 13:55 Florian Westphal
2019-08-20 15:16 Matthieu Baerts
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.