mirror of
https://git.kernel.org/pub/scm/network/iproute2/iproute2.git
synced 2024-11-27 20:04:19 +08:00
ed81deabf2
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>
968 lines
24 KiB
C
968 lines
24 KiB
C
/*
|
|
* bearer.c TIPC bearer functionality.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the License, or (at your option) any later version.
|
|
*
|
|
* Authors: Richard Alpe <richard.alpe@ericsson.com>
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <netdb.h>
|
|
#include <errno.h>
|
|
#include <arpa/inet.h>
|
|
|
|
#include <linux/tipc_netlink.h>
|
|
#include <linux/tipc.h>
|
|
#include <linux/genetlink.h>
|
|
|
|
#include <libmnl/libmnl.h>
|
|
#include <sys/socket.h>
|
|
|
|
#include "cmdl.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,
|
|
"OPTIONS\n"
|
|
" priority - Bearer link priority\n"
|
|
" tolerance - Bearer link tolerance\n"
|
|
" window - Bearer link window\n");
|
|
}
|
|
|
|
static void _print_bearer_media(void)
|
|
{
|
|
fprintf(stderr,
|
|
"\nMEDIA\n"
|
|
" udp - User Datagram Protocol\n"
|
|
" ib - Infiniband\n"
|
|
" eth - Ethernet\n");
|
|
}
|
|
|
|
static void cmd_bearer_enable_l2_help(struct cmdl *cmdl, char *media)
|
|
{
|
|
fprintf(stderr,
|
|
"Usage: %s bearer enable media %s device DEVICE [OPTIONS]\n"
|
|
"\nOPTIONS\n"
|
|
" domain DOMAIN - Discovery domain\n"
|
|
" priority PRIORITY - Bearer priority\n",
|
|
cmdl->argv[0], media);
|
|
}
|
|
|
|
static void cmd_bearer_enable_udp_help(struct cmdl *cmdl, char *media)
|
|
{
|
|
fprintf(stderr,
|
|
"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\n");
|
|
fprintf(stderr,
|
|
"UDP OPTIONS\n"
|
|
" localport PORT - Local UDP port (default 6118)\n"
|
|
" remoteip IP - Remote IP address\n"
|
|
" remoteport PORT - Remote UDP port (default 6118)\n");
|
|
}
|
|
|
|
static int get_netid_cb(const struct nlmsghdr *nlh, void *data)
|
|
{
|
|
struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
|
|
struct nlattr *info[TIPC_NLA_MAX + 1] = {};
|
|
struct nlattr *attrs[TIPC_NLA_NET_MAX + 1] = {};
|
|
int *netid = (int*)data;
|
|
|
|
mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
|
|
if (!info[TIPC_NLA_NET])
|
|
return MNL_CB_ERROR;
|
|
mnl_attr_parse_nested(info[TIPC_NLA_NET], parse_attrs, attrs);
|
|
if (!attrs[TIPC_NLA_NET_ID])
|
|
return MNL_CB_ERROR;
|
|
*netid = mnl_attr_get_u32(attrs[TIPC_NLA_NET_ID]);
|
|
|
|
return MNL_CB_OK;
|
|
}
|
|
|
|
static int generate_multicast(short af, char *buf, int bufsize)
|
|
{
|
|
int netid;
|
|
char mnl_msg[MNL_SOCKET_BUFFER_SIZE];
|
|
struct nlmsghdr *nlh;
|
|
|
|
if (!(nlh = msg_init(mnl_msg, TIPC_NL_NET_GET))) {
|
|
fprintf(stderr, "error, message initialization failed\n");
|
|
return -1;
|
|
}
|
|
if (msg_dumpit(nlh, get_netid_cb, &netid)) {
|
|
fprintf(stderr, "error, failed to fetch TIPC network id from kernel\n");
|
|
return -EINVAL;
|
|
}
|
|
if (af == AF_INET)
|
|
snprintf(buf, bufsize, "228.0.%u.%u", (netid>>8) & 0xFF, netid & 0xFF);
|
|
else
|
|
snprintf(buf, bufsize, "ff02::%u", netid);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nl_add_udp_enable_opts(struct nlmsghdr *nlh, struct opt *opts,
|
|
struct cmdl *cmdl)
|
|
{
|
|
int err;
|
|
struct opt *opt;
|
|
struct nlattr *nest;
|
|
char buf[INET6_ADDRSTRLEN];
|
|
char *locport = "6118";
|
|
char *remport = "6118";
|
|
char *locip = NULL;
|
|
char *remip = NULL;
|
|
struct addrinfo *loc = NULL;
|
|
struct addrinfo *rem = NULL;
|
|
struct addrinfo hints = {
|
|
.ai_family = AF_UNSPEC,
|
|
.ai_socktype = SOCK_DGRAM
|
|
};
|
|
|
|
if (!(opt = get_opt(opts, "localip"))) {
|
|
fprintf(stderr, "error, udp bearer localip missing\n");
|
|
cmd_bearer_enable_udp_help(cmdl, "udp");
|
|
return -EINVAL;
|
|
}
|
|
locip = opt->val;
|
|
|
|
if ((opt = get_opt(opts, "remoteip")))
|
|
remip = opt->val;
|
|
|
|
if ((opt = get_opt(opts, "localport")))
|
|
locport = opt->val;
|
|
|
|
if ((opt = get_opt(opts, "remoteport")))
|
|
remport = opt->val;
|
|
|
|
if ((err = getaddrinfo(locip, locport, &hints, &loc))) {
|
|
fprintf(stderr, "UDP local address error: %s\n",
|
|
gai_strerror(err));
|
|
return err;
|
|
}
|
|
|
|
if (!remip) {
|
|
if (generate_multicast(loc->ai_family, buf, sizeof(buf))) {
|
|
fprintf(stderr, "Failed to generate multicast address\n");
|
|
return -EINVAL;
|
|
}
|
|
remip = buf;
|
|
}
|
|
|
|
if ((err = getaddrinfo(remip, remport, &hints, &rem))) {
|
|
fprintf(stderr, "UDP remote address error: %s\n",
|
|
gai_strerror(err));
|
|
freeaddrinfo(loc);
|
|
return err;
|
|
}
|
|
|
|
if (rem->ai_family != loc->ai_family) {
|
|
fprintf(stderr, "UDP local and remote AF mismatch\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_UDP_OPTS);
|
|
mnl_attr_put(nlh, TIPC_NLA_UDP_LOCAL, loc->ai_addrlen, loc->ai_addr);
|
|
mnl_attr_put(nlh, TIPC_NLA_UDP_REMOTE, rem->ai_addrlen, rem->ai_addr);
|
|
mnl_attr_nest_end(nlh, nest);
|
|
|
|
freeaddrinfo(rem);
|
|
freeaddrinfo(loc);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nl_add_bearer_name(struct nlmsghdr *nlh, const struct cmd *cmd,
|
|
struct cmdl *cmdl, struct opt *opts,
|
|
struct tipc_sup_media sup_media[])
|
|
{
|
|
char id[TIPC_MAX_BEARER_NAME];
|
|
char *media;
|
|
char *identifier;
|
|
struct opt *opt;
|
|
struct tipc_sup_media *entry;
|
|
|
|
if (!(opt = get_opt(opts, "media"))) {
|
|
if (help_flag)
|
|
(cmd->help)(cmdl);
|
|
else
|
|
fprintf(stderr, "error, missing bearer media\n");
|
|
return -EINVAL;
|
|
}
|
|
media = opt->val;
|
|
|
|
for (entry = sup_media; entry->media; entry++) {
|
|
if (strcmp(entry->media, media))
|
|
continue;
|
|
|
|
if (!(opt = get_opt(opts, entry->identifier))) {
|
|
if (help_flag)
|
|
(entry->help)(cmdl, media);
|
|
else
|
|
fprintf(stderr, "error, missing bearer %s\n",
|
|
entry->identifier);
|
|
return -EINVAL;
|
|
}
|
|
|
|
identifier = opt->val;
|
|
snprintf(id, sizeof(id), "%s:%s", media, identifier);
|
|
mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, id);
|
|
|
|
return 0;
|
|
}
|
|
|
|
fprintf(stderr, "error, invalid media type %s\n", media);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static void cmd_bearer_add_udp_help(struct cmdl *cmdl, char *media)
|
|
{
|
|
fprintf(stderr, "Usage: %s bearer add media %s name NAME remoteip REMOTEIP\n\n",
|
|
cmdl->argv[0], media);
|
|
}
|
|
|
|
static void cmd_bearer_add_help(struct cmdl *cmdl)
|
|
{
|
|
fprintf(stderr, "Usage: %s bearer add media udp name NAME remoteip REMOTEIP\n",
|
|
cmdl->argv[0]);
|
|
}
|
|
|
|
static int udp_bearer_add(struct nlmsghdr *nlh, struct opt *opts,
|
|
struct cmdl *cmdl)
|
|
{
|
|
int err;
|
|
struct opt *opt;
|
|
struct nlattr *opts_nest;
|
|
char *remport = "6118";
|
|
|
|
opts_nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_UDP_OPTS);
|
|
|
|
if ((opt = get_opt(opts, "remoteport")))
|
|
remport = opt->val;
|
|
|
|
if ((opt = get_opt(opts, "remoteip"))) {
|
|
char *ip = opt->val;
|
|
struct addrinfo *addr = NULL;
|
|
struct addrinfo hints = {
|
|
.ai_family = AF_UNSPEC,
|
|
.ai_socktype = SOCK_DGRAM
|
|
};
|
|
|
|
if ((err = getaddrinfo(ip, remport, &hints, &addr))) {
|
|
fprintf(stderr, "UDP address error: %s\n",
|
|
gai_strerror(err));
|
|
freeaddrinfo(addr);
|
|
return err;
|
|
}
|
|
|
|
mnl_attr_put(nlh, TIPC_NLA_UDP_REMOTE, addr->ai_addrlen,
|
|
addr->ai_addr);
|
|
freeaddrinfo(addr);
|
|
} else {
|
|
fprintf(stderr, "error, missing remoteip\n");
|
|
return -EINVAL;
|
|
}
|
|
mnl_attr_nest_end(nlh, opts_nest);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_bearer_add_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 nlattr *attrs;
|
|
struct opt opts[] = {
|
|
{ "remoteip", OPT_KEYVAL, NULL },
|
|
{ "remoteport", OPT_KEYVAL, NULL },
|
|
{ "name", OPT_KEYVAL, NULL },
|
|
{ "media", OPT_KEYVAL, NULL },
|
|
{ NULL }
|
|
};
|
|
struct tipc_sup_media sup_media[] = {
|
|
{ "udp", "name", cmd_bearer_add_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 (strcmp(media, "udp") != 0) {
|
|
fprintf(stderr, "error, no \"%s\" media specific options available\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_ADD))) {
|
|
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;
|
|
|
|
err = udp_bearer_add(nlh, opts, cmdl);
|
|
if (err)
|
|
return err;
|
|
|
|
mnl_attr_nest_end(nlh, attrs);
|
|
|
|
return msg_doit(nlh, NULL, NULL);
|
|
}
|
|
|
|
static int cmd_bearer_add(struct nlmsghdr *nlh, const struct cmd *cmd,
|
|
struct cmdl *cmdl, void *data)
|
|
{
|
|
const struct cmd cmds[] = {
|
|
{ "media", cmd_bearer_add_media, cmd_bearer_add_help },
|
|
{ NULL }
|
|
};
|
|
|
|
return run_cmd(nlh, cmd, cmds, cmdl, NULL);
|
|
}
|
|
|
|
static void cmd_bearer_enable_help(struct cmdl *cmdl)
|
|
{
|
|
fprintf(stderr,
|
|
"Usage: %s bearer enable [OPTIONS] media MEDIA ARGS...\n\n"
|
|
"OPTIONS\n"
|
|
" domain DOMAIN - Discovery domain\n"
|
|
" priority PRIORITY - Bearer priority\n",
|
|
cmdl->argv[0]);
|
|
_print_bearer_media();
|
|
}
|
|
|
|
static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd,
|
|
struct cmdl *cmdl, void *data)
|
|
{
|
|
int err;
|
|
struct opt *opt;
|
|
struct nlattr *nest;
|
|
char buf[MNL_SOCKET_BUFFER_SIZE];
|
|
struct opt opts[] = {
|
|
{ "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[] = {
|
|
{ "udp", "name", cmd_bearer_enable_udp_help},
|
|
{ "eth", "device", cmd_bearer_enable_l2_help },
|
|
{ "ib", "device", cmd_bearer_enable_l2_help },
|
|
{ NULL, },
|
|
};
|
|
|
|
if (parse_opts(opts, cmdl) < 0) {
|
|
if (help_flag)
|
|
(cmd->help)(cmdl);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!(nlh = msg_init(buf, TIPC_NL_BEARER_ENABLE))) {
|
|
fprintf(stderr, "error: message initialisation failed\n");
|
|
return -1;
|
|
}
|
|
nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
|
|
|
|
if ((opt = get_opt(opts, "domain")))
|
|
mnl_attr_put_u32(nlh, TIPC_NLA_BEARER_DOMAIN, atoi(opt->val));
|
|
|
|
if ((opt = get_opt(opts, "priority"))) {
|
|
struct nlattr *props;
|
|
|
|
props = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_PROP);
|
|
mnl_attr_put_u32(nlh, TIPC_NLA_PROP_PRIO, atoi(opt->val));
|
|
mnl_attr_nest_end(nlh, props);
|
|
}
|
|
|
|
err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
|
|
if (err)
|
|
return err;
|
|
|
|
opt = get_opt(opts, "media");
|
|
if (strcmp(opt->val, "udp") == 0) {
|
|
err = nl_add_udp_enable_opts(nlh, opts, cmdl);
|
|
if (err)
|
|
return err;
|
|
}
|
|
mnl_attr_nest_end(nlh, nest);
|
|
|
|
return msg_doit(nlh, NULL, NULL);
|
|
}
|
|
|
|
static void cmd_bearer_disable_l2_help(struct cmdl *cmdl, char *media)
|
|
{
|
|
fprintf(stderr, "Usage: %s bearer disable media %s device DEVICE\n",
|
|
cmdl->argv[0], media);
|
|
}
|
|
|
|
static void cmd_bearer_disable_udp_help(struct cmdl *cmdl, char *media)
|
|
{
|
|
fprintf(stderr, "Usage: %s bearer disable media %s name NAME\n",
|
|
cmdl->argv[0], media);
|
|
}
|
|
|
|
static void cmd_bearer_disable_help(struct cmdl *cmdl)
|
|
{
|
|
fprintf(stderr, "Usage: %s bearer disable media MEDIA ARGS...\n",
|
|
cmdl->argv[0]);
|
|
_print_bearer_media();
|
|
}
|
|
|
|
static int cmd_bearer_disable(struct nlmsghdr *nlh, const struct cmd *cmd,
|
|
struct cmdl *cmdl, void *data)
|
|
{
|
|
int err;
|
|
char buf[MNL_SOCKET_BUFFER_SIZE];
|
|
struct nlattr *nest;
|
|
struct opt opts[] = {
|
|
{ "device", OPT_KEYVAL, NULL },
|
|
{ "name", OPT_KEYVAL, NULL },
|
|
{ "media", OPT_KEYVAL, NULL },
|
|
{ NULL }
|
|
};
|
|
struct tipc_sup_media sup_media[] = {
|
|
{ "udp", "name", cmd_bearer_disable_udp_help},
|
|
{ "eth", "device", cmd_bearer_disable_l2_help },
|
|
{ "ib", "device", cmd_bearer_disable_l2_help },
|
|
{ NULL, },
|
|
};
|
|
|
|
if (parse_opts(opts, cmdl) < 0) {
|
|
if (help_flag)
|
|
(cmd->help)(cmdl);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!(nlh = msg_init(buf, TIPC_NL_BEARER_DISABLE))) {
|
|
fprintf(stderr, "error, message initialisation failed\n");
|
|
return -1;
|
|
}
|
|
|
|
nest = 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, nest);
|
|
|
|
return msg_doit(nlh, NULL, NULL);
|
|
|
|
}
|
|
|
|
static void cmd_bearer_set_help(struct cmdl *cmdl)
|
|
{
|
|
fprintf(stderr, "Usage: %s bearer set OPTION media MEDIA ARGS...\n",
|
|
cmdl->argv[0]);
|
|
_print_bearer_opts();
|
|
_print_bearer_media();
|
|
}
|
|
|
|
static void cmd_bearer_set_udp_help(struct cmdl *cmdl, char *media)
|
|
{
|
|
fprintf(stderr, "Usage: %s bearer set OPTION media %s name NAME\n\n",
|
|
cmdl->argv[0], media);
|
|
_print_bearer_opts();
|
|
}
|
|
|
|
static void cmd_bearer_set_l2_help(struct cmdl *cmdl, char *media)
|
|
{
|
|
fprintf(stderr,
|
|
"Usage: %s bearer set [OPTION]... media %s device DEVICE\n",
|
|
cmdl->argv[0], media);
|
|
_print_bearer_opts();
|
|
}
|
|
|
|
static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
|
|
struct cmdl *cmdl, void *data)
|
|
{
|
|
int err;
|
|
int val;
|
|
int prop;
|
|
char buf[MNL_SOCKET_BUFFER_SIZE];
|
|
struct nlattr *props;
|
|
struct nlattr *attrs;
|
|
struct opt opts[] = {
|
|
{ "device", OPT_KEYVAL, NULL },
|
|
{ "media", OPT_KEYVAL, NULL },
|
|
{ "name", OPT_KEYVAL, NULL },
|
|
{ NULL }
|
|
};
|
|
struct tipc_sup_media sup_media[] = {
|
|
{ "udp", "name", cmd_bearer_set_udp_help},
|
|
{ "eth", "device", cmd_bearer_set_l2_help },
|
|
{ "ib", "device", cmd_bearer_set_l2_help },
|
|
{ NULL, },
|
|
};
|
|
|
|
if (strcmp(cmd->cmd, "priority") == 0)
|
|
prop = TIPC_NLA_PROP_PRIO;
|
|
else if ((strcmp(cmd->cmd, "tolerance") == 0))
|
|
prop = TIPC_NLA_PROP_TOL;
|
|
else if ((strcmp(cmd->cmd, "window") == 0))
|
|
prop = TIPC_NLA_PROP_WIN;
|
|
else
|
|
return -EINVAL;
|
|
|
|
if (cmdl->optind >= cmdl->argc) {
|
|
fprintf(stderr, "error, missing value\n");
|
|
return -EINVAL;
|
|
}
|
|
val = atoi(shift_cmdl(cmdl));
|
|
|
|
if (parse_opts(opts, cmdl) < 0)
|
|
return -EINVAL;
|
|
|
|
if (!(nlh = msg_init(buf, TIPC_NL_BEARER_SET))) {
|
|
fprintf(stderr, "error, message initialisation failed\n");
|
|
return -1;
|
|
}
|
|
attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
|
|
|
|
props = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_PROP);
|
|
mnl_attr_put_u32(nlh, prop, val);
|
|
mnl_attr_nest_end(nlh, props);
|
|
|
|
err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
|
|
if (err)
|
|
return err;
|
|
|
|
mnl_attr_nest_end(nlh, attrs);
|
|
|
|
return msg_doit(nlh, NULL, NULL);
|
|
}
|
|
|
|
static int cmd_bearer_set(struct nlmsghdr *nlh, const struct cmd *cmd,
|
|
struct cmdl *cmdl, void *data)
|
|
{
|
|
const struct cmd cmds[] = {
|
|
{ "priority", cmd_bearer_set_prop, cmd_bearer_set_help },
|
|
{ "tolerance", cmd_bearer_set_prop, cmd_bearer_set_help },
|
|
{ "window", cmd_bearer_set_prop, cmd_bearer_set_help },
|
|
{ NULL }
|
|
};
|
|
|
|
return run_cmd(nlh, cmd, cmds, cmdl, NULL);
|
|
}
|
|
|
|
static void cmd_bearer_get_help(struct cmdl *cmdl)
|
|
{
|
|
fprintf(stderr, "Usage: %s bearer get [OPTION] media MEDIA ARGS...\n",
|
|
cmdl->argv[0]);
|
|
_print_bearer_opts();
|
|
_print_bearer_media();
|
|
}
|
|
|
|
static void cmd_bearer_get_udp_help(struct cmdl *cmdl, char *media)
|
|
{
|
|
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();
|
|
}
|
|
|
|
static void cmd_bearer_get_l2_help(struct cmdl *cmdl, char *media)
|
|
{
|
|
fprintf(stderr,
|
|
"Usage: %s bearer get OPTION media %s device DEVICE\n",
|
|
cmdl->argv[0], 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;
|
|
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 *props[TIPC_NLA_PROP_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_PROP])
|
|
return MNL_CB_ERROR;
|
|
|
|
mnl_attr_parse_nested(attrs[TIPC_NLA_BEARER_PROP], parse_attrs, props);
|
|
if (!props[*prop])
|
|
return MNL_CB_ERROR;
|
|
|
|
printf("%u\n", mnl_attr_get_u32(props[*prop]));
|
|
|
|
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)
|
|
{
|
|
int err;
|
|
int prop;
|
|
char buf[MNL_SOCKET_BUFFER_SIZE];
|
|
struct nlattr *attrs;
|
|
struct opt opts[] = {
|
|
{ "device", OPT_KEYVAL, NULL },
|
|
{ "media", OPT_KEYVAL, NULL },
|
|
{ "name", OPT_KEYVAL, NULL },
|
|
{ NULL }
|
|
};
|
|
struct tipc_sup_media sup_media[] = {
|
|
{ "udp", "name", cmd_bearer_get_udp_help},
|
|
{ "eth", "device", cmd_bearer_get_l2_help },
|
|
{ "ib", "device", cmd_bearer_get_l2_help },
|
|
{ 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))
|
|
prop = TIPC_NLA_PROP_TOL;
|
|
else if ((strcmp(cmd->cmd, "window") == 0))
|
|
prop = TIPC_NLA_PROP_WIN;
|
|
else
|
|
return -EINVAL;
|
|
|
|
if (parse_opts(opts, cmdl) < 0)
|
|
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);
|
|
|
|
return msg_doit(nlh, bearer_get_cb, &prop);
|
|
}
|
|
|
|
static int cmd_bearer_get(struct nlmsghdr *nlh, const struct cmd *cmd,
|
|
struct cmdl *cmdl, void *data)
|
|
{
|
|
const struct cmd cmds[] = {
|
|
{ "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 }
|
|
};
|
|
|
|
return run_cmd(nlh, cmd, cmds, cmdl, NULL);
|
|
}
|
|
|
|
static int bearer_list_cb(const struct nlmsghdr *nlh, void *data)
|
|
{
|
|
struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
|
|
struct nlattr *info[TIPC_NLA_MAX + 1] = {};
|
|
struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1] = {};
|
|
|
|
mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
|
|
if (!info[TIPC_NLA_BEARER]) {
|
|
fprintf(stderr, "No bearer in netlink response\n");
|
|
return MNL_CB_ERROR;
|
|
}
|
|
|
|
mnl_attr_parse_nested(info[TIPC_NLA_BEARER], parse_attrs, attrs);
|
|
if (!attrs[TIPC_NLA_BEARER_NAME]) {
|
|
fprintf(stderr, "Bearer name missing in netlink response\n");
|
|
return MNL_CB_ERROR;
|
|
}
|
|
|
|
printf("%s\n", mnl_attr_get_str(attrs[TIPC_NLA_BEARER_NAME]));
|
|
|
|
return MNL_CB_OK;
|
|
}
|
|
|
|
static int cmd_bearer_list(struct nlmsghdr *nlh, const struct cmd *cmd,
|
|
struct cmdl *cmdl, void *data)
|
|
{
|
|
char buf[MNL_SOCKET_BUFFER_SIZE];
|
|
|
|
if (help_flag) {
|
|
fprintf(stderr, "Usage: %s bearer list\n", cmdl->argv[0]);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!(nlh = msg_init(buf, TIPC_NL_BEARER_GET))) {
|
|
fprintf(stderr, "error, message initialisation failed\n");
|
|
return -1;
|
|
}
|
|
|
|
return msg_dumpit(nlh, bearer_list_cb, NULL);
|
|
}
|
|
|
|
void cmd_bearer_help(struct cmdl *cmdl)
|
|
{
|
|
fprintf(stderr,
|
|
"Usage: %s bearer COMMAND [ARGS] ...\n"
|
|
"\n"
|
|
"COMMANDS\n"
|
|
" add - Add data to existing bearer\n"
|
|
" enable - Enable a bearer\n"
|
|
" disable - Disable a bearer\n"
|
|
" set - Set various bearer properties\n"
|
|
" get - Get various bearer properties\n"
|
|
" list - List bearers\n", cmdl->argv[0]);
|
|
}
|
|
|
|
int cmd_bearer(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl,
|
|
void *data)
|
|
{
|
|
const struct cmd cmds[] = {
|
|
{ "add", cmd_bearer_add, cmd_bearer_add_help },
|
|
{ "disable", cmd_bearer_disable, cmd_bearer_disable_help },
|
|
{ "enable", cmd_bearer_enable, cmd_bearer_enable_help },
|
|
{ "get", cmd_bearer_get, cmd_bearer_get_help },
|
|
{ "list", cmd_bearer_list, NULL },
|
|
{ "set", cmd_bearer_set, cmd_bearer_set_help },
|
|
{ NULL }
|
|
};
|
|
|
|
return run_cmd(nlh, cmd, cmds, cmdl, NULL);
|
|
}
|