]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
tipc: add the ability to get UDP bearer options
authorRichard Alpe <richard.alpe@ericsson.com>
Tue, 30 Aug 2016 08:37:00 +0000 (10:37 +0200)
committerStephen Hemminger <stephen@networkplumber.org>
Thu, 1 Sep 2016 15:34:35 +0000 (08:34 -0700)
In this patch we introduce the ability to get UDP specific bearer
options such as remoteip, remoteport, localip and localport.

After some discussions on tipc-discussion on how to handle media
specific options we agreed to pass them after the media.

For media generic bearer options we already do:
$ tipc bearer get OPTION media MEDIA name|device NAME|DEVICE

For the UDP media specific bearer options we introduce in this path:
$ tipc bearer get media udp name NAME OPTION
such as
$ tipc bearer get media udp name NAME remoteip

This allows bash-completion to tab complete only appropriate options,
it makes more logical sense and it scales better. Even though it might
look a little different to the user.

In order to use the existing option parsing framework to do this we
add a flag (OPT_KEY) to the option parsing function.

If the UDP bearer has multiple remoteip addresses associated with it
(replicast) we handle the TIPC_NLA_UDP_MULTI_REMOTEIP flag and send
a TIPC_NL_UDP_GET_REMOTEIP query transparently to the user.

Signed-off-by: Richard Alpe <richard.alpe@ericsson.com>
Reviewed-by: Parthasarathy Bhuvaragan <parthasarathy.bhuvaragan@ericsson.com>
Acked-by: Jon Maloy <jon.maloy@ericsson.com>
man/man8/tipc-bearer.8
tipc/bearer.c
tipc/cmdl.c
tipc/cmdl.h
tipc/link.c
tipc/media.c

index 32be64db9fa045f61c9271161c69632faa089c5b..d95b1e1c02357be003ed2cbcaf34ff5bbc7113d5 100644 (file)
@@ -73,7 +73,7 @@ tipc-bearer \- show or modify TIPC bearers
 
 .ti -8
 .B tipc bearer get
-.RB "{ " "priority" " | " tolerance " | " window " } " media
+.RB "[ " "priority" " | " tolerance " | " window " ] " media
 .br
 .RB "{ { " eth " | " ib " } " device
 .IR "DEVICE" " }"
@@ -81,7 +81,8 @@ tipc-bearer \- show or modify TIPC bearers
 .br
 .RB "{ " udp
 .B name
-.IR NAME " }"
+.IR NAME
+.RB "[ " "localip " "| " "localport " "| " "remoteip " "| " "remoteport " "] }"
 .br
 
 .ti -8
index a9fc1d2a68a23d7bc2ebd60d878c011a7a318591..8729dad4a06099372743161026bdc6c326e5480a 100644 (file)
@@ -14,6 +14,7 @@
 #include <string.h>
 #include <netdb.h>
 #include <errno.h>
+#include <arpa/inet.h>
 
 #include <linux/tipc_netlink.h>
 #include <linux/tipc.h>
 #include "msg.h"
 #include "bearer.h"
 
