iproute2/ip/ipmptcp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3#include <stdio.h>
   4#include <string.h>
   5#include <rt_names.h>
   6#include <errno.h>
   7
   8#include <linux/genetlink.h>
   9#include <linux/mptcp.h>
  10
  11#include "utils.h"
  12#include "ip_common.h"
  13#include "libgenl.h"
  14#include "json_print.h"
  15
  16static void usage(void)
  17{
  18        fprintf(stderr,
  19                "Usage: ip mptcp endpoint add ADDRESS [ dev NAME ] [ id ID ]\n"
  20                "                                     [ port NR ] [ FLAG-LIST ]\n"
  21                "       ip mptcp endpoint delete id ID\n"
  22                "       ip mptcp endpoint show [ id ID ]\n"
  23                "       ip mptcp endpoint flush\n"
  24                "       ip mptcp limits set [ subflows NR ] [ add_addr_accepted NR ]\n"
  25                "       ip mptcp limits show\n"
  26                "       ip mptcp monitor\n"
  27                "FLAG-LIST := [ FLAG-LIST ] FLAG\n"
  28                "FLAG  := [ signal | subflow | backup ]\n");
  29
  30        exit(-1);
  31}
  32
  33/* netlink socket */
  34static struct rtnl_handle genl_rth = { .fd = -1 };
  35static int genl_family = -1;
  36
  37#define MPTCP_BUFLEN    4096
  38#define MPTCP_REQUEST(_req,  _cmd, _flags)      \
  39        GENL_REQUEST(_req, MPTCP_BUFLEN, genl_family, 0,        \
  40                     MPTCP_PM_VER, _cmd, _flags)
  41
  42/* Mapping from argument to address flag mask */
  43static const struct {
  44        const char *name;
  45        unsigned long value;
  46} mptcp_addr_flag_names[] = {
  47        { "signal",             MPTCP_PM_ADDR_FLAG_SIGNAL },
  48        { "subflow",            MPTCP_PM_ADDR_FLAG_SUBFLOW },
  49        { "backup",             MPTCP_PM_ADDR_FLAG_BACKUP },
  50};
  51
  52static void print_mptcp_addr_flags(unsigned int flags)
  53{
  54        unsigned int i;
  55
  56        for (i = 0; i < ARRAY_SIZE(mptcp_addr_flag_names); i++) {
  57                unsigned long mask = mptcp_addr_flag_names[i].value;
  58
  59                if (flags & mask) {
  60                        print_string(PRINT_FP, NULL, "%s ",
  61                                     mptcp_addr_flag_names[i].name);
  62                        print_bool(PRINT_JSON,
  63                                   mptcp_addr_flag_names[i].name, NULL, true);
  64                }
  65
  66                flags &= ~mask;
  67        }
  68
  69        if (flags) {
  70                /* unknown flags */
  71                SPRINT_BUF(b1);
  72
  73                snprintf(b1, sizeof(b1), "%02x", flags);
  74                print_string(PRINT_ANY, "rawflags", "rawflags %s ", b1);
  75        }
  76}
  77
  78static int get_flags(const char *arg, __u32 *flags)
  79{
  80        unsigned int i;
  81
  82        for (i = 0; i < ARRAY_SIZE(mptcp_addr_flag_names); i++) {
  83                if (strcmp(arg, mptcp_addr_flag_names[i].name))
  84                        continue;
  85
  86                *flags |= mptcp_addr_flag_names[i].value;
  87                return 0;
  88        }
  89        return -1;
  90}
  91
  92static int mptcp_parse_opt(int argc, char **argv, struct nlmsghdr *n,
  93                         bool adding)
  94{
  95        struct rtattr *attr_addr;
  96        bool addr_set = false;
  97        inet_prefix address;
  98        bool id_set = false;
  99        __u32 index = 0;
 100        __u32 flags = 0;
 101        __u16 port = 0;
 102        __u8 id = 0;
 103
 104        ll_init_map(&rth);
 105        while (argc > 0) {
 106                if (get_flags(*argv, &flags) == 0) {
 107                } else if (matches(*argv, "id") == 0) {
 108                        NEXT_ARG();
 109
 110                        if (get_u8(&id, *argv, 0))
 111                                invarg("invalid ID\n", *argv);
 112                        id_set = true;
 113                } else if (matches(*argv, "dev") == 0) {
 114                        const char *ifname;
 115
 116                        NEXT_ARG();
 117
 118                        ifname = *argv;
 119
 120                        if (check_ifname(ifname))
 121                                invarg("invalid interface name\n", ifname);
 122
 123                        index = ll_name_to_index(ifname);
 124
 125                        if (!index)
 126                                invarg("device does not exist\n", ifname);
 127
 128                } else if (matches(*argv, "port") == 0) {
 129                        NEXT_ARG();
 130                        if (get_u16(&port, *argv, 0))
 131                                invarg("expected port", *argv);
 132                } else if (get_addr(&address, *argv, AF_UNSPEC) == 0) {
 133                        addr_set = true;
 134                } else {
 135                        invarg("unknown argument", *argv);
 136                }
 137                NEXT_ARG_FWD();
 138        }
 139
 140        if (!addr_set && adding)
 141                missarg("ADDRESS");
 142
 143        if (!id_set && !adding)
 144                missarg("ID");
 145
 146        if (port && !(flags & MPTCP_PM_ADDR_FLAG_SIGNAL))
 147                invarg("flags must have signal when using port", "port");
 148
 149        attr_addr = addattr_nest(n, MPTCP_BUFLEN,
 150                                 MPTCP_PM_ATTR_ADDR | NLA_F_NESTED);
 151        if (id_set)
 152                addattr8(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_ID, id);
 153        if (flags)
 154                addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_FLAGS, flags);
 155        if (index)
 156                addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_IF_IDX, index);
 157        if (port)
 158                addattr16(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_PORT, port);
 159        if (addr_set) {
 160                int type;
 161
 162                addattr16(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_FAMILY,
 163                          address.family);
 164                type = address.family == AF_INET ? MPTCP_PM_ADDR_ATTR_ADDR4 :
 165                                                   MPTCP_PM_ADDR_ATTR_ADDR6;
 166                addattr_l(n, MPTCP_BUFLEN, type, &address.data,
 167                          address.bytelen);
 168        }
 169
 170        addattr_nest_end(n, attr_addr);
 171        return 0;
 172}
 173
 174static int mptcp_addr_modify(int argc, char **argv, int cmd)
 175{
 176        MPTCP_REQUEST(req, cmd, NLM_F_REQUEST);
 177        int ret;
 178
 179        ret = mptcp_parse_opt(argc, argv, &req.n, cmd == MPTCP_PM_CMD_ADD_ADDR);
 180        if (ret)
 181                return ret;
 182
 183        if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
 184                return -2;
 185
 186        return 0;
 187}
 188
 189static int print_mptcp_addrinfo(struct rtattr *addrinfo)
 190{
 191        struct rtattr *tb[MPTCP_PM_ADDR_ATTR_MAX + 1];
 192        __u8 family = AF_UNSPEC, addr_attr_type;
 193        const char *ifname;
 194        unsigned int flags;
 195        __u16 id, port;
 196        int index;
 197
 198        parse_rtattr_nested(tb, MPTCP_PM_ADDR_ATTR_MAX, addrinfo);
 199
 200        open_json_object(NULL);
 201        if (tb[MPTCP_PM_ADDR_ATTR_FAMILY])
 202                family = rta_getattr_u8(tb[MPTCP_PM_ADDR_ATTR_FAMILY]);
 203
 204        addr_attr_type = family == AF_INET ? MPTCP_PM_ADDR_ATTR_ADDR4 :
 205                                             MPTCP_PM_ADDR_ATTR_ADDR6;
 206        if (tb[addr_attr_type]) {
 207                print_string(PRINT_ANY, "address", "%s ",
 208                             format_host_rta(family, tb[addr_attr_type]));
 209        }
 210        if (tb[MPTCP_PM_ADDR_ATTR_PORT]) {
 211                port = rta_getattr_u16(tb[MPTCP_PM_ADDR_ATTR_PORT]);
 212                if (port)
 213                        print_uint(PRINT_ANY, "port", "port %u ", port);
 214        }
 215        if (tb[MPTCP_PM_ADDR_ATTR_ID]) {
 216                id = rta_getattr_u8(tb[MPTCP_PM_ADDR_ATTR_ID]);
 217                print_uint(PRINT_ANY, "id", "id %u ", id);
 218        }
 219        if (tb[MPTCP_PM_ADDR_ATTR_FLAGS]) {
 220                flags = rta_getattr_u32(tb[MPTCP_PM_ADDR_ATTR_FLAGS]);
 221                print_mptcp_addr_flags(flags);
 222        }
 223        if (tb[MPTCP_PM_ADDR_ATTR_IF_IDX]) {
 224                index = rta_getattr_s32(tb[MPTCP_PM_ADDR_ATTR_IF_IDX]);
 225                ifname = index ? ll_index_to_name(index) : NULL;
 226
 227                if (ifname)
 228                        print_string(PRINT_ANY, "dev", "dev %s ", ifname);
 229        }
 230
 231        close_json_object();
 232        print_string(PRINT_FP, NULL, "\n", NULL);
 233        fflush(stdout);
 234
 235        return 0;
 236}
 237
 238static int print_mptcp_addr(struct nlmsghdr *n, void *arg)
 239{
 240        struct rtattr *tb[MPTCP_PM_ATTR_MAX + 1];
 241        struct genlmsghdr *ghdr;
 242        struct rtattr *addrinfo;
 243        int len = n->nlmsg_len;
 244
 245        if (n->nlmsg_type != genl_family)
 246                return 0;
 247
 248        len -= NLMSG_LENGTH(GENL_HDRLEN);
 249        if (len < 0)
 250                return -1;
 251
 252        ghdr = NLMSG_DATA(n);
 253        parse_rtattr_flags(tb, MPTCP_PM_ATTR_MAX, (void *) ghdr + GENL_HDRLEN,
 254                           len, NLA_F_NESTED);
 255        addrinfo = tb[MPTCP_PM_ATTR_ADDR];
 256        if (!addrinfo)
 257                return -1;
 258
 259        ll_init_map(&rth);
 260        return print_mptcp_addrinfo(addrinfo);
 261}
 262
 263static int mptcp_addr_dump(void)
 264{
 265        MPTCP_REQUEST(req, MPTCP_PM_CMD_GET_ADDR, NLM_F_REQUEST | NLM_F_DUMP);
 266
 267        if (rtnl_send(&genl_rth, &req.n, req.n.nlmsg_len) < 0) {
 268                perror("Cannot send show request");
 269                exit(1);
 270        }
 271
 272        new_json_obj(json);
 273
 274        if (rtnl_dump_filter(&genl_rth, print_mptcp_addr, stdout) < 0) {
 275                fprintf(stderr, "Dump terminated\n");
 276                delete_json_obj();
 277                fflush(stdout);
 278                return -2;
 279        }
 280
 281        delete_json_obj();
 282        fflush(stdout);
 283        return 0;
 284}
 285
 286static int mptcp_addr_show(int argc, char **argv)
 287{
 288        MPTCP_REQUEST(req, MPTCP_PM_CMD_GET_ADDR, NLM_F_REQUEST);
 289        struct nlmsghdr *answer;
 290        int ret;
 291
 292        if (argc <= 0)
 293                return mptcp_addr_dump();
 294
 295        ret = mptcp_parse_opt(argc, argv, &req.n, false);
 296        if (ret)
 297                return ret;
 298
 299        if (rtnl_talk(&genl_rth, &req.n, &answer) < 0)
 300                return -2;
 301
 302        return print_mptcp_addr(answer, stdout);
 303}
 304
 305static int mptcp_addr_flush(int argc, char **argv)
 306{
 307        MPTCP_REQUEST(req, MPTCP_PM_CMD_FLUSH_ADDRS, NLM_F_REQUEST);
 308
 309        if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
 310                return -2;
 311
 312        return 0;
 313}
 314
 315static int mptcp_parse_limit(int argc, char **argv, struct nlmsghdr *n)
 316{
 317        bool set_rcv_add_addrs = false;
 318        bool set_subflows = false;
 319        __u32 rcv_add_addrs = 0;
 320        __u32 subflows = 0;
 321
 322        while (argc > 0) {
 323                if (matches(*argv, "subflows") == 0) {
 324                        NEXT_ARG();
 325
 326                        if (get_u32(&subflows, *argv, 0))
 327                                invarg("invalid subflows\n", *argv);
 328                        set_subflows = true;
 329                } else if (matches(*argv, "add_addr_accepted") == 0) {
 330                        NEXT_ARG();
 331
 332                        if (get_u32(&rcv_add_addrs, *argv, 0))
 333                                invarg("invalid add_addr_accepted\n", *argv);
 334                        set_rcv_add_addrs = true;
 335                } else {
 336                        invarg("unknown limit", *argv);
 337                }
 338                NEXT_ARG_FWD();
 339        }
 340
 341        if (set_rcv_add_addrs)
 342                addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ATTR_RCV_ADD_ADDRS,
 343                          rcv_add_addrs);
 344        if (set_subflows)
 345                addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ATTR_SUBFLOWS, subflows);
 346        return set_rcv_add_addrs || set_subflows;
 347}
 348
 349static int print_mptcp_limit(struct nlmsghdr *n, void *arg)
 350{
 351        struct rtattr *tb[MPTCP_PM_ATTR_MAX + 1];
 352        struct genlmsghdr *ghdr;
 353        int len = n->nlmsg_len;
 354        __u32 val;
 355
 356        if (n->nlmsg_type != genl_family)
 357                return 0;
 358
 359        len -= NLMSG_LENGTH(GENL_HDRLEN);
 360        if (len < 0)
 361                return -1;
 362
 363        ghdr = NLMSG_DATA(n);
 364        parse_rtattr(tb, MPTCP_PM_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len);
 365
 366        open_json_object(NULL);
 367        if (tb[MPTCP_PM_ATTR_RCV_ADD_ADDRS]) {
 368                val = rta_getattr_u32(tb[MPTCP_PM_ATTR_RCV_ADD_ADDRS]);
 369
 370                print_uint(PRINT_ANY, "add_addr_accepted",
 371                           "add_addr_accepted %d ", val);
 372        }
 373
 374        if (tb[MPTCP_PM_ATTR_SUBFLOWS]) {
 375                val = rta_getattr_u32(tb[MPTCP_PM_ATTR_SUBFLOWS]);
 376
 377                print_uint(PRINT_ANY, "subflows", "subflows %d ", val);
 378        }
 379        print_string(PRINT_FP, NULL, "%s", "\n");
 380        fflush(stdout);
 381        close_json_object();
 382        return 0;
 383}
 384
 385static int mptcp_limit_get_set(int argc, char **argv, int cmd)
 386{
 387        bool do_get = cmd == MPTCP_PM_CMD_GET_LIMITS;
 388        MPTCP_REQUEST(req, cmd, NLM_F_REQUEST);
 389        struct nlmsghdr *answer;
 390        int ret;
 391
 392        ret = mptcp_parse_limit(argc, argv, &req.n);
 393        if (ret < 0)
 394                return -1;
 395
 396        if (rtnl_talk(&genl_rth, &req.n, do_get ? &answer : NULL) < 0)
 397                return -2;
 398
 399        if (do_get)
 400                return print_mptcp_limit(answer, stdout);
 401        return 0;
 402}
 403
 404static const char * const event_to_str[] = {
 405        [MPTCP_EVENT_CREATED] = "CREATED",
 406        [MPTCP_EVENT_ESTABLISHED] = "ESTABLISHED",
 407        [MPTCP_EVENT_CLOSED] = "CLOSED",
 408        [MPTCP_EVENT_ANNOUNCED] = "ANNOUNCED",
 409        [MPTCP_EVENT_REMOVED] = "REMOVED",
 410        [MPTCP_EVENT_SUB_ESTABLISHED] = "SF_ESTABLISHED",
 411        [MPTCP_EVENT_SUB_CLOSED] = "SF_CLOSED",
 412        [MPTCP_EVENT_SUB_PRIORITY] = "SF_PRIO",
 413};
 414
 415static void print_addr(const char *key, int af, struct rtattr *value)
 416{
 417        void *data = RTA_DATA(value);
 418        char str[INET6_ADDRSTRLEN];
 419
 420        if (inet_ntop(af, data, str, sizeof(str)))
 421                printf(" %s=%s", key, str);
 422}
 423
 424static int mptcp_monitor_msg(struct rtnl_ctrl_data *ctrl,
 425                             struct nlmsghdr *n, void *arg)
 426{
 427        const struct genlmsghdr *ghdr = NLMSG_DATA(n);
 428        struct rtattr *tb[MPTCP_ATTR_MAX + 1];
 429        int len = n->nlmsg_len;
 430
 431        len -= NLMSG_LENGTH(GENL_HDRLEN);
 432        if (len < 0)
 433                return -1;
 434
 435        if (n->nlmsg_type != genl_family)
 436                return 0;
 437
 438        if (timestamp)
 439                print_timestamp(stdout);
 440
 441        if (ghdr->cmd >= ARRAY_SIZE(event_to_str)) {
 442                printf("[UNKNOWN %u]\n", ghdr->cmd);
 443                goto out;
 444        }
 445
 446        if (event_to_str[ghdr->cmd] == NULL) {
 447                printf("[UNKNOWN %u]\n", ghdr->cmd);
 448                goto out;
 449        }
 450
 451        printf("[%14s]", event_to_str[ghdr->cmd]);
 452
 453        parse_rtattr(tb, MPTCP_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len);
 454
 455        printf(" token=%08x", rta_getattr_u32(tb[MPTCP_ATTR_TOKEN]));
 456
 457        if (tb[MPTCP_ATTR_REM_ID])
 458                printf(" remid=%u", rta_getattr_u8(tb[MPTCP_ATTR_REM_ID]));
 459        if (tb[MPTCP_ATTR_LOC_ID])
 460                printf(" locid=%u", rta_getattr_u8(tb[MPTCP_ATTR_LOC_ID]));
 461
 462        if (tb[MPTCP_ATTR_SADDR4])
 463                print_addr("saddr4", AF_INET, tb[MPTCP_ATTR_SADDR4]);
 464        if (tb[MPTCP_ATTR_DADDR4])
 465                print_addr("daddr4", AF_INET, tb[MPTCP_ATTR_DADDR4]);
 466        if (tb[MPTCP_ATTR_SADDR6])
 467                print_addr("saddr6", AF_INET6, tb[MPTCP_ATTR_SADDR6]);
 468        if (tb[MPTCP_ATTR_DADDR6])
 469                print_addr("daddr6", AF_INET6, tb[MPTCP_ATTR_DADDR6]);
 470        if (tb[MPTCP_ATTR_SPORT])
 471                printf(" sport=%u", rta_getattr_be16(tb[MPTCP_ATTR_SPORT]));
 472        if (tb[MPTCP_ATTR_DPORT])
 473                printf(" dport=%u", rta_getattr_be16(tb[MPTCP_ATTR_DPORT]));
 474        if (tb[MPTCP_ATTR_BACKUP])
 475                printf(" backup=%d", rta_getattr_u8(tb[MPTCP_ATTR_BACKUP]));
 476        if (tb[MPTCP_ATTR_ERROR])
 477                printf(" error=%d", rta_getattr_u8(tb[MPTCP_ATTR_ERROR]));
 478        if (tb[MPTCP_ATTR_FLAGS])
 479                printf(" flags=%x", rta_getattr_u16(tb[MPTCP_ATTR_FLAGS]));
 480        if (tb[MPTCP_ATTR_TIMEOUT])
 481                printf(" timeout=%u", rta_getattr_u32(tb[MPTCP_ATTR_TIMEOUT]));
 482        if (tb[MPTCP_ATTR_IF_IDX])
 483                printf(" ifindex=%d", rta_getattr_s32(tb[MPTCP_ATTR_IF_IDX]));
 484        if (tb[MPTCP_ATTR_RESET_REASON])
 485                printf(" reset_reason=%u", rta_getattr_u32(tb[MPTCP_ATTR_RESET_REASON]));
 486        if (tb[MPTCP_ATTR_RESET_FLAGS])
 487                printf(" reset_flags=0x%x", rta_getattr_u32(tb[MPTCP_ATTR_RESET_FLAGS]));
 488
 489        puts("");
 490out:
 491        fflush(stdout);
 492        return 0;
 493}
 494
 495static int mptcp_monitor(void)
 496{
 497        if (genl_add_mcast_grp(&genl_rth, genl_family, MPTCP_PM_EV_GRP_NAME) < 0) {
 498                perror("can't subscribe to mptcp events");
 499                return 1;
 500        }
 501
 502        if (rtnl_listen(&genl_rth, mptcp_monitor_msg, stdout) < 0)
 503                return 2;
 504
 505        return 0;
 506}
 507
 508int do_mptcp(int argc, char **argv)
 509{
 510        if (argc == 0)
 511                usage();
 512
 513        if (matches(*argv, "help") == 0)
 514                usage();
 515
 516        if (genl_init_handle(&genl_rth, MPTCP_PM_NAME, &genl_family))
 517                exit(1);
 518
 519        if (matches(*argv, "endpoint") == 0) {
 520                NEXT_ARG_FWD();
 521                if (argc == 0)
 522                        return mptcp_addr_show(0, NULL);
 523
 524                if (matches(*argv, "add") == 0)
 525                        return mptcp_addr_modify(argc-1, argv+1,
 526                                                 MPTCP_PM_CMD_ADD_ADDR);
 527                if (matches(*argv, "delete") == 0)
 528                        return mptcp_addr_modify(argc-1, argv+1,
 529                                                 MPTCP_PM_CMD_DEL_ADDR);
 530                if (matches(*argv, "show") == 0)
 531                        return mptcp_addr_show(argc-1, argv+1);
 532                if (matches(*argv, "flush") == 0)
 533                        return mptcp_addr_flush(argc-1, argv+1);
 534
 535                goto unknown;
 536        }
 537
 538        if (matches(*argv, "limits") == 0) {
 539                NEXT_ARG_FWD();
 540                if (argc == 0)
 541                        return mptcp_limit_get_set(0, NULL,
 542                                                   MPTCP_PM_CMD_GET_LIMITS);
 543
 544                if (matches(*argv, "set") == 0)
 545                        return mptcp_limit_get_set(argc-1, argv+1,
 546                                                   MPTCP_PM_CMD_SET_LIMITS);
 547                if (matches(*argv, "show") == 0)
 548                        return mptcp_limit_get_set(argc-1, argv+1,
 549                                                   MPTCP_PM_CMD_GET_LIMITS);
 550        }
 551
 552        if (matches(*argv, "monitor") == 0) {
 553                NEXT_ARG_FWD();
 554                if (argc == 0)
 555                        return mptcp_monitor();
 556
 557                goto unknown;
 558        }
 559
 560unknown:
 561        fprintf(stderr, "Command \"%s\" is unknown, try \"ip mptcp help\".\n",
 562                *argv);
 563        exit(-1);
 564}
 565