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.a...@ericsson.com>
---
 include/linux/tipc_netlink.h |   2 +
 man/man8/tipc-bearer.8       |   5 +-
 tipc/bearer.c                | 264 +++++++++++++++++++++++++++++++++++++++----
 tipc/cmdl.c                  |  15 ++-
 tipc/cmdl.h                  |   7 ++
 tipc/link.c                  |   8 +-
 tipc/media.c                 |   4 +-
 7 files changed, 269 insertions(+), 36 deletions(-)

diff --git a/include/linux/tipc_netlink.h b/include/linux/tipc_netlink.h
index b15664c..f9edd20 100644
--- a/include/linux/tipc_netlink.h
+++ b/include/linux/tipc_netlink.h
@@ -61,6 +61,7 @@ enum {
        TIPC_NL_MON_PEER_GET,
        TIPC_NL_PEER_REMOVE,
        TIPC_NL_BEARER_ADD,
+       TIPC_NL_UDP_GET_REMOTEIP,
 
        __TIPC_NL_CMD_MAX,
        TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1
@@ -100,6 +101,7 @@ enum {
        TIPC_NLA_UDP_UNSPEC,
        TIPC_NLA_UDP_LOCAL,             /* sockaddr_storage */
        TIPC_NLA_UDP_REMOTE,            /* sockaddr_storage */
+       TIPC_NLA_UDP_MULTI_REMOTEIP,    /* flag */
 
        __TIPC_NLA_UDP_MAX,
        TIPC_NLA_UDP_MAX = __TIPC_NLA_UDP_MAX - 1
diff --git a/man/man8/tipc-bearer.8 b/man/man8/tipc-bearer.8
index 32be64d..d95b1e1 100644
--- a/man/man8/tipc-bearer.8
+++ b/man/man8/tipc-bearer.8
@@ -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
diff --git a/tipc/bearer.c b/tipc/bearer.c
index d43b263..8729dad 100644
--- a/tipc/bearer.c
+++ b/tipc/bearer.c
@@ -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>
@@ -26,6 +27,15 @@
 #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)
@@ -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 }
        };
 
diff --git a/tipc/cmdl.c b/tipc/cmdl.c
index b816f7d..4a2f4fd 100644
--- a/tipc/cmdl.c
+++ b/tipc/cmdl.c
@@ -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;
diff --git a/tipc/cmdl.h b/tipc/cmdl.h
index d4795cf..d37239f 100644
--- a/tipc/cmdl.h
+++ b/tipc/cmdl.h
@@ -16,6 +16,11 @@
 
 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);
 
diff --git a/tipc/link.c b/tipc/link.c
index 89fb4ff..061b1c5 100644
--- a/tipc/link.c
+++ b/tipc/link.c
@@ -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 }
        };
 
diff --git a/tipc/media.c b/tipc/media.c
index a902ab7..6e10c7e 100644
--- a/tipc/media.c
+++ b/tipc/media.c
@@ -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 }
        };
 
-- 
2.1.4


------------------------------------------------------------------------------
_______________________________________________
tipc-discussion mailing list
tipc-discussion@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tipc-discussion

Reply via email to