diff options
Diffstat (limited to 'tools/testing/selftests/net/mptcp/pm_nl_ctl.c')
-rw-r--r-- | tools/testing/selftests/net/mptcp/pm_nl_ctl.c | 989 |
1 files changed, 963 insertions, 26 deletions
diff --git a/tools/testing/selftests/net/mptcp/pm_nl_ctl.c b/tools/testing/selftests/net/mptcp/pm_nl_ctl.c index b24a2f17d415..7426a2cbd4a0 100644 --- a/tools/testing/selftests/net/mptcp/pm_nl_ctl.c +++ b/tools/testing/selftests/net/mptcp/pm_nl_ctl.c @@ -6,6 +6,7 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <limits.h> #include <sys/socket.h> #include <sys/types.h> @@ -21,16 +22,29 @@ #ifndef MPTCP_PM_NAME #define MPTCP_PM_NAME "mptcp_pm" #endif +#ifndef MPTCP_PM_EVENTS +#define MPTCP_PM_EVENTS "mptcp_pm_events" +#endif +#ifndef IPPROTO_MPTCP +#define IPPROTO_MPTCP 262 +#endif static void syntax(char *argv[]) { - fprintf(stderr, "%s add|get|del|flush|dump|accept [<args>]\n", argv[0]); - fprintf(stderr, "\tadd [flags signal|subflow|backup] [id <nr>] [dev <name>] <ip>\n"); - fprintf(stderr, "\tdel <id>\n"); + fprintf(stderr, "%s add|ann|rem|csf|dsf|get|set|del|flush|dump|events|listen|accept [<args>]\n", argv[0]); + fprintf(stderr, "\tadd [flags signal|subflow|backup|fullmesh] [id <nr>] [dev <name>] <ip>\n"); + fprintf(stderr, "\tann <local-ip> id <local-id> token <token> [port <local-port>] [dev <name>]\n"); + fprintf(stderr, "\trem id <local-id> token <token>\n"); + fprintf(stderr, "\tcsf lip <local-ip> lid <local-id> rip <remote-ip> rport <remote-port> token <token>\n"); + fprintf(stderr, "\tdsf lip <local-ip> lport <local-port> rip <remote-ip> rport <remote-port> token <token>\n"); + fprintf(stderr, "\tdel <id> [<ip>]\n"); fprintf(stderr, "\tget <id>\n"); + fprintf(stderr, "\tset [<ip>] [id <nr>] flags [no]backup|[no]fullmesh [port <nr>] [token <token>] [rip <ip>] [rport <port>]\n"); fprintf(stderr, "\tflush\n"); fprintf(stderr, "\tdump\n"); fprintf(stderr, "\tlimits [<rcv addr max> <subflow max>]\n"); + fprintf(stderr, "\tevents\n"); + fprintf(stderr, "\tlisten <local-ip> <local-port>\n"); exit(0); } @@ -52,20 +66,25 @@ static int init_genl_req(char *data, int family, int cmd, int version) return off; } -static void nl_error(struct nlmsghdr *nh) +static int nl_error(struct nlmsghdr *nh) { struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(nh); int len = nh->nlmsg_len - sizeof(*nh); uint32_t off; - if (len < sizeof(struct nlmsgerr)) + if (len < sizeof(struct nlmsgerr)) { error(1, 0, "netlink error message truncated %d min %ld", len, sizeof(struct nlmsgerr)); + return -1; + } - if (!err->error) { + if (err->error) { /* check messages from kernel */ struct rtattr *attrs = (struct rtattr *)NLMSG_DATA(nh); + fprintf(stderr, "netlink error %d (%s)\n", + err->error, strerror(-err->error)); + while (RTA_OK(attrs, len)) { if (attrs->rta_type == NLMSGERR_ATTR_MSG) fprintf(stderr, "netlink ext ack msg: %s\n", @@ -77,12 +96,115 @@ static void nl_error(struct nlmsghdr *nh) } attrs = RTA_NEXT(attrs, len); } - } else { - fprintf(stderr, "netlink error %d", err->error); + return -1; } + + return 0; } -/* do a netlink command and, if max > 0, fetch the reply */ +static int capture_events(int fd, int event_group) +{ + u_int8_t buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + + NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 1024]; + struct genlmsghdr *ghdr; + struct rtattr *attrs; + struct nlmsghdr *nh; + int ret = 0; + int res_len; + int msg_len; + fd_set rfds; + + if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, + &event_group, sizeof(event_group)) < 0) + error(1, errno, "could not join the " MPTCP_PM_EVENTS " mcast group"); + + do { + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + res_len = NLMSG_ALIGN(sizeof(struct nlmsghdr)) + + NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 1024; + + ret = select(FD_SETSIZE, &rfds, NULL, NULL, NULL); + + if (ret < 0) + error(1, ret, "error in select() on NL socket"); + + res_len = recv(fd, buffer, res_len, 0); + if (res_len < 0) + error(1, res_len, "error on recv() from NL socket"); + + nh = (struct nlmsghdr *)buffer; + + for (; NLMSG_OK(nh, res_len); nh = NLMSG_NEXT(nh, res_len)) { + if (nh->nlmsg_type == NLMSG_ERROR) + error(1, NLMSG_ERROR, "received invalid NL message"); + + ghdr = (struct genlmsghdr *)NLMSG_DATA(nh); + + if (ghdr->cmd == 0) + continue; + + fprintf(stderr, "type:%d", ghdr->cmd); + + msg_len = nh->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN); + + attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN); + while (RTA_OK(attrs, msg_len)) { + if (attrs->rta_type == MPTCP_ATTR_TOKEN) + fprintf(stderr, ",token:%u", *(__u32 *)RTA_DATA(attrs)); + else if (attrs->rta_type == MPTCP_ATTR_FAMILY) + fprintf(stderr, ",family:%u", *(__u16 *)RTA_DATA(attrs)); + else if (attrs->rta_type == MPTCP_ATTR_LOC_ID) + fprintf(stderr, ",loc_id:%u", *(__u8 *)RTA_DATA(attrs)); + else if (attrs->rta_type == MPTCP_ATTR_REM_ID) + fprintf(stderr, ",rem_id:%u", *(__u8 *)RTA_DATA(attrs)); + else if (attrs->rta_type == MPTCP_ATTR_SADDR4) { + u_int32_t saddr4 = ntohl(*(__u32 *)RTA_DATA(attrs)); + + fprintf(stderr, ",saddr4:%u.%u.%u.%u", saddr4 >> 24, + (saddr4 >> 16) & 0xFF, (saddr4 >> 8) & 0xFF, + (saddr4 & 0xFF)); + } else if (attrs->rta_type == MPTCP_ATTR_SADDR6) { + char buf[INET6_ADDRSTRLEN]; + + if (inet_ntop(AF_INET6, RTA_DATA(attrs), buf, + sizeof(buf)) != NULL) + fprintf(stderr, ",saddr6:%s", buf); + } else if (attrs->rta_type == MPTCP_ATTR_DADDR4) { + u_int32_t daddr4 = ntohl(*(__u32 *)RTA_DATA(attrs)); + + fprintf(stderr, ",daddr4:%u.%u.%u.%u", daddr4 >> 24, + (daddr4 >> 16) & 0xFF, (daddr4 >> 8) & 0xFF, + (daddr4 & 0xFF)); + } else if (attrs->rta_type == MPTCP_ATTR_DADDR6) { + char buf[INET6_ADDRSTRLEN]; + + if (inet_ntop(AF_INET6, RTA_DATA(attrs), buf, + sizeof(buf)) != NULL) + fprintf(stderr, ",daddr6:%s", buf); + } else if (attrs->rta_type == MPTCP_ATTR_SPORT) + fprintf(stderr, ",sport:%u", + ntohs(*(__u16 *)RTA_DATA(attrs))); + else if (attrs->rta_type == MPTCP_ATTR_DPORT) + fprintf(stderr, ",dport:%u", + ntohs(*(__u16 *)RTA_DATA(attrs))); + else if (attrs->rta_type == MPTCP_ATTR_BACKUP) + fprintf(stderr, ",backup:%u", *(__u8 *)RTA_DATA(attrs)); + else if (attrs->rta_type == MPTCP_ATTR_ERROR) + fprintf(stderr, ",error:%u", *(__u8 *)RTA_DATA(attrs)); + else if (attrs->rta_type == MPTCP_ATTR_SERVER_SIDE) + fprintf(stderr, ",server_side:%u", *(__u8 *)RTA_DATA(attrs)); + + attrs = RTA_NEXT(attrs, msg_len); + } + } + fprintf(stderr, "\n"); + } while (1); + + return 0; +} + +/* do a netlink command and, if max > 0, fetch the reply ; nh's size >1024B */ static int do_nl_req(int fd, struct nlmsghdr *nh, int len, int max) { struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; @@ -91,12 +213,16 @@ static int do_nl_req(int fd, struct nlmsghdr *nh, int len, int max) int rem, ret; int err = 0; + /* If no expected answer, ask for an ACK to look for errors if any */ + if (max == 0) { + nh->nlmsg_flags |= NLM_F_ACK; + max = 1024; + } + nh->nlmsg_len = len; ret = sendto(fd, data, len, 0, (void *)&nladdr, sizeof(nladdr)); if (ret != len) error(1, errno, "send netlink: %uB != %uB\n", ret, len); - if (max == 0) - return 0; addr_len = sizeof(nladdr); rem = ret = recvfrom(fd, data, max, 0, (void *)&nladdr, &addr_len); @@ -105,21 +231,29 @@ static int do_nl_req(int fd, struct nlmsghdr *nh, int len, int max) /* Beware: the NLMSG_NEXT macro updates the 'rem' argument */ for (; NLMSG_OK(nh, rem); nh = NLMSG_NEXT(nh, rem)) { - if (nh->nlmsg_type == NLMSG_ERROR) { - nl_error(nh); + if (nh->nlmsg_type == NLMSG_DONE) + break; + + if (nh->nlmsg_type == NLMSG_ERROR && nl_error(nh)) err = 1; - } } if (err) error(1, 0, "bailing out due to netlink error[s]"); return ret; } -static int genl_parse_getfamily(struct nlmsghdr *nlh) +static int genl_parse_getfamily(struct nlmsghdr *nlh, int *pm_family, + int *events_mcast_grp) { struct genlmsghdr *ghdr = NLMSG_DATA(nlh); int len = nlh->nlmsg_len; struct rtattr *attrs; + struct rtattr *grps; + struct rtattr *grp; + int got_events_grp; + int got_family; + int grps_len; + int grp_len; if (nlh->nlmsg_type != GENL_ID_CTRL) error(1, errno, "Not a controller message, len=%d type=0x%x\n", @@ -134,9 +268,42 @@ static int genl_parse_getfamily(struct nlmsghdr *nlh) error(1, errno, "Unknown controller command %d\n", ghdr->cmd); attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN); + got_family = 0; + got_events_grp = 0; + while (RTA_OK(attrs, len)) { - if (attrs->rta_type == CTRL_ATTR_FAMILY_ID) - return *(__u16 *)RTA_DATA(attrs); + if (attrs->rta_type == CTRL_ATTR_FAMILY_ID) { + *pm_family = *(__u16 *)RTA_DATA(attrs); + got_family = 1; + } else if (attrs->rta_type == CTRL_ATTR_MCAST_GROUPS) { + grps = RTA_DATA(attrs); + grps_len = RTA_PAYLOAD(attrs); + + while (RTA_OK(grps, grps_len)) { + grp = RTA_DATA(grps); + grp_len = RTA_PAYLOAD(grps); + got_events_grp = 0; + + while (RTA_OK(grp, grp_len)) { + if (grp->rta_type == CTRL_ATTR_MCAST_GRP_ID) + *events_mcast_grp = *(__u32 *)RTA_DATA(grp); + else if (grp->rta_type == CTRL_ATTR_MCAST_GRP_NAME && + !strcmp(RTA_DATA(grp), MPTCP_PM_EVENTS)) + got_events_grp = 1; + + grp = RTA_NEXT(grp, grp_len); + } + + if (got_events_grp) + break; + + grps = RTA_NEXT(grps, grps_len); + } + } + + if (got_family && got_events_grp) + return 0; + attrs = RTA_NEXT(attrs, len); } @@ -144,7 +311,7 @@ static int genl_parse_getfamily(struct nlmsghdr *nlh) return -1; } -static int resolve_mptcp_pm_netlink(int fd) +static int resolve_mptcp_pm_netlink(int fd, int *pm_family, int *events_mcast_grp) { char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct genlmsghdr)) + @@ -166,7 +333,429 @@ static int resolve_mptcp_pm_netlink(int fd) off += NLMSG_ALIGN(rta->rta_len); do_nl_req(fd, nh, off, sizeof(data)); - return genl_parse_getfamily((void *)data); + return genl_parse_getfamily((void *)data, pm_family, events_mcast_grp); +} + +int dsf(int fd, int pm_family, int argc, char *argv[]) +{ + char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + + NLMSG_ALIGN(sizeof(struct genlmsghdr)) + + 1024]; + struct rtattr *rta, *addr; + u_int16_t family, port; + struct nlmsghdr *nh; + u_int32_t token; + int addr_start; + int off = 0; + int arg; + + const char *params[5]; + + memset(params, 0, 5 * sizeof(const char *)); + + memset(data, 0, sizeof(data)); + nh = (void *)data; + off = init_genl_req(data, pm_family, MPTCP_PM_CMD_SUBFLOW_DESTROY, + MPTCP_PM_VER); + + if (argc < 12) + syntax(argv); + + /* Params recorded in this order: + * <local-ip>, <local-port>, <remote-ip>, <remote-port>, <token> + */ + for (arg = 2; arg < argc; arg++) { + if (!strcmp(argv[arg], "lip")) { + if (++arg >= argc) + error(1, 0, " missing local IP"); + + params[0] = argv[arg]; + } else if (!strcmp(argv[arg], "lport")) { + if (++arg >= argc) + error(1, 0, " missing local port"); + + params[1] = argv[arg]; + } else if (!strcmp(argv[arg], "rip")) { + if (++arg >= argc) + error(1, 0, " missing remote IP"); + + params[2] = argv[arg]; + } else if (!strcmp(argv[arg], "rport")) { + if (++arg >= argc) + error(1, 0, " missing remote port"); + + params[3] = argv[arg]; + } else if (!strcmp(argv[arg], "token")) { + if (++arg >= argc) + error(1, 0, " missing token"); + + params[4] = argv[arg]; + } else + error(1, 0, "unknown keyword %s", argv[arg]); + } + + for (arg = 0; arg < 4; arg = arg + 2) { + /* addr header */ + addr_start = off; + addr = (void *)(data + off); + addr->rta_type = NLA_F_NESTED | + ((arg == 0) ? MPTCP_PM_ATTR_ADDR : MPTCP_PM_ATTR_ADDR_REMOTE); + addr->rta_len = RTA_LENGTH(0); + off += NLMSG_ALIGN(addr->rta_len); + + /* addr data */ + rta = (void *)(data + off); + if (inet_pton(AF_INET, params[arg], RTA_DATA(rta))) { + family = AF_INET; + rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4; + rta->rta_len = RTA_LENGTH(4); + } else if (inet_pton(AF_INET6, params[arg], RTA_DATA(rta))) { + family = AF_INET6; + rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6; + rta->rta_len = RTA_LENGTH(16); + } else + error(1, errno, "can't parse ip %s", params[arg]); + off += NLMSG_ALIGN(rta->rta_len); + + /* family */ + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY; + rta->rta_len = RTA_LENGTH(2); + memcpy(RTA_DATA(rta), &family, 2); + off += NLMSG_ALIGN(rta->rta_len); + + /* port */ + port = atoi(params[arg + 1]); + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT; + rta->rta_len = RTA_LENGTH(2); + memcpy(RTA_DATA(rta), &port, 2); + off += NLMSG_ALIGN(rta->rta_len); + + addr->rta_len = off - addr_start; + } + + /* token */ + token = strtoul(params[4], NULL, 10); + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ATTR_TOKEN; + rta->rta_len = RTA_LENGTH(4); + memcpy(RTA_DATA(rta), &token, 4); + off += NLMSG_ALIGN(rta->rta_len); + + do_nl_req(fd, nh, off, 0); + + return 0; +} + +int csf(int fd, int pm_family, int argc, char *argv[]) +{ + char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + + NLMSG_ALIGN(sizeof(struct genlmsghdr)) + + 1024]; + u_int32_t flags = MPTCP_PM_ADDR_FLAG_SUBFLOW; + const char *params[5]; + struct nlmsghdr *nh; + struct rtattr *addr; + struct rtattr *rta; + u_int16_t family; + u_int32_t token; + u_int16_t port; + int addr_start; + u_int8_t id; + int off = 0; + int arg; + + memset(params, 0, 5 * sizeof(const char *)); + + memset(data, 0, sizeof(data)); + nh = (void *)data; + off = init_genl_req(data, pm_family, MPTCP_PM_CMD_SUBFLOW_CREATE, + MPTCP_PM_VER); + + if (argc < 12) + syntax(argv); + + /* Params recorded in this order: + * <local-ip>, <local-id>, <remote-ip>, <remote-port>, <token> + */ + for (arg = 2; arg < argc; arg++) { + if (!strcmp(argv[arg], "lip")) { + if (++arg >= argc) + error(1, 0, " missing local IP"); + + params[0] = argv[arg]; + } else if (!strcmp(argv[arg], "lid")) { + if (++arg >= argc) + error(1, 0, " missing local id"); + + params[1] = argv[arg]; + } else if (!strcmp(argv[arg], "rip")) { + if (++arg >= argc) + error(1, 0, " missing remote ip"); + + params[2] = argv[arg]; + } else if (!strcmp(argv[arg], "rport")) { + if (++arg >= argc) + error(1, 0, " missing remote port"); + + params[3] = argv[arg]; + } else if (!strcmp(argv[arg], "token")) { + if (++arg >= argc) + error(1, 0, " missing token"); + + params[4] = argv[arg]; + } else + error(1, 0, "unknown param %s", argv[arg]); + } + + for (arg = 0; arg < 4; arg = arg + 2) { + /* addr header */ + addr_start = off; + addr = (void *)(data + off); + addr->rta_type = NLA_F_NESTED | + ((arg == 0) ? MPTCP_PM_ATTR_ADDR : MPTCP_PM_ATTR_ADDR_REMOTE); + addr->rta_len = RTA_LENGTH(0); + off += NLMSG_ALIGN(addr->rta_len); + + /* addr data */ + rta = (void *)(data + off); + if (inet_pton(AF_INET, params[arg], RTA_DATA(rta))) { + family = AF_INET; + rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4; + rta->rta_len = RTA_LENGTH(4); + } else if (inet_pton(AF_INET6, params[arg], RTA_DATA(rta))) { + family = AF_INET6; + rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6; + rta->rta_len = RTA_LENGTH(16); + } else + error(1, errno, "can't parse ip %s", params[arg]); + off += NLMSG_ALIGN(rta->rta_len); + + /* family */ + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY; + rta->rta_len = RTA_LENGTH(2); + memcpy(RTA_DATA(rta), &family, 2); + off += NLMSG_ALIGN(rta->rta_len); + + if (arg == 2) { + /* port */ + port = atoi(params[arg + 1]); + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT; + rta->rta_len = RTA_LENGTH(2); + memcpy(RTA_DATA(rta), &port, 2); + off += NLMSG_ALIGN(rta->rta_len); + } + + if (arg == 0) { + /* id */ + id = atoi(params[arg + 1]); + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ADDR_ATTR_ID; + rta->rta_len = RTA_LENGTH(1); + memcpy(RTA_DATA(rta), &id, 1); + off += NLMSG_ALIGN(rta->rta_len); + } + + /* addr flags */ + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS; + rta->rta_len = RTA_LENGTH(4); + memcpy(RTA_DATA(rta), &flags, 4); + off += NLMSG_ALIGN(rta->rta_len); + + addr->rta_len = off - addr_start; + } + + /* token */ + token = strtoul(params[4], NULL, 10); + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ATTR_TOKEN; + rta->rta_len = RTA_LENGTH(4); + memcpy(RTA_DATA(rta), &token, 4); + off += NLMSG_ALIGN(rta->rta_len); + + do_nl_req(fd, nh, off, 0); + + return 0; +} + +int remove_addr(int fd, int pm_family, int argc, char *argv[]) +{ + char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + + NLMSG_ALIGN(sizeof(struct genlmsghdr)) + + 1024]; + struct nlmsghdr *nh; + struct rtattr *rta; + u_int32_t token; + u_int8_t id; + int off = 0; + int arg; + + memset(data, 0, sizeof(data)); + nh = (void *)data; + off = init_genl_req(data, pm_family, MPTCP_PM_CMD_REMOVE, + MPTCP_PM_VER); + + if (argc < 6) + syntax(argv); + + for (arg = 2; arg < argc; arg++) { + if (!strcmp(argv[arg], "id")) { + if (++arg >= argc) + error(1, 0, " missing id value"); + + id = atoi(argv[arg]); + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ATTR_LOC_ID; + rta->rta_len = RTA_LENGTH(1); + memcpy(RTA_DATA(rta), &id, 1); + off += NLMSG_ALIGN(rta->rta_len); + } else if (!strcmp(argv[arg], "token")) { + if (++arg >= argc) + error(1, 0, " missing token value"); + + token = strtoul(argv[arg], NULL, 10); + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ATTR_TOKEN; + rta->rta_len = RTA_LENGTH(4); + memcpy(RTA_DATA(rta), &token, 4); + off += NLMSG_ALIGN(rta->rta_len); + } else + error(1, 0, "unknown keyword %s", argv[arg]); + } + + do_nl_req(fd, nh, off, 0); + return 0; +} + +int announce_addr(int fd, int pm_family, int argc, char *argv[]) +{ + char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + + NLMSG_ALIGN(sizeof(struct genlmsghdr)) + + 1024]; + u_int32_t flags = MPTCP_PM_ADDR_FLAG_SIGNAL; + u_int32_t token = UINT_MAX; + struct rtattr *rta, *addr; + u_int32_t id = UINT_MAX; + struct nlmsghdr *nh; + u_int16_t family; + int addr_start; + int off = 0; + int arg; + + memset(data, 0, sizeof(data)); + nh = (void *)data; + off = init_genl_req(data, pm_family, MPTCP_PM_CMD_ANNOUNCE, + MPTCP_PM_VER); + + if (argc < 7) + syntax(argv); + + /* local-ip header */ + addr_start = off; + addr = (void *)(data + off); + addr->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR; + addr->rta_len = RTA_LENGTH(0); + off += NLMSG_ALIGN(addr->rta_len); + + /* local-ip data */ + /* record addr type */ + rta = (void *)(data + off); + if (inet_pton(AF_INET, argv[2], RTA_DATA(rta))) { + family = AF_INET; + rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4; + rta->rta_len = RTA_LENGTH(4); + } else if (inet_pton(AF_INET6, argv[2], RTA_DATA(rta))) { + family = AF_INET6; + rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6; + rta->rta_len = RTA_LENGTH(16); + } else + error(1, errno, "can't parse ip %s", argv[2]); + off += NLMSG_ALIGN(rta->rta_len); + + /* addr family */ + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY; + rta->rta_len = RTA_LENGTH(2); + memcpy(RTA_DATA(rta), &family, 2); + off += NLMSG_ALIGN(rta->rta_len); + + for (arg = 3; arg < argc; arg++) { + if (!strcmp(argv[arg], "id")) { + /* local-id */ + if (++arg >= argc) + error(1, 0, " missing id value"); + + id = atoi(argv[arg]); + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ADDR_ATTR_ID; + rta->rta_len = RTA_LENGTH(1); + memcpy(RTA_DATA(rta), &id, 1); + off += NLMSG_ALIGN(rta->rta_len); + } else if (!strcmp(argv[arg], "dev")) { + /* for the if_index */ + int32_t ifindex; + + if (++arg >= argc) + error(1, 0, " missing dev name"); + + ifindex = if_nametoindex(argv[arg]); + if (!ifindex) + error(1, errno, "unknown device %s", argv[arg]); + + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ADDR_ATTR_IF_IDX; + rta->rta_len = RTA_LENGTH(4); + memcpy(RTA_DATA(rta), &ifindex, 4); + off += NLMSG_ALIGN(rta->rta_len); + } else if (!strcmp(argv[arg], "port")) { + /* local-port (optional) */ + u_int16_t port; + + if (++arg >= argc) + error(1, 0, " missing port value"); + + port = atoi(argv[arg]); + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT; + rta->rta_len = RTA_LENGTH(2); + memcpy(RTA_DATA(rta), &port, 2); + off += NLMSG_ALIGN(rta->rta_len); + } else if (!strcmp(argv[arg], "token")) { + /* MPTCP connection token */ + if (++arg >= argc) + error(1, 0, " missing token value"); + + token = strtoul(argv[arg], NULL, 10); + } else + error(1, 0, "unknown keyword %s", argv[arg]); + } + + /* addr flags */ + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS; + rta->rta_len = RTA_LENGTH(4); + memcpy(RTA_DATA(rta), &flags, 4); + off += NLMSG_ALIGN(rta->rta_len); + + addr->rta_len = off - addr_start; + + if (id == UINT_MAX || token == UINT_MAX) + error(1, 0, " missing mandatory inputs"); + + /* token */ + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ATTR_TOKEN; + rta->rta_len = RTA_LENGTH(4); + memcpy(RTA_DATA(rta), &token, 4); + off += NLMSG_ALIGN(rta->rta_len); + + do_nl_req(fd, nh, off, 0); + + return 0; } int add_addr(int fd, int pm_family, int argc, char *argv[]) @@ -176,8 +765,8 @@ int add_addr(int fd, int pm_family, int argc, char *argv[]) 1024]; struct rtattr *rta, *nest; struct nlmsghdr *nh; + u_int32_t flags = 0; u_int16_t family; - u_int32_t flags; int nest_start; u_int8_t id; int off = 0; @@ -223,7 +812,6 @@ int add_addr(int fd, int pm_family, int argc, char *argv[]) char *tok, *str; /* flags */ - flags = 0; if (++arg >= argc) error(1, 0, " missing flags value"); @@ -236,11 +824,18 @@ int add_addr(int fd, int pm_family, int argc, char *argv[]) flags |= MPTCP_PM_ADDR_FLAG_SIGNAL; else if (!strcmp(tok, "backup")) flags |= MPTCP_PM_ADDR_FLAG_BACKUP; + else if (!strcmp(tok, "fullmesh")) + flags |= MPTCP_PM_ADDR_FLAG_FULLMESH; else error(1, errno, "unknown flag %s", argv[arg]); } + if (flags & MPTCP_PM_ADDR_FLAG_SIGNAL && + flags & MPTCP_PM_ADDR_FLAG_FULLMESH) { + error(1, errno, "error flag fullmesh"); + } + rta = (void *)(data + off); rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS; rta->rta_len = RTA_LENGTH(4); @@ -271,6 +866,20 @@ int add_addr(int fd, int pm_family, int argc, char *argv[]) rta->rta_len = RTA_LENGTH(4); memcpy(RTA_DATA(rta), &ifindex, 4); off += NLMSG_ALIGN(rta->rta_len); + } else if (!strcmp(argv[arg], "port")) { + u_int16_t port; + + if (++arg >= argc) + error(1, 0, " missing port value"); + if (!(flags & MPTCP_PM_ADDR_FLAG_SIGNAL)) + error(1, 0, " flags must be signal when using port"); + + port = atoi(argv[arg]); + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT; + rta->rta_len = RTA_LENGTH(2); + memcpy(RTA_DATA(rta), &port, 2); + off += NLMSG_ALIGN(rta->rta_len); } else error(1, 0, "unknown keyword %s", argv[arg]); } @@ -287,6 +896,7 @@ int del_addr(int fd, int pm_family, int argc, char *argv[]) 1024]; struct rtattr *rta, *nest; struct nlmsghdr *nh; + u_int16_t family; int nest_start; u_int8_t id; int off = 0; @@ -296,11 +906,14 @@ int del_addr(int fd, int pm_family, int argc, char *argv[]) off = init_genl_req(data, pm_family, MPTCP_PM_CMD_DEL_ADDR, MPTCP_PM_VER); - /* the only argument is the address id */ - if (argc != 3) + /* the only argument is the address id (nonzero) */ + if (argc != 3 && argc != 4) syntax(argv); id = atoi(argv[2]); + /* zero id with the IP address */ + if (!id && argc != 4) + syntax(argv); nest_start = off; nest = (void *)(data + off); @@ -314,6 +927,30 @@ int del_addr(int fd, int pm_family, int argc, char *argv[]) rta->rta_len = RTA_LENGTH(1); memcpy(RTA_DATA(rta), &id, 1); off += NLMSG_ALIGN(rta->rta_len); + + if (!id) { + /* addr data */ + rta = (void *)(data + off); + if (inet_pton(AF_INET, argv[3], RTA_DATA(rta))) { + family = AF_INET; + rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4; + rta->rta_len = RTA_LENGTH(4); + } else if (inet_pton(AF_INET6, argv[3], RTA_DATA(rta))) { + family = AF_INET6; + rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6; + rta->rta_len = RTA_LENGTH(16); + } else { + error(1, errno, "can't parse ip %s", argv[3]); + } + off += NLMSG_ALIGN(rta->rta_len); + + /* family */ + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY; + rta->rta_len = RTA_LENGTH(2); + memcpy(RTA_DATA(rta), &family, 2); + off += NLMSG_ALIGN(rta->rta_len); + } nest->rta_len = off - nest_start; do_nl_req(fd, nh, off, 0); @@ -323,6 +960,7 @@ int del_addr(int fd, int pm_family, int argc, char *argv[]) static void print_addr(struct rtattr *attrs, int len) { uint16_t family = 0; + uint16_t port = 0; char str[1024]; uint32_t flags; uint8_t id; @@ -330,12 +968,16 @@ static void print_addr(struct rtattr *attrs, int len) while (RTA_OK(attrs, len)) { if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_FAMILY) memcpy(&family, RTA_DATA(attrs), 2); + if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_PORT) + memcpy(&port, RTA_DATA(attrs), 2); if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR4) { if (family != AF_INET) error(1, errno, "wrong IP (v4) for family %d", family); inet_ntop(AF_INET, RTA_DATA(attrs), str, sizeof(str)); printf("%s", str); + if (port) + printf(" %d", port); } if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR6) { if (family != AF_INET6) @@ -343,6 +985,8 @@ static void print_addr(struct rtattr *attrs, int len) family); inet_ntop(AF_INET6, RTA_DATA(attrs), str, sizeof(str)); printf("%s", str); + if (port) + printf(" %d", port); } if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ID) { memcpy(&id, RTA_DATA(attrs), 1); @@ -373,6 +1017,20 @@ static void print_addr(struct rtattr *attrs, int len) printf(","); } + if (flags & MPTCP_PM_ADDR_FLAG_FULLMESH) { + printf("fullmesh"); + flags &= ~MPTCP_PM_ADDR_FLAG_FULLMESH; + if (flags) + printf(","); + } + + if (flags & MPTCP_PM_ADDR_FLAG_IMPLICIT) { + printf("implicit"); + flags &= ~MPTCP_PM_ADDR_FLAG_IMPLICIT; + if (flags) + printf(","); + } + /* bump unknown flags, if any */ if (flags) printf("0x%x", flags); @@ -429,6 +1087,7 @@ int get_addr(int fd, int pm_family, int argc, char *argv[]) 1024]; struct rtattr *rta, *nest; struct nlmsghdr *nh; + u_int32_t token = 0; int nest_start; u_int8_t id; int off = 0; @@ -439,10 +1098,12 @@ int get_addr(int fd, int pm_family, int argc, char *argv[]) MPTCP_PM_VER); /* the only argument is the address id */ - if (argc != 3) + if (argc != 3 && argc != 5) syntax(argv); id = atoi(argv[2]); + if (argc == 5 && !strcmp(argv[3], "token")) + token = strtoul(argv[4], NULL, 10); nest_start = off; nest = (void *)(data + off); @@ -458,6 +1119,15 @@ int get_addr(int fd, int pm_family, int argc, char *argv[]) off += NLMSG_ALIGN(rta->rta_len); nest->rta_len = off - nest_start; + /* token */ + if (token) { + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ATTR_TOKEN; + rta->rta_len = RTA_LENGTH(4); + memcpy(RTA_DATA(rta), &token, 4); + off += NLMSG_ALIGN(rta->rta_len); + } + print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data))); return 0; } @@ -469,8 +1139,16 @@ int dump_addrs(int fd, int pm_family, int argc, char *argv[]) 1024]; pid_t pid = getpid(); struct nlmsghdr *nh; + u_int32_t token = 0; + struct rtattr *rta; int off = 0; + if (argc != 2 && argc != 4) + syntax(argv); + + if (argc == 4 && !strcmp(argv[2], "token")) + token = strtoul(argv[3], NULL, 10); + memset(data, 0, sizeof(data)); nh = (void *)data; off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR, @@ -480,6 +1158,15 @@ int dump_addrs(int fd, int pm_family, int argc, char *argv[]) nh->nlmsg_pid = pid; nh->nlmsg_len = off; + /* token */ + if (token) { + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ATTR_TOKEN; + rta->rta_len = RTA_LENGTH(4); + memcpy(RTA_DATA(rta), &token, 4); + off += NLMSG_ALIGN(rta->rta_len); + } + print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data))); return 0; } @@ -584,9 +1271,245 @@ int get_set_limits(int fd, int pm_family, int argc, char *argv[]) return 0; } +int add_listener(int argc, char *argv[]) +{ + struct sockaddr_storage addr; + struct sockaddr_in6 *a6; + struct sockaddr_in *a4; + u_int16_t family; + int enable = 1; + int sock; + int err; + + if (argc < 4) + syntax(argv); + + memset(&addr, 0, sizeof(struct sockaddr_storage)); + a4 = (struct sockaddr_in *)&addr; + a6 = (struct sockaddr_in6 *)&addr; + + if (inet_pton(AF_INET, argv[2], &a4->sin_addr)) { + family = AF_INET; + a4->sin_family = family; + a4->sin_port = htons(atoi(argv[3])); + } else if (inet_pton(AF_INET6, argv[2], &a6->sin6_addr)) { + family = AF_INET6; + a6->sin6_family = family; + a6->sin6_port = htons(atoi(argv[3])); + } else + error(1, errno, "can't parse ip %s", argv[2]); + + sock = socket(family, SOCK_STREAM, IPPROTO_MPTCP); + if (sock < 0) + error(1, errno, "can't create listener sock\n"); + + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable))) { + close(sock); + error(1, errno, "can't set SO_REUSEADDR on listener sock\n"); + } + + err = bind(sock, (struct sockaddr *)&addr, + ((family == AF_INET) ? sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6))); + + if (err == 0 && listen(sock, 30) == 0) + pause(); + + close(sock); + return 0; +} + +int set_flags(int fd, int pm_family, int argc, char *argv[]) +{ + char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + + NLMSG_ALIGN(sizeof(struct genlmsghdr)) + + 1024]; + struct rtattr *rta, *nest; + struct nlmsghdr *nh; + u_int32_t flags = 0; + u_int32_t token = 0; + u_int16_t rport = 0; + u_int16_t family; + void *rip = NULL; + int nest_start; + int use_id = 0; + u_int8_t id; + int off = 0; + int arg = 2; + + memset(data, 0, sizeof(data)); + nh = (void *)data; + off = init_genl_req(data, pm_family, MPTCP_PM_CMD_SET_FLAGS, + MPTCP_PM_VER); + + if (argc < 3) + syntax(argv); + + nest_start = off; + nest = (void *)(data + off); + nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR; + nest->rta_len = RTA_LENGTH(0); + off += NLMSG_ALIGN(nest->rta_len); + + if (!strcmp(argv[arg], "id")) { + if (++arg >= argc) + error(1, 0, " missing id value"); + + use_id = 1; + id = atoi(argv[arg]); + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ADDR_ATTR_ID; + rta->rta_len = RTA_LENGTH(1); + memcpy(RTA_DATA(rta), &id, 1); + off += NLMSG_ALIGN(rta->rta_len); + } else { + /* addr data */ + rta = (void *)(data + off); + if (inet_pton(AF_INET, argv[arg], RTA_DATA(rta))) { + family = AF_INET; + rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4; + rta->rta_len = RTA_LENGTH(4); + } else if (inet_pton(AF_INET6, argv[arg], RTA_DATA(rta))) { + family = AF_INET6; + rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6; + rta->rta_len = RTA_LENGTH(16); + } else { + error(1, errno, "can't parse ip %s", argv[arg]); + } + off += NLMSG_ALIGN(rta->rta_len); + + /* family */ + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY; + rta->rta_len = RTA_LENGTH(2); + memcpy(RTA_DATA(rta), &family, 2); + off += NLMSG_ALIGN(rta->rta_len); + } + + if (++arg >= argc) + error(1, 0, " missing flags keyword"); + + for (; arg < argc; arg++) { + if (!strcmp(argv[arg], "token")) { + if (++arg >= argc) + error(1, 0, " missing token value"); + + /* token */ + token = strtoul(argv[arg], NULL, 10); + } else if (!strcmp(argv[arg], "flags")) { + char *tok, *str; + + /* flags */ + if (++arg >= argc) + error(1, 0, " missing flags value"); + + for (str = argv[arg]; (tok = strtok(str, ",")); + str = NULL) { + if (!strcmp(tok, "backup")) + flags |= MPTCP_PM_ADDR_FLAG_BACKUP; + else if (!strcmp(tok, "fullmesh")) + flags |= MPTCP_PM_ADDR_FLAG_FULLMESH; + else if (strcmp(tok, "nobackup") && + strcmp(tok, "nofullmesh")) + error(1, errno, + "unknown flag %s", argv[arg]); + } + + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS; + rta->rta_len = RTA_LENGTH(4); + memcpy(RTA_DATA(rta), &flags, 4); + off += NLMSG_ALIGN(rta->rta_len); + } else if (!strcmp(argv[arg], "port")) { + u_int16_t port; + + if (use_id) + error(1, 0, " port can't be used with id"); + + if (++arg >= argc) + error(1, 0, " missing port value"); + + port = atoi(argv[arg]); + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT; + rta->rta_len = RTA_LENGTH(2); + memcpy(RTA_DATA(rta), &port, 2); + off += NLMSG_ALIGN(rta->rta_len); + } else if (!strcmp(argv[arg], "rport")) { + if (++arg >= argc) + error(1, 0, " missing remote port"); + + rport = atoi(argv[arg]); + } else if (!strcmp(argv[arg], "rip")) { + if (++arg >= argc) + error(1, 0, " missing remote ip"); + + rip = argv[arg]; + } else { + error(1, 0, "unknown keyword %s", argv[arg]); + } + } + nest->rta_len = off - nest_start; + + /* token */ + if (token) { + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ATTR_TOKEN; + rta->rta_len = RTA_LENGTH(4); + memcpy(RTA_DATA(rta), &token, 4); + off += NLMSG_ALIGN(rta->rta_len); + } + + /* remote addr/port */ + if (rip) { + nest_start = off; + nest = (void *)(data + off); + nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR_REMOTE; + nest->rta_len = RTA_LENGTH(0); + off += NLMSG_ALIGN(nest->rta_len); + + /* addr data */ + rta = (void *)(data + off); + if (inet_pton(AF_INET, rip, RTA_DATA(rta))) { + family = AF_INET; + rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4; + rta->rta_len = RTA_LENGTH(4); + } else if (inet_pton(AF_INET6, rip, RTA_DATA(rta))) { + family = AF_INET6; + rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6; + rta->rta_len = RTA_LENGTH(16); + } else { + error(1, errno, "can't parse ip %s", (char *)rip); + } + off += NLMSG_ALIGN(rta->rta_len); + + /* family */ + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY; + rta->rta_len = RTA_LENGTH(2); + memcpy(RTA_DATA(rta), &family, 2); + off += NLMSG_ALIGN(rta->rta_len); + + if (rport) { + rta = (void *)(data + off); + rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT; + rta->rta_len = RTA_LENGTH(2); + memcpy(RTA_DATA(rta), &rport, 2); + off += NLMSG_ALIGN(rta->rta_len); + } + + nest->rta_len = off - nest_start; + } + + do_nl_req(fd, nh, off, 0); + return 0; +} + int main(int argc, char *argv[]) { - int fd, pm_family; + int events_mcast_grp; + int pm_family; + int fd; if (argc < 2) syntax(argv); @@ -595,10 +1518,18 @@ int main(int argc, char *argv[]) if (fd == -1) error(1, errno, "socket netlink"); - pm_family = resolve_mptcp_pm_netlink(fd); + resolve_mptcp_pm_netlink(fd, &pm_family, &events_mcast_grp); if (!strcmp(argv[1], "add")) return add_addr(fd, pm_family, argc, argv); + else if (!strcmp(argv[1], "ann")) + return announce_addr(fd, pm_family, argc, argv); + else if (!strcmp(argv[1], "rem")) + return remove_addr(fd, pm_family, argc, argv); + else if (!strcmp(argv[1], "csf")) + return csf(fd, pm_family, argc, argv); + else if (!strcmp(argv[1], "dsf")) + return dsf(fd, pm_family, argc, argv); else if (!strcmp(argv[1], "del")) return del_addr(fd, pm_family, argc, argv); else if (!strcmp(argv[1], "flush")) @@ -609,6 +1540,12 @@ int main(int argc, char *argv[]) return dump_addrs(fd, pm_family, argc, argv); else if (!strcmp(argv[1], "limits")) return get_set_limits(fd, pm_family, argc, argv); + else if (!strcmp(argv[1], "set")) + return set_flags(fd, pm_family, argc, argv); + else if (!strcmp(argv[1], "events")) + return capture_events(fd, events_mcast_grp); + else if (!strcmp(argv[1], "listen")) + return add_listener(argc, argv); fprintf(stderr, "unknown sub-command: %s", argv[1]); syntax(argv); |