+#define UDP_PROP_IP 1
+#define UDP_PROP_PORT 2
+
+struct cb_data {
+       int attr;
+       int prop;
+       struct nlmsghdr *nlh;
+};
+
 static void _print_bearer_opts(void)
 {
        fprintf(stderr,
@@ -57,14 +67,17 @@ static void cmd_bearer_enable_l2_help(struct cmdl *cmdl, char *media)
 static void cmd_bearer_enable_udp_help(struct cmdl *cmdl, char *media)
 {
        fprintf(stderr,
-               "Usage: %s bearer enable media %s name NAME localip IP [OPTIONS]\n"
-               "\nOPTIONS\n"
+               "Usage: %s bearer enable [OPTIONS] media %s name NAME localip IP [UDP OPTIONS]\n\n",
+               cmdl->argv[0], media);
+       fprintf(stderr,
+               "OPTIONS\n"
                " domain DOMAIN         - Discovery domain\n"
-               " priority PRIORITY     - Bearer priority\n"
+               " priority PRIORITY     - Bearer priority\n\n");
+       fprintf(stderr,
+               "UDP OPTIONS\n"
                " localport PORT        - Local UDP port (default 6118)\n"
                " remoteip IP           - Remote IP address\n"
-               " remoteport IP         - Remote UDP port (default 6118)\n",
-               cmdl->argv[0], media);
+               " remoteport PORT       - Remote UDP port (default 6118)\n");
 }
 
 static int get_netid_cb(const struct nlmsghdr *nlh, void *data)
@@ -283,10 +296,10 @@ static int cmd_bearer_add_media(struct nlmsghdr *nlh, const struct cmd *cmd,
        struct opt *opt;
        struct nlattr *attrs;
        struct opt opts[] = {
-               { "remoteip",           NULL },
-               { "remoteport",         NULL },
-               { "name",               NULL },
-               { "media",              NULL },
+               { "remoteip",           OPT_KEYVAL,     NULL },
+               { "remoteport",         OPT_KEYVAL,     NULL },
+               { "name",               OPT_KEYVAL,     NULL },
+               { "media",              OPT_KEYVAL,     NULL },
                { NULL }
        };
        struct tipc_sup_media sup_media[] = {
@@ -364,15 +377,15 @@ static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd,
        struct nlattr *nest;
        char buf[MNL_SOCKET_BUFFER_SIZE];
        struct opt opts[] = {
-               { "device",             NULL },
-               { "domain",             NULL },
-               { "localip",            NULL },
-               { "localport",          NULL },
-               { "media",              NULL },
-               { "name",               NULL },
-               { "priority",           NULL },
-               { "remoteip",           NULL },
-               { "remoteport",         NULL },
+               { "device",             OPT_KEYVAL,     NULL },
+               { "domain",             OPT_KEYVAL,     NULL },
+               { "localip",            OPT_KEYVAL,     NULL },
+               { "localport",          OPT_KEYVAL,     NULL },
+               { "media",              OPT_KEYVAL,     NULL },
+               { "name",               OPT_KEYVAL,     NULL },
+               { "priority",           OPT_KEYVAL,     NULL },
+               { "remoteip",           OPT_KEYVAL,     NULL },
+               { "remoteport",         OPT_KEYVAL,     NULL },
                { NULL }
        };
        struct tipc_sup_media sup_media[] = {
@@ -446,9 +459,9 @@ static int cmd_bearer_disable(struct nlmsghdr *nlh, const struct cmd *cmd,
        char buf[MNL_SOCKET_BUFFER_SIZE];
        struct nlattr *nest;
        struct opt opts[] = {
-               { "device",             NULL },
-               { "name",               NULL },
-               { "media",              NULL },
+               { "device",             OPT_KEYVAL,     NULL },
+               { "name",               OPT_KEYVAL,     NULL },
+               { "media",              OPT_KEYVAL,     NULL },
                { NULL }
        };
        struct tipc_sup_media sup_media[] = {
@@ -512,9 +525,9 @@ static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
        struct nlattr *props;
        struct nlattr *attrs;
        struct opt opts[] = {
-               { "device",             NULL },
-               { "media",              NULL },
-               { "name",               NULL },
+               { "device",             OPT_KEYVAL,     NULL },
+               { "media",              OPT_KEYVAL,     NULL },
+               { "name",               OPT_KEYVAL,     NULL },
                { NULL }
        };
        struct tipc_sup_media sup_media[] = {
@@ -576,7 +589,7 @@ static int cmd_bearer_set(struct nlmsghdr *nlh, const struct cmd *cmd,
 
 static void cmd_bearer_get_help(struct cmdl *cmdl)
 {
-       fprintf(stderr, "Usage: %s bearer get OPTION media MEDIA ARGS...\n",
+       fprintf(stderr, "Usage: %s bearer get [OPTION] media MEDIA ARGS...\n",
                cmdl->argv[0]);
        _print_bearer_opts();
        _print_bearer_media();
@@ -584,8 +597,14 @@ static void cmd_bearer_get_help(struct cmdl *cmdl)
 
 static void cmd_bearer_get_udp_help(struct cmdl *cmdl, char *media)
 {
-       fprintf(stderr, "Usage: %s bearer get OPTION media %s name NAME\n\n",
+       fprintf(stderr, "Usage: %s bearer get [OPTION] media %s name NAME [UDP OPTIONS]\n\n",
                cmdl->argv[0], media);
+       fprintf(stderr,
+               "UDP OPTIONS\n"
+               " remoteip              - Remote ip address\n"
+               " remoteport            - Remote port\n"
+               " localip               - Local ip address\n"
+               " localport             - Local port\n\n");
        _print_bearer_opts();
 }
 
@@ -597,6 +616,115 @@ static void cmd_bearer_get_l2_help(struct cmdl *cmdl, char *media)
        _print_bearer_opts();
 }
 
+
+static int bearer_dump_udp_cb(const struct nlmsghdr *nlh, void *data)
+{
+       struct sockaddr_storage *addr;
+       struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+       struct nlattr *info[TIPC_NLA_UDP_MAX + 1] = {};
+
+       mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
+
+       if (!info[TIPC_NLA_UDP_REMOTE])
+               return MNL_CB_ERROR;
+
+       addr = mnl_attr_get_payload(info[TIPC_NLA_UDP_REMOTE]);
+
+       if (addr->ss_family == AF_INET) {
+               struct sockaddr_in *ipv4 = (struct sockaddr_in *) addr;
+
+               printf("%s\n", inet_ntoa(ipv4->sin_addr));
+       } else if (addr->ss_family == AF_INET6) {
+               char straddr[INET6_ADDRSTRLEN];
+               struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *) addr;
+
+               if (!inet_ntop(AF_INET6, &ipv6->sin6_addr, straddr,
+                                       sizeof(straddr))) {
+                       fprintf(stderr, "error, parsing IPv6 addr\n");
+                       return MNL_CB_ERROR;
+               }
+               printf("%s\n", straddr);
+
+       } else {
+               return MNL_CB_ERROR;
+       }
+
+       return MNL_CB_OK;
+}
+
+static int bearer_get_udp_cb(const struct nlmsghdr *nlh, void *data)
+{
+       struct cb_data *cb_data = (struct cb_data *) data;
+       struct sockaddr_storage *addr;
+       struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+       struct nlattr *info[TIPC_NLA_MAX + 1] = {};
+       struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1] = {};
+       struct nlattr *opts[TIPC_NLA_UDP_MAX + 1] = {};
+
+       mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
+       if (!info[TIPC_NLA_BEARER])
+               return MNL_CB_ERROR;
+
+       mnl_attr_parse_nested(info[TIPC_NLA_BEARER], parse_attrs, attrs);
+       if (!attrs[TIPC_NLA_BEARER_UDP_OPTS])
+               return MNL_CB_ERROR;
+
+       mnl_attr_parse_nested(attrs[TIPC_NLA_BEARER_UDP_OPTS], parse_attrs, opts);
+       if (!opts[TIPC_NLA_UDP_LOCAL])
+               return MNL_CB_ERROR;
+
+       if ((cb_data->attr == TIPC_NLA_UDP_REMOTE) &&
+           (cb_data->prop == UDP_PROP_IP) &&
+           opts[TIPC_NLA_UDP_MULTI_REMOTEIP]) {
+               struct genlmsghdr *genl = mnl_nlmsg_get_payload(cb_data->nlh);
+
+               genl->cmd = TIPC_NL_UDP_GET_REMOTEIP;
+               return msg_dumpit(cb_data->nlh, bearer_dump_udp_cb, NULL);
+       }
+
+       addr = mnl_attr_get_payload(opts[cb_data->attr]);
+
+       if (addr->ss_family == AF_INET) {
+               struct sockaddr_in *ipv4 = (struct sockaddr_in *) addr;
+
+               switch (cb_data->prop) {
+               case UDP_PROP_IP:
+                       printf("%s\n", inet_ntoa(ipv4->sin_addr));
+                       break;
+               case UDP_PROP_PORT:
+                       printf("%u\n", ntohs(ipv4->sin_port));
+                       break;
+               default:
+                       return MNL_CB_ERROR;
+               }
+
+       } else if (addr->ss_family == AF_INET6) {
+               char straddr[INET6_ADDRSTRLEN];
+               struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *) addr;
+
+               switch (cb_data->prop) {
+               case UDP_PROP_IP:
+                       if (!inet_ntop(AF_INET6, &ipv6->sin6_addr, straddr,
+                                               sizeof(straddr))) {
+                               fprintf(stderr, "error, parsing IPv6 addr\n");
+                               return MNL_CB_ERROR;
+                       }
+                       printf("%s\n", straddr);
+                       break;
+               case UDP_PROP_PORT:
+                       printf("%u\n", ntohs(ipv6->sin6_port));
+                       break;
+               default:
+                       return MNL_CB_ERROR;
+               }
+
+       } else {
+               return MNL_CB_ERROR;
+       }
+
+       return MNL_CB_OK;
+}
+
 static int bearer_get_cb(const struct nlmsghdr *nlh, void *data)
 {
        int *prop = data;
@@ -622,6 +750,86 @@ static int bearer_get_cb(const struct nlmsghdr *nlh, void *data)
        return MNL_CB_OK;
 }
 
+static int cmd_bearer_get_media(struct nlmsghdr *nlh, const struct cmd *cmd,
+                               struct cmdl *cmdl, void *data)
+{
+       int err;
+       char *media;
+       char buf[MNL_SOCKET_BUFFER_SIZE];
+       struct opt *opt;
+       struct cb_data cb_data = {0};
+       struct nlattr *attrs;
+       struct opt opts[] = {
+               { "localip",            OPT_KEY,        NULL },
+               { "localport",          OPT_KEY,        NULL },
+               { "remoteip",           OPT_KEY,        NULL },
+               { "remoteport",         OPT_KEY,        NULL },
+               { "name",               OPT_KEYVAL,     NULL },
+               { "media",              OPT_KEYVAL,     NULL },
+               { NULL }
+       };
+       struct tipc_sup_media sup_media[] = {
+               { "udp",        "name",         cmd_bearer_get_udp_help},
+               { NULL, },
+       };
+
+       /* Rewind optind to include media in the option list */
+       cmdl->optind--;
+       if (parse_opts(opts, cmdl) < 0)
+               return -EINVAL;
+
+       if (!(opt = get_opt(opts, "media"))) {
+               fprintf(stderr, "error, missing media value\n");
+               return -EINVAL;
+       }
+       media = opt->val;
+
+       if (help_flag) {
+               cmd_bearer_get_udp_help(cmdl, media);
+               return -EINVAL;
+       }
+       if (strcmp(media, "udp") != 0) {
+               fprintf(stderr, "error, no \"%s\" media specific options\n", media);
+               return -EINVAL;
+       }
+       if (!(opt = get_opt(opts, "name"))) {
+               fprintf(stderr, "error, missing media name\n");
+               return -EINVAL;
+       }
+
+       if (!(nlh = msg_init(buf, TIPC_NL_BEARER_GET))) {
+               fprintf(stderr, "error, message initialisation failed\n");
+               return -1;
+       }
+
+       attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
+       err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
+       if (err)
+               return err;
+       mnl_attr_nest_end(nlh, attrs);
+       cb_data.nlh = nlh;
+
+       if (has_opt(opts, "localip")) {
+               cb_data.attr = TIPC_NLA_UDP_LOCAL;
+               cb_data.prop = UDP_PROP_IP;
+               return msg_doit(nlh, bearer_get_udp_cb, &cb_data);
+       } else if (has_opt(opts, "localport")) {
+               cb_data.attr = TIPC_NLA_UDP_LOCAL;
+               cb_data.prop = UDP_PROP_PORT;
+               return msg_doit(nlh, bearer_get_udp_cb, &cb_data);
+       } else if (has_opt(opts, "remoteip")) {
+               cb_data.attr = TIPC_NLA_UDP_REMOTE;
+               cb_data.prop = UDP_PROP_IP;
+               return msg_doit(nlh, bearer_get_udp_cb, &cb_data);
+       } else if (has_opt(opts, "remoteport")) {
+               cb_data.attr = TIPC_NLA_UDP_REMOTE;
+               cb_data.prop = UDP_PROP_PORT;
+               return msg_doit(nlh, bearer_get_udp_cb, &cb_data);
+       }
+       fprintf(stderr, "error, missing UDP option\n");
+       return -EINVAL;
+}
+
 static int cmd_bearer_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
                               struct cmdl *cmdl, void *data)
 {
@@ -630,9 +838,9 @@ static int cmd_bearer_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
        char buf[MNL_SOCKET_BUFFER_SIZE];
        struct nlattr *attrs;
        struct opt opts[] = {
-               { "device",             NULL },
-               { "media",              NULL },
-               { "name",               NULL },
+               { "device",             OPT_KEYVAL,     NULL },
+               { "media",              OPT_KEYVAL,     NULL },
+               { "name",               OPT_KEYVAL,     NULL },
                { NULL }
        };
        struct tipc_sup_media sup_media[] = {
@@ -642,6 +850,11 @@ static int cmd_bearer_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
                { NULL, },
        };
 
+       if (help_flag) {
+               (cmd->help)(cmdl);
+               return -EINVAL;
+       }
+
        if (strcmp(cmd->cmd, "priority") == 0)
                prop = TIPC_NLA_PROP_PRIO;
        else if ((strcmp(cmd->cmd, "tolerance") == 0))
@@ -675,6 +888,7 @@ static int cmd_bearer_get(struct nlmsghdr *nlh, const struct cmd *cmd,
                { "priority",   cmd_bearer_get_prop,    cmd_bearer_get_help },
                { "tolerance",  cmd_bearer_get_prop,    cmd_bearer_get_help },
                { "window",     cmd_bearer_get_prop,    cmd_bearer_get_help },
+               { "media",      cmd_bearer_get_media,   cmd_bearer_get_help },
                { NULL }
        };
 
index b816f7d45f3f37437a8a5da58256f276c8deaee4..4a2f4fd92f4816f52465ded2e65f642b3f36e8a7 100644 (file)
@@ -62,6 +62,11 @@ struct opt *get_opt(struct opt *opts, char *key)
        return NULL;
 }
 
+bool has_opt(struct opt *opts, char *key)
+{
+       return get_opt(opts, key) ? true : false;
+}
+
 char *shift_cmdl(struct cmdl *cmdl)
 {
        int next;
@@ -80,7 +85,7 @@ int parse_opts(struct opt *opts, struct cmdl *cmdl)
        int i;
        int cnt = 0;
 
-       for (i = cmdl->optind; i < cmdl->argc; i += 2) {
+       for (i = cmdl->optind; i < cmdl->argc; i++) {
                struct opt *o;
 
                o = find_opt(opts, cmdl->argv[i]);
@@ -89,9 +94,13 @@ int parse_opts(struct opt *opts, struct cmdl *cmdl)
                                        cmdl->argv[i]);
                        return -EINVAL;
                }
+               if (o->flag & OPT_KEYVAL) {
+                       cmdl->optind++;
+                       i++;
+               }
                cnt++;
-               o->val = cmdl->argv[i + 1];
-               cmdl->optind += 2;
+               o->val = cmdl->argv[i];
+               cmdl->optind++;
        }
 
        return cnt;
index d4795cfe0f42a8ccdc2ea6e3b4171611442b0645..d37239f8569020e2b09cdb65b53c402b82a9a121 100644 (file)
 
 extern int help_flag;
 
+enum {
+       OPT_KEY                 = (1 << 0),
+       OPT_KEYVAL              = (1 << 1),
+};
+
 struct cmdl {
        int optind;
        int argc;
@@ -37,10 +42,12 @@ struct cmd {
 
 struct opt {
        const char *key;
+       uint16_t flag;
        char *val;
 };
 
 struct opt *get_opt(struct opt *opts, char *key);
+bool has_opt(struct opt *opts, char *key);
 int parse_opts(struct opt *opts, struct cmdl *cmdl);
 char *shift_cmdl(struct cmdl *cmdl);
 
index 89fb4ff4e7f9a7737dcc9ef1bb33b74405fa3445..061b1c534389289706081cd7bf5bf2ec61024e60 100644 (file)
@@ -98,7 +98,7 @@ static int cmd_link_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
        char buf[MNL_SOCKET_BUFFER_SIZE];
        struct opt *opt;
        struct opt opts[] = {
-               { "link",               NULL },
+               { "link",               OPT_KEYVAL,     NULL },
                { NULL }
        };
 
@@ -169,7 +169,7 @@ static int cmd_link_stat_reset(struct nlmsghdr *nlh, const struct cmd *cmd,
        struct opt *opt;
        struct nlattr *nest;
        struct opt opts[] = {
-               { "link",               NULL },
+               { "link",               OPT_KEYVAL,     NULL },
                { NULL }
        };
 
@@ -365,7 +365,7 @@ static int cmd_link_stat_show(struct nlmsghdr *nlh, const struct cmd *cmd,
        char buf[MNL_SOCKET_BUFFER_SIZE];
        struct opt *opt;
        struct opt opts[] = {
-               { "link",               NULL },
+               { "link",               OPT_KEYVAL,     NULL },
                { NULL }
        };
 
@@ -429,7 +429,7 @@ static int cmd_link_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
        struct nlattr *attrs;
        struct opt *opt;
        struct opt opts[] = {
-               { "link",       NULL },
+               { "link",               OPT_KEYVAL,     NULL },
                { NULL }
        };
 
index a902ab78bc44f2fe978521b7ea4cc4d701ba7114..6e10c7e5d8e664313c3a5507cfa763ef16d764e7 100644 (file)
@@ -93,7 +93,7 @@ static int cmd_media_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
        struct nlattr *nest;
        struct opt *opt;
        struct opt opts[] = {
-               { "media",              NULL },
+               { "media",              OPT_KEYVAL,     NULL },
                { NULL }
        };
 
@@ -173,7 +173,7 @@ static int cmd_media_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
        struct nlattr *attrs;
        struct opt *opt;
        struct opt opts[] = {
-               { "media",              NULL },
+               { "media",              OPT_KEYVAL,     NULL },
                { NULL }
        };