Message ID | 65a08c10aa83d4cc6861b1c2b9534fa8b9e1cae1.1585234717.git.pabeni@redhat.com |
---|---|
State | Superseded, archived |
Delegated to: | Mat Martineau |
Headers | show |
Series | iproute: mptcp support | expand |
On Thu, 26 Mar 2020, Paolo Abeni wrote: > Implement basic commands to: > - manipulate MPTCP local addresses list > - manipulate MPTCP connection limits > > Examples: > 1. Allows multiple subflows per MPTCP connection > $ ip mptcp limits subflows 2 > > 2. Accept ADD_ADDR announcement from the peer (server): > $ ip mptcp limits add_addr_accepted 2 > > 3. Add a ipv4 address to be annunced for backup subflows: > $ip mptcp address add 10.99.1.2 signal backup > > 4. Add an ipv6 address used as source for additional subflows: > $ip mptcp address add 2001::2 subflow > > Signed-off-by: Paolo Abeni <pabeni@redhat.com> > --- > diff --git a/ip/ipmptcp.c b/ip/ipmptcp.c > new file mode 100644 > index 00000000..1ff66a7b > --- /dev/null > +++ b/ip/ipmptcp.c > @@ -0,0 +1,446 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +#include <stdio.h> > +#include <string.h> > +#include <rt_names.h> > +#include <errno.h> > + > +#include <linux/genetlink.h> > +#include <linux/mptcp.h> > + > +#include "utils.h" > +#include "ip_common.h" > +#include "libgenl.h" > +#include "json_print.h" > + > +static void usage(void) > +{ > + fprintf(stderr, > + "Usage: ip mptcp address add <address> [dev <name>] [id <id>] [signal] [subflow] [backup]\n" > + " ip mptcp address del id <id>\n" > + " ip mptcp address list\n" > + " ip mptcp address get id <id>\n" > + " ip mptcp address flush\n" > + " ip mptcp limits [subflows <nr>] [add_addr_accepted <nr>]\n"); > + > + exit(-1); > +} > + Looking at the documentation for 'ip', there seem to be two command styles: ip [ OPTIONS ] OBJECT { COMMAND } # for most commands ip xfrm XFRM-OBJECT { COMMAND } # for xfrm and the above seems to fit the 'xfrm' style. To avoid confusion with 'ip address', what about using "ip mptcp adv-address" (or "advertise-addr"?) to clarify that these are addresses to be advertised, rather than something that creates new addresses? For consistency with other commands, "ip mptcp address show id <id>" could be a better fit than 'get'. For the limit changes, how about: ip mptcp limit set [subflows <nr>] [add_addr_accepted <nr>] ip mptcp limit get or ip mptcp limit show Do you think the 'ip mptcp' command will be extended in the future for managing per-connection settings? That probably still works with the above syntax, for example by adding [connection <token>] to 'ip mptcp address add'. -- Mat Martineau Intel
Hi Paolo, Mat, On 27/03/2020 00:45, Mat Martineau wrote: > > On Thu, 26 Mar 2020, Paolo Abeni wrote: > >> Implement basic commands to: >> - manipulate MPTCP local addresses list >> - manipulate MPTCP connection limits >> >> Examples: >> 1. Allows multiple subflows per MPTCP connection >> $ ip mptcp limits subflows 2 >> >> 2. Accept ADD_ADDR announcement from the peer (server): >> $ ip mptcp limits add_addr_accepted 2 >> >> 3. Add a ipv4 address to be annunced for backup subflows: >> $ip mptcp address add 10.99.1.2 signal backup >> >> 4. Add an ipv6 address used as source for additional subflows: >> $ip mptcp address add 2001::2 subflow >> >> Signed-off-by: Paolo Abeni <pabeni@redhat.com> >> --- Thank you for the good work! > >> diff --git a/ip/ipmptcp.c b/ip/ipmptcp.c >> new file mode 100644 >> index 00000000..1ff66a7b >> --- /dev/null >> +++ b/ip/ipmptcp.c >> @@ -0,0 +1,446 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> + >> +#include <stdio.h> >> +#include <string.h> >> +#include <rt_names.h> >> +#include <errno.h> >> + >> +#include <linux/genetlink.h> >> +#include <linux/mptcp.h> >> + >> +#include "utils.h" >> +#include "ip_common.h" >> +#include "libgenl.h" >> +#include "json_print.h" >> + >> +static void usage(void) >> +{ >> + fprintf(stderr, >> + "Usage: ip mptcp address add <address> [dev <name>] [id >> <id>] [signal] [subflow] [backup]\n" >> + " ip mptcp address del id <id>\n" >> + " ip mptcp address list\n" >> + " ip mptcp address get id <id>\n" >> + " ip mptcp address flush\n" >> + " ip mptcp limits [subflows <nr>] [add_addr_accepted >> <nr>]\n"); >> + >> + exit(-1); >> +} >> + > > Looking at the documentation for 'ip', there seem to be two command styles: > > ip [ OPTIONS ] OBJECT { COMMAND } # for most commands > > ip xfrm XFRM-OBJECT { COMMAND } # for xfrm > > > and the above seems to fit the 'xfrm' style. > > > To avoid confusion with 'ip address', what about using "ip mptcp > adv-address" (or "advertise-addr"?) to clarify that these are addresses > to be advertised, rather than something that creates new addresses? +1 > For consistency with other commands, "ip mptcp address show id <id>" > could be a better fit than 'get'. +1 > > For the limit changes, how about: > > ip mptcp limit set [subflows <nr>] [add_addr_accepted <nr>] > > ip mptcp limit get > or > ip mptcp limit show +1 > Do you think the 'ip mptcp' command will be extended in the future for > managing per-connection settings? That probably still works with the > above syntax, for example by adding [connection <token>] to 'ip mptcp > address add'. Good idea. It will be possible to retrieve these tokens with "ss". It can be useful for the debugging. For the rest mptcpd will be needed to track the connections. Cheers, Matt
On Thu, 2020-03-26 at 16:45 -0700, Mat Martineau wrote: > On Thu, 26 Mar 2020, Paolo Abeni wrote: > > > Implement basic commands to: > > - manipulate MPTCP local addresses list > > - manipulate MPTCP connection limits > > > > Examples: > > 1. Allows multiple subflows per MPTCP connection > > $ ip mptcp limits subflows 2 > > > > 2. Accept ADD_ADDR announcement from the peer (server): > > $ ip mptcp limits add_addr_accepted 2 > > > > 3. Add a ipv4 address to be annunced for backup subflows: > > $ip mptcp address add 10.99.1.2 signal backup > > > > 4. Add an ipv6 address used as source for additional subflows: > > $ip mptcp address add 2001::2 subflow > > > > Signed-off-by: Paolo Abeni <pabeni@redhat.com> > > --- > > diff --git a/ip/ipmptcp.c b/ip/ipmptcp.c > > new file mode 100644 > > index 00000000..1ff66a7b > > --- /dev/null > > +++ b/ip/ipmptcp.c > > @@ -0,0 +1,446 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > + > > +#include <stdio.h> > > +#include <string.h> > > +#include <rt_names.h> > > +#include <errno.h> > > + > > +#include <linux/genetlink.h> > > +#include <linux/mptcp.h> > > + > > +#include "utils.h" > > +#include "ip_common.h" > > +#include "libgenl.h" > > +#include "json_print.h" > > + > > +static void usage(void) > > +{ > > + fprintf(stderr, > > + "Usage: ip mptcp address add <address> [dev <name>] [id <id>] [signal] [subflow] [backup]\n" > > + " ip mptcp address del id <id>\n" > > + " ip mptcp address list\n" > > + " ip mptcp address get id <id>\n" > > + " ip mptcp address flush\n" > > + " ip mptcp limits [subflows <nr>] [add_addr_accepted <nr>]\n"); > > + > > + exit(-1); > > +} > > + > > Looking at the documentation for 'ip', there seem to be two command > styles: > > ip [ OPTIONS ] OBJECT { COMMAND } # for most commands > > ip xfrm XFRM-OBJECT { COMMAND } # for xfrm > > > and the above seems to fit the 'xfrm' style. > > > To avoid confusion with 'ip address', what about using "ip mptcp > adv-address" (or "advertise-addr"?) to clarify that these are addresses to > be advertised, rather than something that creates new addresses? ok to rename, but the addresses specified here could be used for advertise but also as source address for additional flows, so we would need something more generic (and nothing come to my mind beyond 'address'). > For consistency with other commands, "ip mptcp address show id <id>" could > be a better fit than 'get'. Ok, than is probably better also rename 'list' into 'show', so we will have a single 'getter' command with optional filter, WDYT? > For the limit changes, how about: > > ip mptcp limit set [subflows <nr>] [add_addr_accepted <nr>] > > ip mptcp limit get > or > ip mptcp limit show Ok, I'll use 'show' > > > Do you think the 'ip mptcp' command will be extended in the future for > managing per-connection settings? That probably still works with the above > syntax, for example by adding [connection <token>] to 'ip mptcp address > add'. > > > -- > Mat Martineau > Intel >
On Fri, 27 Mar 2020, Paolo Abeni wrote: > On Thu, 2020-03-26 at 16:45 -0700, Mat Martineau wrote: >> On Thu, 26 Mar 2020, Paolo Abeni wrote: >> >>> Implement basic commands to: >>> - manipulate MPTCP local addresses list >>> - manipulate MPTCP connection limits >>> >>> Examples: >>> 1. Allows multiple subflows per MPTCP connection >>> $ ip mptcp limits subflows 2 >>> >>> 2. Accept ADD_ADDR announcement from the peer (server): >>> $ ip mptcp limits add_addr_accepted 2 >>> >>> 3. Add a ipv4 address to be annunced for backup subflows: >>> $ip mptcp address add 10.99.1.2 signal backup >>> >>> 4. Add an ipv6 address used as source for additional subflows: >>> $ip mptcp address add 2001::2 subflow >>> >>> Signed-off-by: Paolo Abeni <pabeni@redhat.com> >>> --- >>> diff --git a/ip/ipmptcp.c b/ip/ipmptcp.c >>> new file mode 100644 >>> index 00000000..1ff66a7b >>> --- /dev/null >>> +++ b/ip/ipmptcp.c >>> @@ -0,0 +1,446 @@ >>> +// SPDX-License-Identifier: GPL-2.0 >>> + >>> +#include <stdio.h> >>> +#include <string.h> >>> +#include <rt_names.h> >>> +#include <errno.h> >>> + >>> +#include <linux/genetlink.h> >>> +#include <linux/mptcp.h> >>> + >>> +#include "utils.h" >>> +#include "ip_common.h" >>> +#include "libgenl.h" >>> +#include "json_print.h" >>> + >>> +static void usage(void) >>> +{ >>> + fprintf(stderr, >>> + "Usage: ip mptcp address add <address> [dev <name>] [id <id>] [signal] [subflow] [backup]\n" >>> + " ip mptcp address del id <id>\n" >>> + " ip mptcp address list\n" >>> + " ip mptcp address get id <id>\n" >>> + " ip mptcp address flush\n" >>> + " ip mptcp limits [subflows <nr>] [add_addr_accepted <nr>]\n"); >>> + >>> + exit(-1); >>> +} >>> + >> >> Looking at the documentation for 'ip', there seem to be two command >> styles: >> >> ip [ OPTIONS ] OBJECT { COMMAND } # for most commands >> >> ip xfrm XFRM-OBJECT { COMMAND } # for xfrm >> >> >> and the above seems to fit the 'xfrm' style. >> >> >> To avoid confusion with 'ip address', what about using "ip mptcp >> adv-address" (or "advertise-addr"?) to clarify that these are addresses to >> be advertised, rather than something that creates new addresses? > > ok to rename, but the addresses specified here could be used for > advertise but also as source address for additional flows, so we would > need something more generic (and nothing come to my mind beyond > 'address'). Good point. Would something like "default-addr" be generic for that purpose while still getting the point across that we expect these IP addresses to exist already, and are telling MPTCP to use them for any connection? > >> For consistency with other commands, "ip mptcp address show id <id>" could >> be a better fit than 'get'. > > Ok, than is probably better also rename 'list' into 'show', so we will > have a single 'getter' command with optional filter, WDYT? Fine with me. -- Mat Martineau Intel
[me is still somewhat alive] On Sun, 2020-03-29 at 21:02 -0700, Mat Martineau wrote: > On Fri, 27 Mar 2020, Paolo Abeni wrote: > > > On Thu, 2020-03-26 at 16:45 -0700, Mat Martineau wrote: > > > To avoid confusion with 'ip address', what about using "ip mptcp > > > adv-address" (or "advertise-addr"?) to clarify that these are addresses to > > > be advertised, rather than something that creates new addresses? > > > > ok to rename, but the addresses specified here could be used for > > advertise but also as source address for additional flows, so we would > > need something more generic (and nothing come to my mind beyond > > 'address'). > > Good point. Would something like "default-addr" be generic for that > purpose while still getting the point across that we expect these IP > addresses to exist already, and are telling MPTCP to use them for any > connection? I'm wondering if something quite different, alike 'endpoint' would fit better ?!? in (distant) future we could add even port numbers to announced address. Cheers, Paolo
On Thu, 2020-04-09 at 12:56 +0200, Paolo Abeni wrote: > I'm wondering if something quite different, alike 'endpoint' would fit > better ?!? in the advantage of using an acronym is: you don't need to know what it means, just spell it correctly :) what about # ip mptcp advertise-ma where ma can be "multihomed (host) address", like mentioned in RFC 8684 § 2.3 ?
diff --git a/ip/Makefile b/ip/Makefile index 5ab78d7d..8735b8e4 100644 --- a/ip/Makefile +++ b/ip/Makefile @@ -11,7 +11,7 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \ iplink_bridge.o iplink_bridge_slave.o ipfou.o iplink_ipvlan.o \ iplink_geneve.o iplink_vrf.o iproute_lwtunnel.o ipmacsec.o ipila.o \ ipvrf.o iplink_xstats.o ipseg6.o iplink_netdevsim.o iplink_rmnet.o \ - ipnexthop.o + ipnexthop.o ipmptcp.o RTMONOBJ=rtmon.o diff --git a/ip/ip.c b/ip/ip.c index 90392c2a..4249df03 100644 --- a/ip/ip.c +++ b/ip/ip.c @@ -51,7 +51,7 @@ static void usage(void) "where OBJECT := { link | address | addrlabel | route | rule | neigh | ntable |\n" " tunnel | tuntap | maddress | mroute | mrule | monitor | xfrm |\n" " netns | l2tp | fou | macsec | tcp_metrics | token | netconf | ila |\n" - " vrf | sr | nexthop }\n" + " vrf | sr | nexthop | mptcp }\n" " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n" " -h[uman-readable] | -iec | -j[son] | -p[retty] |\n" " -f[amily] { inet | inet6 | mpls | bridge | link } |\n" @@ -103,6 +103,7 @@ static const struct cmd { { "vrf", do_ipvrf}, { "sr", do_seg6 }, { "nexthop", do_ipnh }, + { "mptcp", do_mptcp }, { "help", do_help }, { 0 } }; diff --git a/ip/ip_common.h b/ip/ip_common.h index 879287e3..d604f755 100644 --- a/ip/ip_common.h +++ b/ip/ip_common.h @@ -83,6 +83,7 @@ void vrf_reset(void); int netns_identify_pid(const char *pidstr, char *name, int len); int do_seg6(int argc, char **argv); int do_ipnh(int argc, char **argv); +int do_mptcp(int argc, char **argv); int iplink_get(char *name, __u32 filt_mask); int iplink_ifla_xstats(int argc, char **argv); diff --git a/ip/ipmptcp.c b/ip/ipmptcp.c new file mode 100644 index 00000000..1ff66a7b --- /dev/null +++ b/ip/ipmptcp.c @@ -0,0 +1,446 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <stdio.h> +#include <string.h> +#include <rt_names.h> +#include <errno.h> + +#include <linux/genetlink.h> +#include <linux/mptcp.h> + +#include "utils.h" +#include "ip_common.h" +#include "libgenl.h" +#include "json_print.h" + +static void usage(void) +{ + fprintf(stderr, + "Usage: ip mptcp address add <address> [dev <name>] [id <id>] [signal] [subflow] [backup]\n" + " ip mptcp address del id <id>\n" + " ip mptcp address list\n" + " ip mptcp address get id <id>\n" + " ip mptcp address flush\n" + " ip mptcp limits [subflows <nr>] [add_addr_accepted <nr>]\n"); + + exit(-1); +} + +/* netlink socket */ +static struct rtnl_handle genl_rth = { .fd = -1 }; +static int genl_family = -1; + +#define MPTCP_BUFLEN 4096 +#define MPTCP_REQUEST(_req, _cmd, _flags) \ + GENL_REQUEST(_req, MPTCP_BUFLEN, genl_family, 0, \ + MPTCP_PM_VER, _cmd, _flags) + +/* Mapping from argument to address flag mask */ +static const struct { + const char *name; + unsigned long value; +} mptcp_addr_flag_names[] = { + { "signal", MPTCP_PM_ADDR_FLAG_SIGNAL }, + { "subflow", MPTCP_PM_ADDR_FLAG_SUBFLOW }, + { "backup", MPTCP_PM_ADDR_FLAG_BACKUP }, +}; + +static void print_mptcp_addr_flags(unsigned int flags) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(mptcp_addr_flag_names); i++) { + unsigned long mask = mptcp_addr_flag_names[i].value; + + if (flags & mask) { + print_string(PRINT_FP, NULL, "%s ", + mptcp_addr_flag_names[i].name); + print_bool(PRINT_JSON, + mptcp_addr_flag_names[i].name, NULL, true); + } + + flags &= ~mask; + } + + if (flags) { + /* unknown flags */ + SPRINT_BUF(b1); + + snprintf(b1, sizeof(b1), "%02x", flags); + print_string(PRINT_ANY, "rawflags", "rawflags %s ", b1); + } +} + +static int get_flags(const char *arg, __u32 *flags) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(mptcp_addr_flag_names); i++) { + if (strcmp(arg, mptcp_addr_flag_names[i].name)) + continue; + + *flags |= mptcp_addr_flag_names[i].value; + return 0; + } + return -1; +} + +static int mptcp_parse_opt(int argc, char **argv, struct nlmsghdr *n, + bool adding) +{ + struct rtattr *attr_addr; + bool addr_set = false; + inet_prefix address; + bool id_set = false; + __u32 index = 0; + __u32 flags = 0; + __u8 id = 0; + + ll_init_map(&rth); + while (argc > 0) { + if (get_flags(*argv, &flags) == 0) { + } else if (!matches(*argv, "id")) { + NEXT_ARG(); + + if (get_u8(&id, *argv, 0)) { + invarg("invalid TTL\n", *argv); + return -1; + } + id_set = true; + } else if (!matches(*argv, "dev")) { + const char *ifname; + + NEXT_ARG(); + + ifname = *argv; + + if (check_ifname(ifname)) { + invarg("name", ifname); + return -1; + } + + index = ll_name_to_index(ifname); + + if (!index) { + invarg("name", ifname); + return -1; + } + } else if (get_addr(&address, *argv, AF_UNSPEC) == 0) { + addr_set = true; + } else { + invarg("unknown argument", *argv); + usage(); + } + argc--, argv++; + } + + if (!addr_set && adding) { + fprintf(stderr, "mptcp: must set 'address' on add\n"); + return -1; + } + + if (!id_set && !adding) { + fprintf(stderr, "mptcp: must set 'id'\n"); + return -1; + } + + attr_addr = addattr_nest(n, MPTCP_BUFLEN, + MPTCP_PM_ATTR_ADDR | NLA_F_NESTED); + if (id_set) + addattr8(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_ID, id); + if (flags) + addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_FLAGS, flags); + if (index) + addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_IF_IDX, index); + if (addr_set) { + int type; + + addattr16(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_FAMILY, + address.family); + type = address.family == AF_INET ? MPTCP_PM_ADDR_ATTR_ADDR4 : + MPTCP_PM_ADDR_ATTR_ADDR6; + addattr_l(n, MPTCP_BUFLEN, type, &address.data, + address.bytelen); + } + + addattr_nest_end(n, attr_addr); + return 0; +} + +static int mptcp_addr_modify(int argc, char **argv, int cmd) +{ + MPTCP_REQUEST(req, cmd, NLM_F_REQUEST); + int ret; + + ret = mptcp_parse_opt(argc, argv, &req.n, cmd == MPTCP_PM_CMD_ADD_ADDR); + if (ret) + return ret; + + if (rtnl_talk(&genl_rth, &req.n, NULL) < 0) + return -2; + + return 0; +} + +static int print_mptcp_addrinfo(struct rtattr *addrinfo) +{ + struct rtattr *tb[MPTCP_PM_ADDR_ATTR_MAX + 1]; + __u8 family = AF_UNSPEC, addr_attr_type; + const char *ifname; + unsigned int flags; + int index; + __u16 id; + + parse_rtattr_nested(tb, MPTCP_PM_ADDR_ATTR_MAX, addrinfo); + + open_json_object(NULL); + if (tb[MPTCP_PM_ADDR_ATTR_FAMILY]) + family = rta_getattr_u8(tb[MPTCP_PM_ADDR_ATTR_FAMILY]); + + addr_attr_type = family == AF_INET ? MPTCP_PM_ADDR_ATTR_ADDR4 : + MPTCP_PM_ADDR_ATTR_ADDR6; + if (tb[addr_attr_type]) { + print_string(PRINT_ANY, "address", "%s ", + format_host_rta(family, tb[addr_attr_type])); + } + if (tb[MPTCP_PM_ADDR_ATTR_ID]) { + id = rta_getattr_u8(tb[MPTCP_PM_ADDR_ATTR_ID]); + print_uint(PRINT_ANY, "id", "id %u ", id); + } + if (tb[MPTCP_PM_ADDR_ATTR_FLAGS]) { + flags = rta_getattr_u32(tb[MPTCP_PM_ADDR_ATTR_FLAGS]); + print_mptcp_addr_flags(flags); + } + if (tb[MPTCP_PM_ADDR_ATTR_IF_IDX]) { + index = rta_getattr_s32(tb[MPTCP_PM_ADDR_ATTR_IF_IDX]); + ifname = index ? ll_index_to_name(index) : NULL; + + if (ifname) + print_string(PRINT_ANY, "dev", "dev %s ", ifname); + } + + close_json_object(); + print_string(PRINT_FP, NULL, "\n", NULL); + fflush(stdout); + + return 0; +} + +static int print_mptcp_addr(struct nlmsghdr *n, void *arg) +{ + struct rtattr *tb[MPTCP_PM_ATTR_MAX + 1]; + struct genlmsghdr *ghdr; + struct rtattr *addrinfo; + int len = n->nlmsg_len; + + if (n->nlmsg_type != genl_family) + return 0; + + len -= NLMSG_LENGTH(GENL_HDRLEN); + if (len < 0) + return -1; + + ghdr = NLMSG_DATA(n); + parse_rtattr_flags(tb, MPTCP_PM_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, + len, NLA_F_NESTED); + addrinfo = tb[MPTCP_PM_ATTR_ADDR]; + if (!addrinfo) + return -1; + + ll_init_map(&rth); + return print_mptcp_addrinfo(addrinfo); +} + +static int mptcp_addr_list(int argc, char **argv) +{ + MPTCP_REQUEST(req, MPTCP_PM_CMD_GET_ADDR, NLM_F_REQUEST | NLM_F_DUMP); + + if (argc > 0) { + fprintf(stderr, + "\"ip mptcp addr show\" does not take any arguments.\n"); + return -1; + } + + if (rtnl_send(&genl_rth, &req.n, req.n.nlmsg_len) < 0) { + perror("Cannot send show request"); + exit(1); + } + + new_json_obj(json); + + if (rtnl_dump_filter(&genl_rth, print_mptcp_addr, stdout) < 0) { + fprintf(stderr, "Dump terminated\n"); + delete_json_obj(); + fflush(stdout); + return -2; + } + + close_json_object(); + fflush(stdout); + return 0; +} + +static int mptcp_addr_get(int argc, char **argv) +{ + MPTCP_REQUEST(req, MPTCP_PM_CMD_GET_ADDR, NLM_F_REQUEST); + struct nlmsghdr *answer; + int ret; + + ret = mptcp_parse_opt(argc, argv, &req.n, false); + if (ret) + return ret; + + if (rtnl_talk(&genl_rth, &req.n, &answer) < 0) + return -2; + + return print_mptcp_addr(answer, stdout); +} + +static int mptcp_addr_flush(int argc, char **argv) +{ + MPTCP_REQUEST(req, MPTCP_PM_CMD_FLUSH_ADDRS, NLM_F_REQUEST); + + if (rtnl_talk(&genl_rth, &req.n, NULL) < 0) + return -2; + + return 0; +} + +static int mptcp_parse_limit(int argc, char **argv, struct nlmsghdr *n) +{ + bool set_rcv_add_addrs = false; + bool set_subflows = false; + __u32 rcv_add_addrs = 0; + __u32 subflows = 0; + + while (argc > 0) { + if (!matches(*argv, "subflows")) { + NEXT_ARG(); + + if (get_u32(&subflows, *argv, 0)) { + invarg("invalid subflows\n", *argv); + return -1; + } + set_subflows = true; + } else if (!matches(*argv, "add_addr_accepted")) { + NEXT_ARG(); + + if (get_u32(&rcv_add_addrs, *argv, 0)) { + invarg("invalid add_addr_accepted\n", *argv); + return -1; + } + set_rcv_add_addrs = true; + } else { + invarg("unknown argument", *argv); + usage(); + } + argc--, argv++; + } + + if (set_rcv_add_addrs) + addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ATTR_RCV_ADD_ADDRS, + rcv_add_addrs); + if (set_subflows) + addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ATTR_SUBFLOWS, subflows); + return set_rcv_add_addrs || set_subflows; +} + +static int print_mptcp_limit(struct nlmsghdr *n, void *arg) +{ + struct rtattr *tb[MPTCP_PM_ATTR_MAX + 1]; + struct genlmsghdr *ghdr; + int len = n->nlmsg_len; + __u32 val; + + if (n->nlmsg_type != genl_family) + return 0; + + len -= NLMSG_LENGTH(GENL_HDRLEN); + if (len < 0) + return -1; + + ghdr = NLMSG_DATA(n); + parse_rtattr(tb, MPTCP_PM_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len); + + open_json_object(NULL); + if (tb[MPTCP_PM_ATTR_RCV_ADD_ADDRS]) { + val = rta_getattr_u32(tb[MPTCP_PM_ATTR_RCV_ADD_ADDRS]); + + print_uint(PRINT_ANY, "add_addr_accepted", + "add_addr_accepted %d ", val); + } + + if (tb[MPTCP_PM_ATTR_SUBFLOWS]) { + val = rta_getattr_u32(tb[MPTCP_PM_ATTR_SUBFLOWS]); + + print_uint(PRINT_ANY, "subflows", "subflows %d ", val); + } + print_string(PRINT_FP, NULL, "%s", "\n"); + fflush(stdout); + close_json_object(); + return 0; +} + +static int mptcp_limit_get_set(int argc, char **argv) +{ + MPTCP_REQUEST(req, MPTCP_PM_CMD_SET_LIMITS, NLM_F_REQUEST); + struct nlmsghdr *answer; + bool do_get; + int ret; + + ret = mptcp_parse_limit(argc, argv, &req.n); + if (ret < 0) + return -1; + + do_get = ret == 0; + if (do_get) + req.g.cmd = MPTCP_PM_CMD_GET_LIMITS; + if (rtnl_talk(&genl_rth, &req.n, do_get ? &answer : NULL) < 0) + return -2; + + if (do_get) + return print_mptcp_limit(answer, stdout); + return 0; +} + +int do_mptcp(int argc, char **argv) +{ + if (argc == 0) + usage(); + + if (!matches(*argv, "help")) + usage(); + + if (genl_init_handle(&genl_rth, MPTCP_PM_NAME, &genl_family)) + exit(1); + + if (!matches(*argv, "address")) { + argc--, argv++; + if (argc == 0) + return mptcp_addr_list(0, NULL); + + if (!matches(*argv, "add")) + return mptcp_addr_modify(argc-1, argv+1, + MPTCP_PM_CMD_ADD_ADDR); + if (!matches(*argv, "delete")) + return mptcp_addr_modify(argc-1, argv+1, + MPTCP_PM_CMD_DEL_ADDR); + if (!matches(*argv, "list")) + return mptcp_addr_list(argc-1, argv+1); + if (!matches(*argv, "get")) + return mptcp_addr_get(argc-1, argv+1); + if (!matches(*argv, "flush")) + return mptcp_addr_flush(argc-1, argv+1); + + goto unknown; + } + + if (!matches(*argv, "limits")) + return mptcp_limit_get_set(argc-1, argv+1); + +unknown: + fprintf(stderr, + "Command \"%s\" is unknown, try \"ip mptcp help\".\n", + *argv); + exit(-1); +}
Implement basic commands to: - manipulate MPTCP local addresses list - manipulate MPTCP connection limits Examples: 1. Allows multiple subflows per MPTCP connection $ ip mptcp limits subflows 2 2. Accept ADD_ADDR announcement from the peer (server): $ ip mptcp limits add_addr_accepted 2 3. Add a ipv4 address to be annunced for backup subflows: $ip mptcp address add 10.99.1.2 signal backup 4. Add an ipv6 address used as source for additional subflows: $ip mptcp address add 2001::2 subflow Signed-off-by: Paolo Abeni <pabeni@redhat.com> --- ip/Makefile | 2 +- ip/ip.c | 3 +- ip/ip_common.h | 1 + ip/ipmptcp.c | 446 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 450 insertions(+), 2 deletions(-) create mode 100644 ip/ipmptcp.c