mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2025-10-17 09:18:38 +00:00
Merge branch 'master' into net-next
This commit is contained in:
commit
f9b004020a
2
Makefile
2
Makefile
@ -39,7 +39,7 @@ WFLAGS += -Wmissing-declarations -Wold-style-definition -Wformat=2
|
||||
CFLAGS := $(WFLAGS) $(CCOPTS) -I../include $(DEFINES) $(CFLAGS)
|
||||
YACCFLAGS = -d -t -v
|
||||
|
||||
SUBDIRS=lib ip tc bridge misc netem genl man
|
||||
SUBDIRS=lib ip tc bridge misc netem genl tipc man
|
||||
|
||||
LIBNETLINK=../lib/libnetlink.a ../lib/libutil.a
|
||||
LDLIBS += $(LIBNETLINK)
|
||||
|
253
include/linux/tipc_netlink.h
Normal file
253
include/linux/tipc_netlink.h
Normal file
@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Ericsson AB
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_TIPC_NETLINK_H_
|
||||
#define _LINUX_TIPC_NETLINK_H_
|
||||
|
||||
#define TIPC_GENL_V2_NAME "TIPCv2"
|
||||
#define TIPC_GENL_V2_VERSION 0x1
|
||||
|
||||
/* Netlink commands */
|
||||
enum {
|
||||
TIPC_NL_UNSPEC,
|
||||
TIPC_NL_LEGACY,
|
||||
TIPC_NL_BEARER_DISABLE,
|
||||
TIPC_NL_BEARER_ENABLE,
|
||||
TIPC_NL_BEARER_GET,
|
||||
TIPC_NL_BEARER_SET,
|
||||
TIPC_NL_SOCK_GET,
|
||||
TIPC_NL_PUBL_GET,
|
||||
TIPC_NL_LINK_GET,
|
||||
TIPC_NL_LINK_SET,
|
||||
TIPC_NL_LINK_RESET_STATS,
|
||||
TIPC_NL_MEDIA_GET,
|
||||
TIPC_NL_MEDIA_SET,
|
||||
TIPC_NL_NODE_GET,
|
||||
TIPC_NL_NET_GET,
|
||||
TIPC_NL_NET_SET,
|
||||
TIPC_NL_NAME_TABLE_GET,
|
||||
|
||||
__TIPC_NL_CMD_MAX,
|
||||
TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1
|
||||
};
|
||||
|
||||
/* Top level netlink attributes */
|
||||
enum {
|
||||
TIPC_NLA_UNSPEC,
|
||||
TIPC_NLA_BEARER, /* nest */
|
||||
TIPC_NLA_SOCK, /* nest */
|
||||
TIPC_NLA_PUBL, /* nest */
|
||||
TIPC_NLA_LINK, /* nest */
|
||||
TIPC_NLA_MEDIA, /* nest */
|
||||
TIPC_NLA_NODE, /* nest */
|
||||
TIPC_NLA_NET, /* nest */
|
||||
TIPC_NLA_NAME_TABLE, /* nest */
|
||||
|
||||
__TIPC_NLA_MAX,
|
||||
TIPC_NLA_MAX = __TIPC_NLA_MAX - 1
|
||||
};
|
||||
|
||||
/* Bearer info */
|
||||
enum {
|
||||
TIPC_NLA_BEARER_UNSPEC,
|
||||
TIPC_NLA_BEARER_NAME, /* string */
|
||||
TIPC_NLA_BEARER_PROP, /* nest */
|
||||
TIPC_NLA_BEARER_DOMAIN, /* u32 */
|
||||
TIPC_NLA_BEARER_UDP_OPTS, /* nest */
|
||||
|
||||
__TIPC_NLA_BEARER_MAX,
|
||||
TIPC_NLA_BEARER_MAX = __TIPC_NLA_BEARER_MAX - 1
|
||||
};
|
||||
|
||||
enum {
|
||||
TIPC_NLA_UDP_UNSPEC,
|
||||
TIPC_NLA_UDP_LOCAL, /* sockaddr_storage */
|
||||
TIPC_NLA_UDP_REMOTE, /* sockaddr_storage */
|
||||
|
||||
__TIPC_NLA_UDP_MAX,
|
||||
TIPC_NLA_UDP_MAX = __TIPC_NLA_UDP_MAX - 1
|
||||
};
|
||||
/* Socket info */
|
||||
enum {
|
||||
TIPC_NLA_SOCK_UNSPEC,
|
||||
TIPC_NLA_SOCK_ADDR, /* u32 */
|
||||
TIPC_NLA_SOCK_REF, /* u32 */
|
||||
TIPC_NLA_SOCK_CON, /* nest */
|
||||
TIPC_NLA_SOCK_HAS_PUBL, /* flag */
|
||||
|
||||
__TIPC_NLA_SOCK_MAX,
|
||||
TIPC_NLA_SOCK_MAX = __TIPC_NLA_SOCK_MAX - 1
|
||||
};
|
||||
|
||||
/* Link info */
|
||||
enum {
|
||||
TIPC_NLA_LINK_UNSPEC,
|
||||
TIPC_NLA_LINK_NAME, /* string */
|
||||
TIPC_NLA_LINK_DEST, /* u32 */
|
||||
TIPC_NLA_LINK_MTU, /* u32 */
|
||||
TIPC_NLA_LINK_BROADCAST, /* flag */
|
||||
TIPC_NLA_LINK_UP, /* flag */
|
||||
TIPC_NLA_LINK_ACTIVE, /* flag */
|
||||
TIPC_NLA_LINK_PROP, /* nest */
|
||||
TIPC_NLA_LINK_STATS, /* nest */
|
||||
TIPC_NLA_LINK_RX, /* u32 */
|
||||
TIPC_NLA_LINK_TX, /* u32 */
|
||||
|
||||
__TIPC_NLA_LINK_MAX,
|
||||
TIPC_NLA_LINK_MAX = __TIPC_NLA_LINK_MAX - 1
|
||||
};
|
||||
|
||||
/* Media info */
|
||||
enum {
|
||||
TIPC_NLA_MEDIA_UNSPEC,
|
||||
TIPC_NLA_MEDIA_NAME, /* string */
|
||||
TIPC_NLA_MEDIA_PROP, /* nest */
|
||||
|
||||
__TIPC_NLA_MEDIA_MAX,
|
||||
TIPC_NLA_MEDIA_MAX = __TIPC_NLA_MEDIA_MAX - 1
|
||||
};
|
||||
|
||||
/* Node info */
|
||||
enum {
|
||||
TIPC_NLA_NODE_UNSPEC,
|
||||
TIPC_NLA_NODE_ADDR, /* u32 */
|
||||
TIPC_NLA_NODE_UP, /* flag */
|
||||
|
||||
__TIPC_NLA_NODE_MAX,
|
||||
TIPC_NLA_NODE_MAX = __TIPC_NLA_NODE_MAX - 1
|
||||
};
|
||||
|
||||
/* Net info */
|
||||
enum {
|
||||
TIPC_NLA_NET_UNSPEC,
|
||||
TIPC_NLA_NET_ID, /* u32 */
|
||||
TIPC_NLA_NET_ADDR, /* u32 */
|
||||
|
||||
__TIPC_NLA_NET_MAX,
|
||||
TIPC_NLA_NET_MAX = __TIPC_NLA_NET_MAX - 1
|
||||
};
|
||||
|
||||
/* Name table info */
|
||||
enum {
|
||||
TIPC_NLA_NAME_TABLE_UNSPEC,
|
||||
TIPC_NLA_NAME_TABLE_PUBL, /* nest */
|
||||
|
||||
__TIPC_NLA_NAME_TABLE_MAX,
|
||||
TIPC_NLA_NAME_TABLE_MAX = __TIPC_NLA_NAME_TABLE_MAX - 1
|
||||
};
|
||||
|
||||
/* Publication info */
|
||||
enum {
|
||||
TIPC_NLA_PUBL_UNSPEC,
|
||||
|
||||
TIPC_NLA_PUBL_TYPE, /* u32 */
|
||||
TIPC_NLA_PUBL_LOWER, /* u32 */
|
||||
TIPC_NLA_PUBL_UPPER, /* u32 */
|
||||
TIPC_NLA_PUBL_SCOPE, /* u32 */
|
||||
TIPC_NLA_PUBL_NODE, /* u32 */
|
||||
TIPC_NLA_PUBL_REF, /* u32 */
|
||||
TIPC_NLA_PUBL_KEY, /* u32 */
|
||||
|
||||
__TIPC_NLA_PUBL_MAX,
|
||||
TIPC_NLA_PUBL_MAX = __TIPC_NLA_PUBL_MAX - 1
|
||||
};
|
||||
|
||||
/* Nest, connection info */
|
||||
enum {
|
||||
TIPC_NLA_CON_UNSPEC,
|
||||
|
||||
TIPC_NLA_CON_FLAG, /* flag */
|
||||
TIPC_NLA_CON_NODE, /* u32 */
|
||||
TIPC_NLA_CON_SOCK, /* u32 */
|
||||
TIPC_NLA_CON_TYPE, /* u32 */
|
||||
TIPC_NLA_CON_INST, /* u32 */
|
||||
|
||||
__TIPC_NLA_CON_MAX,
|
||||
TIPC_NLA_CON_MAX = __TIPC_NLA_CON_MAX - 1
|
||||
};
|
||||
|
||||
/* Nest, link propreties. Valid for link, media and bearer */
|
||||
enum {
|
||||
TIPC_NLA_PROP_UNSPEC,
|
||||
|
||||
TIPC_NLA_PROP_PRIO, /* u32 */
|
||||
TIPC_NLA_PROP_TOL, /* u32 */
|
||||
TIPC_NLA_PROP_WIN, /* u32 */
|
||||
|
||||
__TIPC_NLA_PROP_MAX,
|
||||
TIPC_NLA_PROP_MAX = __TIPC_NLA_PROP_MAX - 1
|
||||
};
|
||||
|
||||
/* Nest, statistics info */
|
||||
enum {
|
||||
TIPC_NLA_STATS_UNSPEC,
|
||||
|
||||
TIPC_NLA_STATS_RX_INFO, /* u32 */
|
||||
TIPC_NLA_STATS_RX_FRAGMENTS, /* u32 */
|
||||
TIPC_NLA_STATS_RX_FRAGMENTED, /* u32 */
|
||||
TIPC_NLA_STATS_RX_BUNDLES, /* u32 */
|
||||
TIPC_NLA_STATS_RX_BUNDLED, /* u32 */
|
||||
TIPC_NLA_STATS_TX_INFO, /* u32 */
|
||||
TIPC_NLA_STATS_TX_FRAGMENTS, /* u32 */
|
||||
TIPC_NLA_STATS_TX_FRAGMENTED, /* u32 */
|
||||
TIPC_NLA_STATS_TX_BUNDLES, /* u32 */
|
||||
TIPC_NLA_STATS_TX_BUNDLED, /* u32 */
|
||||
TIPC_NLA_STATS_MSG_PROF_TOT, /* u32 */
|
||||
TIPC_NLA_STATS_MSG_LEN_CNT, /* u32 */
|
||||
TIPC_NLA_STATS_MSG_LEN_TOT, /* u32 */
|
||||
TIPC_NLA_STATS_MSG_LEN_P0, /* u32 */
|
||||
TIPC_NLA_STATS_MSG_LEN_P1, /* u32 */
|
||||
TIPC_NLA_STATS_MSG_LEN_P2, /* u32 */
|
||||
TIPC_NLA_STATS_MSG_LEN_P3, /* u32 */
|
||||
TIPC_NLA_STATS_MSG_LEN_P4, /* u32 */
|
||||
TIPC_NLA_STATS_MSG_LEN_P5, /* u32 */
|
||||
TIPC_NLA_STATS_MSG_LEN_P6, /* u32 */
|
||||
TIPC_NLA_STATS_RX_STATES, /* u32 */
|
||||
TIPC_NLA_STATS_RX_PROBES, /* u32 */
|
||||
TIPC_NLA_STATS_RX_NACKS, /* u32 */
|
||||
TIPC_NLA_STATS_RX_DEFERRED, /* u32 */
|
||||
TIPC_NLA_STATS_TX_STATES, /* u32 */
|
||||
TIPC_NLA_STATS_TX_PROBES, /* u32 */
|
||||
TIPC_NLA_STATS_TX_NACKS, /* u32 */
|
||||
TIPC_NLA_STATS_TX_ACKS, /* u32 */
|
||||
TIPC_NLA_STATS_RETRANSMITTED, /* u32 */
|
||||
TIPC_NLA_STATS_DUPLICATES, /* u32 */
|
||||
TIPC_NLA_STATS_LINK_CONGS, /* u32 */
|
||||
TIPC_NLA_STATS_MAX_QUEUE, /* u32 */
|
||||
TIPC_NLA_STATS_AVG_QUEUE, /* u32 */
|
||||
|
||||
__TIPC_NLA_STATS_MAX,
|
||||
TIPC_NLA_STATS_MAX = __TIPC_NLA_STATS_MAX - 1
|
||||
};
|
||||
|
||||
#endif
|
@ -183,7 +183,7 @@ static int ipaddrlabel_modify(int cmd, int argc, char **argv)
|
||||
req.ifal.ifal_family = AF_INET6;
|
||||
|
||||
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
|
||||
return 2;
|
||||
return -2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -232,12 +232,12 @@ static int ipaddrlabel_flush(int argc, char **argv)
|
||||
|
||||
if (rtnl_wilddump_request(&rth, af, RTM_GETADDRLABEL) < 0) {
|
||||
perror("Cannot send dump request");
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rtnl_dump_filter(&rth, flush_addrlabel, NULL) < 0) {
|
||||
fprintf(stderr, "Flush terminated\n");
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
13
ip/iplink.c
13
ip/iplink.c
@ -80,6 +80,7 @@ void iplink_usage(void)
|
||||
fprintf(stderr, " [ rate TXRATE ] ] \n");
|
||||
|
||||
fprintf(stderr, " [ spoofchk { on | off} ] ] \n");
|
||||
fprintf(stderr, " [ query_rss { on | off} ] ] \n");
|
||||
fprintf(stderr, " [ state { auto | enable | disable} ] ]\n");
|
||||
fprintf(stderr, " [ master DEVICE ]\n");
|
||||
fprintf(stderr, " [ nomaster ]\n");
|
||||
@ -331,6 +332,18 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
|
||||
ivs.vf = vf;
|
||||
addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK, &ivs, sizeof(ivs));
|
||||
|
||||
} else if (matches(*argv, "query_rss") == 0) {
|
||||
struct ifla_vf_rss_query_en ivs;
|
||||
NEXT_ARG();
|
||||
if (matches(*argv, "on") == 0)
|
||||
ivs.setting = 1;
|
||||
else if (matches(*argv, "off") == 0)
|
||||
ivs.setting = 0;
|
||||
else
|
||||
invarg("Invalid \"query_rss\" value\n", *argv);
|
||||
ivs.vf = vf;
|
||||
addattr_l(&req->n, sizeof(*req), IFLA_VF_RSS_QUERY_EN, &ivs, sizeof(ivs));
|
||||
|
||||
} else if (matches(*argv, "state") == 0) {
|
||||
struct ifla_vf_link_state ivl;
|
||||
NEXT_ARG();
|
||||
|
@ -77,7 +77,7 @@ static void usage(void)
|
||||
fprintf(stderr, " [ scope SCOPE ] [ metric METRIC ]\n");
|
||||
fprintf(stderr, "INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]...\n");
|
||||
fprintf(stderr, "NH := [ via [ FAMILY ] ADDRESS ] [ dev STRING ] [ weight NUMBER ] NHFLAGS\n");
|
||||
fprintf(stderr, "FAMILY := [ inet | inet6 | ipx | dnet | mpls | bridge | link ]");
|
||||
fprintf(stderr, "FAMILY := [ inet | inet6 | ipx | dnet | mpls | bridge | link ]\n");
|
||||
fprintf(stderr, "OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ] [ as [ to ] ADDRESS ]\n");
|
||||
fprintf(stderr, " [ rtt TIME ] [ rttvar TIME ] [ reordering NUMBER ]\n");
|
||||
fprintf(stderr, " [ window NUMBER] [ cwnd NUMBER ] [ initcwnd NUMBER ]\n");
|
||||
@ -1164,7 +1164,7 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
|
||||
req.r.rtm_family = AF_INET;
|
||||
|
||||
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
|
||||
return -1;
|
||||
return -2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -381,7 +381,7 @@ static int iprule_modify(int cmd, int argc, char **argv)
|
||||
req.r.rtm_table = RT_TABLE_MAIN;
|
||||
|
||||
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
|
||||
return 2;
|
||||
return -2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -496,7 +496,7 @@ int get_prefix_1(inet_prefix *dst, char *arg, int family)
|
||||
if (strcmp(arg, "default") == 0 ||
|
||||
strcmp(arg, "any") == 0 ||
|
||||
strcmp(arg, "all") == 0) {
|
||||
if ((family == AF_DECnet) || (family = AF_MPLS))
|
||||
if ((family == AF_DECnet) || (family == AF_MPLS))
|
||||
return -1;
|
||||
dst->family = family;
|
||||
dst->bytelen = 0;
|
||||
|
@ -75,7 +75,8 @@ ip-link \- network device configuration
|
||||
.BR ip6gretap " |"
|
||||
.BR vti " |"
|
||||
.BR nlmon " |"
|
||||
.BR ipvlan " ]"
|
||||
.BR ipvlan " |"
|
||||
.BR lowpan " ]"
|
||||
|
||||
.ti -8
|
||||
.BR "ip link delete " {
|
||||
@ -243,6 +244,9 @@ Link types:
|
||||
.sp
|
||||
.BR ipvlan
|
||||
- Interface for L3 (IPv6/IPv4) based VLANs
|
||||
.sp
|
||||
.BR lowpan
|
||||
- Interface for 6LoWPAN (IPv6) over IEEE 802.15.4 / Bluetooth
|
||||
.in -8
|
||||
|
||||
.TP
|
||||
@ -709,12 +713,6 @@ tool can be used. But it allows to change network namespace only for physical de
|
||||
.BI alias " NAME"
|
||||
give the device a symbolic name for easy reference.
|
||||
|
||||
.TP
|
||||
.BI group " GROUP"
|
||||
specify the group the device belongs to.
|
||||
The available groups are listed in file
|
||||
.BR "@SYSCONFDIR@/group" .
|
||||
|
||||
.TP
|
||||
.BI vf " NUM"
|
||||
specify a Virtual Function device to be configured. The associated PF device
|
||||
@ -863,7 +861,7 @@ specifies which help of link type to dislpay.
|
||||
.SS
|
||||
.I GROUP
|
||||
may be a number or a string from the file
|
||||
.B /etc/iproute2/group
|
||||
.B @SYSCONFDIR@/group
|
||||
which can be manually filled.
|
||||
|
||||
.SH "EXAMPLES"
|
||||
@ -915,6 +913,12 @@ encap-dport 5555 encap-csum encap-remcsum
|
||||
Creates an IPIP that is encapsulated with Generic UDP Encapsulation,
|
||||
and the outer UDP checksum and remote checksum offload are enabled.
|
||||
|
||||
.RE
|
||||
.PP
|
||||
ip link add link wpan0 lowpan0 type lowpan
|
||||
.RS 4
|
||||
Creates a 6LoWPAN interface named lowpan0 on the underlying
|
||||
IEEE 802.15.4 device wpan0.
|
||||
.RE
|
||||
|
||||
.SH SEE ALSO
|
||||
|
@ -245,7 +245,7 @@ Use color output.
|
||||
|
||||
.PP
|
||||
The names of all objects may be written in full or
|
||||
abbreviated form, for exampe
|
||||
abbreviated form, for example
|
||||
.B address
|
||||
can be abbreviated as
|
||||
.B addr
|
||||
@ -275,6 +275,10 @@ Usually it is
|
||||
or, if the objects of this class cannot be listed,
|
||||
.BR "help" .
|
||||
|
||||
.SH EXIT STATUS
|
||||
Exit status is 0 if command was successful, and 1 if there is a syntax error.
|
||||
If an error was reported by the kernel exit status is 2.
|
||||
|
||||
.SH HISTORY
|
||||
.B ip
|
||||
was written by Alexey N. Kuznetsov and added in Linux 2.2.
|
||||
|
93
misc/ss.c
93
misc/ss.c
@ -1684,7 +1684,7 @@ static void tcp_stats_print(struct tcpstat *s)
|
||||
|
||||
if (s->mss)
|
||||
printf(" mss:%d", s->mss);
|
||||
if (s->cwnd && s->cwnd != 2)
|
||||
if (s->cwnd)
|
||||
printf(" cwnd:%d", s->cwnd);
|
||||
if (s->ssthresh)
|
||||
printf(" ssthresh:%d", s->ssthresh);
|
||||
@ -1692,11 +1692,11 @@ static void tcp_stats_print(struct tcpstat *s)
|
||||
if (s->dctcp && s->dctcp->enabled) {
|
||||
struct dctcpstat *dctcp = s->dctcp;
|
||||
|
||||
printf("dctcp:(ce_state:%u,alpha:%u,ab_ecn:%u,ab_tot:%u)",
|
||||
printf(" dctcp:(ce_state:%u,alpha:%u,ab_ecn:%u,ab_tot:%u)",
|
||||
dctcp->ce_state, dctcp->alpha, dctcp->ab_ecn,
|
||||
dctcp->ab_tot);
|
||||
} else if (s->dctcp) {
|
||||
printf("dctcp:fallback_mode");
|
||||
printf(" dctcp:fallback_mode");
|
||||
}
|
||||
|
||||
if (s->send_bps)
|
||||
@ -1893,8 +1893,8 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
|
||||
/* workaround for older kernels with less fields */
|
||||
if (len < sizeof(*info)) {
|
||||
info = alloca(sizeof(*info));
|
||||
memset(info, 0, sizeof(*info));
|
||||
memcpy(info, RTA_DATA(tb[INET_DIAG_INFO]), len);
|
||||
memset((char *)info + len, 0, sizeof(*info) - len);
|
||||
} else
|
||||
info = RTA_DATA(tb[INET_DIAG_INFO]);
|
||||
|
||||
@ -2834,13 +2834,27 @@ static int packet_stats_print(struct sockstat *s, const struct filter *f)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void packet_show_ring(struct packet_diag_ring *ring)
|
||||
{
|
||||
printf("blk_size:%d", ring->pdr_block_size);
|
||||
printf(",blk_nr:%d", ring->pdr_block_nr);
|
||||
printf(",frm_size:%d", ring->pdr_frame_size);
|
||||
printf(",frm_nr:%d", ring->pdr_frame_nr);
|
||||
printf(",tmo:%d", ring->pdr_retire_tmo);
|
||||
printf(",features:0x%x", ring->pdr_features);
|
||||
}
|
||||
|
||||
static int packet_show_sock(const struct sockaddr_nl *addr,
|
||||
struct nlmsghdr *nlh, void *arg)
|
||||
{
|
||||
const struct filter *f = arg;
|
||||
struct packet_diag_msg *r = NLMSG_DATA(nlh);
|
||||
struct packet_diag_info *pinfo = NULL;
|
||||
struct packet_diag_ring *ring_rx = NULL, *ring_tx = NULL;
|
||||
struct rtattr *tb[PACKET_DIAG_MAX+1];
|
||||
struct sockstat stat = {};
|
||||
uint32_t fanout = 0;
|
||||
bool has_fanout = false;
|
||||
|
||||
parse_rtattr(tb, PACKET_DIAG_MAX, (struct rtattr*)(r+1),
|
||||
nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
|
||||
@ -2861,16 +2875,82 @@ static int packet_show_sock(const struct sockaddr_nl *addr,
|
||||
}
|
||||
|
||||
if (tb[PACKET_DIAG_INFO]) {
|
||||
struct packet_diag_info *pinfo = RTA_DATA(tb[PACKET_DIAG_INFO]);
|
||||
pinfo = RTA_DATA(tb[PACKET_DIAG_INFO]);
|
||||
stat.lport = stat.iface = pinfo->pdi_index;
|
||||
}
|
||||
|
||||
if (tb[PACKET_DIAG_UID])
|
||||
stat.uid = *(__u32 *)RTA_DATA(tb[PACKET_DIAG_UID]);
|
||||
|
||||
if (tb[PACKET_DIAG_RX_RING])
|
||||
ring_rx = RTA_DATA(tb[PACKET_DIAG_RX_RING]);
|
||||
|
||||
if (tb[PACKET_DIAG_TX_RING])
|
||||
ring_tx = RTA_DATA(tb[PACKET_DIAG_TX_RING]);
|
||||
|
||||
if (tb[PACKET_DIAG_FANOUT]) {
|
||||
has_fanout = true;
|
||||
fanout = *(uint32_t *)RTA_DATA(tb[PACKET_DIAG_FANOUT]);
|
||||
}
|
||||
|
||||
if (packet_stats_print(&stat, f))
|
||||
return 0;
|
||||
|
||||
if (show_details) {
|
||||
if (pinfo) {
|
||||
printf("\n\tver:%d", pinfo->pdi_version);
|
||||
printf(" cpy_thresh:%d", pinfo->pdi_copy_thresh);
|
||||
printf(" flags( ");
|
||||
if (pinfo->pdi_flags & PDI_RUNNING)
|
||||
printf("running");
|
||||
if (pinfo->pdi_flags & PDI_AUXDATA)
|
||||
printf(" auxdata");
|
||||
if (pinfo->pdi_flags & PDI_ORIGDEV)
|
||||
printf(" origdev");
|
||||
if (pinfo->pdi_flags & PDI_VNETHDR)
|
||||
printf(" vnethdr");
|
||||
if (pinfo->pdi_flags & PDI_LOSS)
|
||||
printf(" loss");
|
||||
if (!pinfo->pdi_flags)
|
||||
printf("0");
|
||||
printf(" )");
|
||||
}
|
||||
if (ring_rx) {
|
||||
printf("\n\tring_rx(");
|
||||
packet_show_ring(ring_rx);
|
||||
printf(")");
|
||||
}
|
||||
if (ring_tx) {
|
||||
printf("\n\tring_tx(");
|
||||
packet_show_ring(ring_tx);
|
||||
printf(")");
|
||||
}
|
||||
if (has_fanout) {
|
||||
uint16_t type = (fanout >> 16) & 0xffff;
|
||||
|
||||
printf("\n\tfanout(");
|
||||
printf("id:%d,", fanout & 0xffff);
|
||||
printf("type:");
|
||||
|
||||
if (type == 0)
|
||||
printf("hash");
|
||||
else if (type == 1)
|
||||
printf("lb");
|
||||
else if (type == 2)
|
||||
printf("cpu");
|
||||
else if (type == 3)
|
||||
printf("roll");
|
||||
else if (type == 4)
|
||||
printf("random");
|
||||
else if (type == 5)
|
||||
printf("qm");
|
||||
else
|
||||
printf("0x%x", type);
|
||||
|
||||
printf(")");
|
||||
}
|
||||
}
|
||||
|
||||
if (show_bpf && tb[PACKET_DIAG_FILTER]) {
|
||||
struct sock_filter *fil =
|
||||
RTA_DATA(tb[PACKET_DIAG_FILTER]);
|
||||
@ -2894,7 +2974,8 @@ static int packet_show_netlink(struct filter *f)
|
||||
DIAG_REQUEST(req, struct packet_diag_req r);
|
||||
|
||||
req.r.sdiag_family = AF_PACKET;
|
||||
req.r.pdiag_show = PACKET_SHOW_INFO | PACKET_SHOW_MEMINFO | PACKET_SHOW_FILTER;
|
||||
req.r.pdiag_show = PACKET_SHOW_INFO | PACKET_SHOW_MEMINFO |
|
||||
PACKET_SHOW_FILTER | PACKET_SHOW_RING_CFG | PACKET_SHOW_FANOUT;
|
||||
|
||||
return handle_netlink_request(f, &req.nlh, sizeof(req), packet_show_sock);
|
||||
}
|
||||
|
@ -43,9 +43,6 @@ static int basic_parse_opt(struct filter_util *qu, char *handle,
|
||||
struct rtattr *tail;
|
||||
long h = 0;
|
||||
|
||||
if (argc == 0)
|
||||
return 0;
|
||||
|
||||
if (handle) {
|
||||
h = strtol(handle, NULL, 0);
|
||||
if (h == LONG_MIN || h == LONG_MAX) {
|
||||
@ -54,9 +51,11 @@ static int basic_parse_opt(struct filter_util *qu, char *handle,
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
t->tcm_handle = h;
|
||||
|
||||
if (argc == 0)
|
||||
return 0;
|
||||
|
||||
tail = (struct rtattr*)(((void*)n)+NLMSG_ALIGN(n->nlmsg_len));
|
||||
addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
|
||||
|
||||
|
186
tc/q_gred.c
186
tc/q_gred.c
@ -37,14 +37,11 @@
|
||||
|
||||
static void explain(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: ... gred DP drop-probability limit BYTES "
|
||||
"min BYTES max BYTES\n");
|
||||
fprintf(stderr, " avpkt BYTES burst PACKETS probability PROBABILITY "
|
||||
"bandwidth KBPS\n");
|
||||
fprintf(stderr, " [prio value]\n");
|
||||
fprintf(stderr," OR ...\n");
|
||||
fprintf(stderr," gred setup DPs <num of DPs> default <default DP> "
|
||||
"[grio]\n");
|
||||
fprintf(stderr, "Usage: tc qdisc { add | replace | change } ... gred setup vqs NUMBER\n");
|
||||
fprintf(stderr, " default DEFAULT_VQ [ grio ]\n");
|
||||
fprintf(stderr, " tc qdisc change ... gred vq VQ [ prio VALUE ] limit BYTES\n");
|
||||
fprintf(stderr, " min BYTES max BYTES avpkt BYTES [ burst PACKETS ]\n");
|
||||
fprintf(stderr, " [ probability PROBABILITY ] [ bandwidth KBPS ]\n");
|
||||
}
|
||||
|
||||
static int init_gred(struct qdisc_util *qu, int argc, char **argv,
|
||||
@ -53,34 +50,35 @@ static int init_gred(struct qdisc_util *qu, int argc, char **argv,
|
||||
|
||||
struct rtattr *tail;
|
||||
struct tc_gred_sopt opt = { 0 };
|
||||
int dps = 0;
|
||||
int def_dp = -1;
|
||||
|
||||
opt.def_DP = MAX_DPs;
|
||||
|
||||
while (argc > 0) {
|
||||
DPRINTF(stderr,"init_gred: invoked with %s\n",*argv);
|
||||
if (strcmp(*argv, "DPs") == 0) {
|
||||
if (strcmp(*argv, "vqs") == 0 ||
|
||||
strcmp(*argv, "DPs") == 0) {
|
||||
NEXT_ARG();
|
||||
DPRINTF(stderr,"init_gred: next_arg with %s\n",*argv);
|
||||
dps = strtol(*argv, (char **)NULL, 10);
|
||||
if (dps < 0 || dps >MAX_DPs) {
|
||||
fprintf(stderr, "DPs =%d\n", dps);
|
||||
fprintf(stderr, "Illegal \"DPs\"\n");
|
||||
fprintf(stderr, "GRED: only %d DPs are "
|
||||
"currently supported\n",MAX_DPs);
|
||||
if (get_unsigned(&opt.DPs, *argv, 10)) {
|
||||
fprintf(stderr, "Illegal \"vqs\"\n");
|
||||
return -1;
|
||||
} else if (opt.DPs > MAX_DPs) {
|
||||
fprintf(stderr, "GRED: only %u VQs are "
|
||||
"currently supported\n", MAX_DPs);
|
||||
return -1;
|
||||
}
|
||||
} else if (strcmp(*argv, "default") == 0) {
|
||||
NEXT_ARG();
|
||||
def_dp = strtol(*argv, (char **)NULL, 10);
|
||||
if (dps == 0) {
|
||||
fprintf(stderr, "\"default DP\" must be "
|
||||
"defined after DPs\n");
|
||||
if (opt.DPs == 0) {
|
||||
fprintf(stderr, "\"default\" must be defined "
|
||||
"after \"vqs\"\n");
|
||||
return -1;
|
||||
}
|
||||
if (def_dp < 0 || def_dp > dps) {
|
||||
fprintf(stderr,
|
||||
"\"default DP\" must be less than %d\n",
|
||||
opt.DPs);
|
||||
NEXT_ARG();
|
||||
if (get_unsigned(&opt.def_DP, *argv, 10)) {
|
||||
fprintf(stderr, "Illegal \"default\"\n");
|
||||
return -1;
|
||||
} else if (opt.def_DP >= opt.DPs) {
|
||||
fprintf(stderr, "\"default\" must be less than "
|
||||
"\"vqs\"\n");
|
||||
return -1;
|
||||
}
|
||||
} else if (strcmp(*argv, "grio") == 0) {
|
||||
@ -96,15 +94,12 @@ static int init_gred(struct qdisc_util *qu, int argc, char **argv,
|
||||
argc--; argv++;
|
||||
}
|
||||
|
||||
if (!dps || def_dp == -1) {
|
||||
if (!opt.DPs || opt.def_DP == MAX_DPs) {
|
||||
fprintf(stderr, "Illegal gred setup parameters \n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
opt.DPs = dps;
|
||||
opt.def_DP = def_dp;
|
||||
|
||||
DPRINTF("TC_GRED: sending DPs=%d default=%d\n",opt.DPs,opt.def_DP);
|
||||
DPRINTF("TC_GRED: sending DPs=%u def_DP=%u\n",opt.DPs,opt.def_DP);
|
||||
n->nlmsg_flags|=NLM_F_CREATE;
|
||||
tail = NLMSG_TAIL(n);
|
||||
addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
|
||||
@ -118,17 +113,17 @@ static int init_gred(struct qdisc_util *qu, int argc, char **argv,
|
||||
static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
|
||||
{
|
||||
int ok=0;
|
||||
struct tc_gred_qopt opt;
|
||||
struct tc_gred_qopt opt = { 0 };
|
||||
unsigned burst = 0;
|
||||
unsigned avpkt = 0;
|
||||
double probability = 0.02;
|
||||
unsigned rate = 0;
|
||||
int wlog;
|
||||
int parm;
|
||||
__u8 sbuf[256];
|
||||
struct rtattr *tail;
|
||||
__u32 max_P;
|
||||
|
||||
memset(&opt, 0, sizeof(opt));
|
||||
opt.DP = MAX_DPs;
|
||||
|
||||
while (argc > 0) {
|
||||
if (strcmp(*argv, "limit") == 0) {
|
||||
@ -143,8 +138,7 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n
|
||||
fprintf(stderr, "Illegal \"setup\"\n");
|
||||
return -1;
|
||||
}
|
||||
return init_gred(qu,argc-1, argv+1,n);
|
||||
|
||||
return init_gred(qu, argc-1, argv+1, n);
|
||||
} else if (strcmp(*argv, "min") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_size(&opt.qth_min, *argv)) {
|
||||
@ -159,20 +153,21 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n
|
||||
return -1;
|
||||
}
|
||||
ok++;
|
||||
} else if (strcmp(*argv, "DP") == 0) {
|
||||
} else if (strcmp(*argv, "vq") == 0 ||
|
||||
strcmp(*argv, "DP") == 0) {
|
||||
NEXT_ARG();
|
||||
opt.DP=strtol(*argv, (char **)NULL, 10);
|
||||
DPRINTF ("\n ******* DP =%u\n",opt.DP);
|
||||
if (opt.DP >MAX_DPs) { /* need a better error check */
|
||||
fprintf(stderr, "DP =%u \n",opt.DP);
|
||||
fprintf(stderr, "Illegal \"DP\"\n");
|
||||
fprintf(stderr, "GRED: only %d DPs are currently supported\n",MAX_DPs);
|
||||
if (get_unsigned(&opt.DP, *argv, 10)) {
|
||||
fprintf(stderr, "Illegal \"vq\"\n");
|
||||
return -1;
|
||||
}
|
||||
} else if (opt.DP >= MAX_DPs) {
|
||||
fprintf(stderr, "GRED: only %u VQs are "
|
||||
"currently supported\n", MAX_DPs);
|
||||
return -1;
|
||||
} /* need a better error check */
|
||||
ok++;
|
||||
} else if (strcmp(*argv, "burst") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_unsigned(&burst, *argv, 0)) {
|
||||
if (get_unsigned(&burst, *argv, 0)) {
|
||||
fprintf(stderr, "Illegal \"burst\"\n");
|
||||
return -1;
|
||||
}
|
||||
@ -214,40 +209,44 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n
|
||||
argc--; argv++;
|
||||
}
|
||||
|
||||
if (rate == 0)
|
||||
get_rate(&rate, "10Mbit");
|
||||
|
||||
if (!opt.qth_min || !opt.qth_max || !opt.limit || !avpkt ||
|
||||
(opt.DP<0)) {
|
||||
fprintf(stderr, "Required parameter (min, max, limit, "
|
||||
"avpkt, DP) is missing\n");
|
||||
if (!ok) {
|
||||
explain();
|
||||
return -1;
|
||||
}
|
||||
if (opt.DP == MAX_DPs || !opt.limit || !opt.qth_min || !opt.qth_max ||
|
||||
!avpkt) {
|
||||
fprintf(stderr, "Required parameter (vq, limit, min, max, "
|
||||
"avpkt) is missing\n");
|
||||
return -1;
|
||||
}
|
||||
if (!burst) {
|
||||
burst = (2 * opt.qth_min + opt.qth_max) / (3 * avpkt);
|
||||
fprintf(stderr, "GRED: set burst to %u\n", burst);
|
||||
}
|
||||
|
||||
if ((wlog = tc_red_eval_ewma(opt.qth_min, burst, avpkt)) < 0) {
|
||||
if (!rate) {
|
||||
get_rate(&rate, "10Mbit");
|
||||
fprintf(stderr, "GRED: set bandwidth to 10Mbit\n");
|
||||
}
|
||||
if ((parm = tc_red_eval_ewma(opt.qth_min, burst, avpkt)) < 0) {
|
||||
fprintf(stderr, "GRED: failed to calculate EWMA constant.\n");
|
||||
return -1;
|
||||
}
|
||||
if (wlog >= 10)
|
||||
fprintf(stderr, "GRED: WARNING. Burst %d seems to be too "
|
||||
if (parm >= 10)
|
||||
fprintf(stderr, "GRED: WARNING. Burst %u seems to be too "
|
||||
"large.\n", burst);
|
||||
opt.Wlog = wlog;
|
||||
if ((wlog = tc_red_eval_P(opt.qth_min, opt.qth_max, probability)) < 0) {
|
||||
opt.Wlog = parm;
|
||||
if ((parm = tc_red_eval_P(opt.qth_min, opt.qth_max, probability)) < 0) {
|
||||
fprintf(stderr, "GRED: failed to calculate probability.\n");
|
||||
return -1;
|
||||
}
|
||||
opt.Plog = wlog;
|
||||
if ((wlog = tc_red_eval_idle_damping(opt.Wlog, avpkt, rate, sbuf)) < 0)
|
||||
opt.Plog = parm;
|
||||
if ((parm = tc_red_eval_idle_damping(opt.Wlog, avpkt, rate, sbuf)) < 0)
|
||||
{
|
||||
fprintf(stderr, "GRED: failed to calculate idle damping "
|
||||
"table.\n");
|
||||
return -1;
|
||||
}
|
||||
opt.Scell_log = wlog;
|
||||
opt.Scell_log = parm;
|
||||
|
||||
tail = NLMSG_TAIL(n);
|
||||
addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
|
||||
@ -262,14 +261,13 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n
|
||||
static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
|
||||
{
|
||||
struct rtattr *tb[TCA_GRED_MAX + 1];
|
||||
struct tc_gred_sopt *sopt;
|
||||
struct tc_gred_qopt *qopt;
|
||||
__u32 *max_p = NULL;
|
||||
int i;
|
||||
unsigned i;
|
||||
SPRINT_BUF(b1);
|
||||
SPRINT_BUF(b2);
|
||||
SPRINT_BUF(b3);
|
||||
SPRINT_BUF(b4);
|
||||
SPRINT_BUF(b5);
|
||||
|
||||
if (opt == NULL)
|
||||
return 0;
|
||||
@ -283,40 +281,50 @@ static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
|
||||
RTA_PAYLOAD(tb[TCA_GRED_MAX_P]) >= sizeof(__u32) * MAX_DPs)
|
||||
max_p = RTA_DATA(tb[TCA_GRED_MAX_P]);
|
||||
|
||||
sopt = RTA_DATA(tb[TCA_GRED_DPS]);
|
||||
qopt = RTA_DATA(tb[TCA_GRED_PARMS]);
|
||||
if (RTA_PAYLOAD(tb[TCA_GRED_PARMS]) < sizeof(*qopt)*MAX_DPs) {
|
||||
if (RTA_PAYLOAD(tb[TCA_GRED_DPS]) < sizeof(*sopt) ||
|
||||
RTA_PAYLOAD(tb[TCA_GRED_PARMS]) < sizeof(*qopt)*MAX_DPs) {
|
||||
fprintf(f,"\n GRED received message smaller than expected\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Bad hack! should really return a proper message as shown above*/
|
||||
|
||||
fprintf(f, "vqs %u default %u %s",
|
||||
sopt->DPs,
|
||||
sopt->def_DP,
|
||||
sopt->grio ? "grio " : "");
|
||||
|
||||
for (i=0;i<MAX_DPs;i++, qopt++) {
|
||||
if (qopt->DP >= MAX_DPs) continue;
|
||||
fprintf(f, "\n DP:%d (prio %d) Average Queue %s Measured "
|
||||
"Queue %s ",
|
||||
fprintf(f, "\n vq %u prio %hhu limit %s min %s max %s ",
|
||||
qopt->DP,
|
||||
qopt->prio,
|
||||
sprint_size(qopt->qave, b4),
|
||||
sprint_size(qopt->backlog, b5));
|
||||
fprintf(f, "\n\t Packet drops: %d (forced %d early %d) ",
|
||||
qopt->forced+qopt->early,
|
||||
qopt->forced,
|
||||
qopt->early);
|
||||
fprintf(f, "\n\t Packet totals: %u (bytes %u) ",
|
||||
qopt->packets,
|
||||
qopt->bytesin);
|
||||
if (show_details)
|
||||
fprintf(f, "\n limit %s min %s max %s ",
|
||||
sprint_size(qopt->limit, b1),
|
||||
sprint_size(qopt->qth_min, b2),
|
||||
sprint_size(qopt->qth_max, b3));
|
||||
fprintf(f, "ewma %u ", qopt->Wlog);
|
||||
if (max_p)
|
||||
fprintf(f, "probability %lg ", max_p[i] / pow(2, 32));
|
||||
else
|
||||
fprintf(f, "Plog %u ", qopt->Plog);
|
||||
fprintf(f, "Scell_log %u", qopt->Scell_log);
|
||||
sprint_size(qopt->limit, b1),
|
||||
sprint_size(qopt->qth_min, b2),
|
||||
sprint_size(qopt->qth_max, b3));
|
||||
if (show_details) {
|
||||
fprintf(f, "ewma %u ", qopt->Wlog);
|
||||
if (max_p)
|
||||
fprintf(f, "probability %lg ", max_p[i] / pow(2, 32));
|
||||
else
|
||||
fprintf(f, "Plog %u ", qopt->Plog);
|
||||
fprintf(f, "Scell_log %u ", qopt->Scell_log);
|
||||
}
|
||||
if (show_stats) {
|
||||
fprintf(f, "\n Queue size: average %s current %s ",
|
||||
sprint_size(qopt->qave, b1),
|
||||
sprint_size(qopt->backlog, b2));
|
||||
fprintf(f, "\n Dropped packets: forced %u early %u pdrop %u other %u ",
|
||||
qopt->forced,
|
||||
qopt->early,
|
||||
qopt->pdrop,
|
||||
qopt->other);
|
||||
fprintf(f, "\n Total packets: %u (%s) ",
|
||||
qopt->packets,
|
||||
sprint_size(qopt->bytesin, b1));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -34,18 +34,14 @@ static void explain(void)
|
||||
|
||||
static int ingress_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
|
||||
{
|
||||
|
||||
if (argc > 0) {
|
||||
while (argc > 0) {
|
||||
|
||||
if (strcmp(*argv, "handle") == 0) {
|
||||
NEXT_ARG();
|
||||
argc--; argv++;
|
||||
} else {
|
||||
fprintf(stderr, "What is \"%s\"?\n", *argv);
|
||||
explain();
|
||||
return -1;
|
||||
}
|
||||
while (argc > 0) {
|
||||
if (strcmp(*argv, "handle") == 0) {
|
||||
NEXT_ARG();
|
||||
argc--; argv++;
|
||||
} else {
|
||||
fprintf(stderr, "What is \"%s\"?\n", *argv);
|
||||
explain();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,8 +51,7 @@ static int ingress_parse_opt(struct qdisc_util *qu, int argc, char **argv, struc
|
||||
|
||||
static int ingress_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
|
||||
{
|
||||
|
||||
fprintf(f, "---------------- ");
|
||||
fprintf(f, "---------------- ");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
27
tc/q_red.c
27
tc/q_red.c
@ -29,7 +29,7 @@
|
||||
static void explain(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: ... red limit BYTES [min BYTES] [max BYTES] avpkt BYTES [burst PACKETS]\n");
|
||||
fprintf(stderr, " [adaptive] [probability PROBABILITY] bandwidth KBPS\n");
|
||||
fprintf(stderr, " [adaptive] [probability PROBABILITY] [bandwidth KBPS]\n");
|
||||
fprintf(stderr, " [ecn] [harddrop]\n");
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ static int red_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
|
||||
unsigned avpkt = 0;
|
||||
double probability = 0.02;
|
||||
unsigned rate = 0;
|
||||
int wlog;
|
||||
int parm;
|
||||
__u8 sbuf[256];
|
||||
__u32 max_P;
|
||||
struct rtattr *tail;
|
||||
@ -109,9 +109,6 @@ static int red_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
|
||||
argc--; argv++;
|
||||
}
|
||||
|
||||
if (rate == 0)
|
||||
get_rate(&rate, "10Mbit");
|
||||
|
||||
if (!opt.limit || !avpkt) {
|
||||
fprintf(stderr, "RED: Required parameter (limit, avpkt) is missing\n");
|
||||
return -1;
|
||||
@ -126,23 +123,27 @@ static int red_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
|
||||
opt.qth_min = opt.qth_max / 3;
|
||||
if (!burst)
|
||||
burst = (2 * opt.qth_min + opt.qth_max) / (3 * avpkt);
|
||||
if ((wlog = tc_red_eval_ewma(opt.qth_min, burst, avpkt)) < 0) {
|
||||
if (!rate) {
|
||||
get_rate(&rate, "10Mbit");
|
||||
fprintf(stderr, "RED: set bandwidth to 10Mbit\n");
|
||||
}
|
||||
if ((parm = tc_red_eval_ewma(opt.qth_min, burst, avpkt)) < 0) {
|
||||
fprintf(stderr, "RED: failed to calculate EWMA constant.\n");
|
||||
return -1;
|
||||
}
|
||||
if (wlog >= 10)
|
||||
fprintf(stderr, "RED: WARNING. Burst %d seems to be too large.\n", burst);
|
||||
opt.Wlog = wlog;
|
||||
if ((wlog = tc_red_eval_P(opt.qth_min, opt.qth_max, probability)) < 0) {
|
||||
if (parm >= 10)
|
||||
fprintf(stderr, "RED: WARNING. Burst %u seems to be too large.\n", burst);
|
||||
opt.Wlog = parm;
|
||||
if ((parm = tc_red_eval_P(opt.qth_min, opt.qth_max, probability)) < 0) {
|
||||
fprintf(stderr, "RED: failed to calculate probability.\n");
|
||||
return -1;
|
||||
}
|
||||
opt.Plog = wlog;
|
||||
if ((wlog = tc_red_eval_idle_damping(opt.Wlog, avpkt, rate, sbuf)) < 0) {
|
||||
opt.Plog = parm;
|
||||
if ((parm = tc_red_eval_idle_damping(opt.Wlog, avpkt, rate, sbuf)) < 0) {
|
||||
fprintf(stderr, "RED: failed to calculate idle damping table.\n");
|
||||
return -1;
|
||||
}
|
||||
opt.Scell_log = wlog;
|
||||
opt.Scell_log = parm;
|
||||
|
||||
tail = NLMSG_TAIL(n);
|
||||
addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
|
||||
|
@ -1,9 +1,11 @@
|
||||
## -- Config --
|
||||
DEV := lo
|
||||
PREFIX := sudo -E
|
||||
PREFIX := sudo -E unshare -n
|
||||
RESULTS_DIR := results
|
||||
## -- End Config --
|
||||
|
||||
HAVE_UNSHARED_UTIL := $(shell unshare --version 2> /dev/null)
|
||||
|
||||
rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))
|
||||
|
||||
TESTS := $(patsubst tests/%,%,$(call rwildcard,tests/,*.t))
|
||||
@ -38,6 +40,9 @@ distclean: clean
|
||||
echo "Entering iproute2" && cd iproute2 && $(MAKE) distclean && cd ..;
|
||||
|
||||
$(TESTS): clean
|
||||
ifeq (,$(HAVE_UNSHARED_UTIL))
|
||||
$(error Please install util-linux tools to run tests in separated network namespace)
|
||||
endif
|
||||
@mkdir -p $(RESULTS_DIR)
|
||||
|
||||
@for d in $(TESTS_DIR); do \
|
||||
|
12
testsuite/tests/ip/route/add_default_route.t
Executable file
12
testsuite/tests/ip/route/add_default_route.t
Executable file
@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
|
||||
source lib/generic.sh
|
||||
|
||||
ts_log "[Testing add default route]"
|
||||
|
||||
DEV=dummy0
|
||||
|
||||
ts_ip "$0" "Add new interface $DEV" link add $DEV type dummy
|
||||
ts_ip "$0" "Set $DEV into UP state" link set up dev $DEV
|
||||
ts_ip "$0" "Add 1.1.1.1/24 addr on $DEV" addr add 1.1.1.1/24 dev $DEV
|
||||
ts_ip "$0" "Add default route via 1.1.1.1" route add default via 1.1.1.1
|
1
tipc/.gitignore
vendored
Normal file
1
tipc/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
tipc
|
19
tipc/Makefile
Normal file
19
tipc/Makefile
Normal file
@ -0,0 +1,19 @@
|
||||
TIPCOBJ=bearer.o \
|
||||
cmdl.o link.o \
|
||||
media.o misc.o \
|
||||
msg.o nametable.o \
|
||||
node.o socket.o \
|
||||
tipc.o
|
||||
|
||||
TARGETS=tipc
|
||||
LDLIBS += -lmnl
|
||||
|
||||
all: $(TARGETS) $(LIBS)
|
||||
|
||||
tipc: $(TIPCOBJ)
|
||||
|
||||
install: all
|
||||
install -m 0755 $(TARGETS) $(DESTDIR)$(SBINDIR)
|
||||
|
||||
clean:
|
||||
rm -f $(TIPCOBJ) $(TARGETS)
|
63
tipc/README
Normal file
63
tipc/README
Normal file
@ -0,0 +1,63 @@
|
||||
DESIGN DECISIONS
|
||||
----------------
|
||||
|
||||
HELP
|
||||
~~~~
|
||||
--help or -h is used for help. We do not reserve the bare word "help", which
|
||||
for example the ip command does. Reserving a bare word like help quickly
|
||||
becomes cumbersome to handle in the code. It might be simple to handle
|
||||
when it's passed early in the command chain like "ip addr help". But when
|
||||
the user tries to pass "help" further down this requires manual checks and
|
||||
special treatment. For example, at the time of writing this tool, it's
|
||||
possible to create a vlan named "help" with the ip tool, but it's impossible
|
||||
to remove it, the command just shows help. This is an effect of treating
|
||||
bare words specially.
|
||||
|
||||
Help texts are not dynamically generated. That is, we do not pass datastructures
|
||||
like command list or option lists and print them dynamically. This is
|
||||
intentional. There is always that exception and when it comes to help texts
|
||||
these exceptions are normally neglected at the expence of usability.
|
||||
|
||||
KEY-VALUE
|
||||
~~~~~~~~~
|
||||
All options are key-values. There are both drawbacks and benefits to this.
|
||||
The main drawback is that it becomes more to write for the user and
|
||||
information might seem redundant. The main benefits is scalability and code
|
||||
simplification. Consistency is important.
|
||||
|
||||
Consider this.
|
||||
1. tipc link set priority PRIO link LINK
|
||||
2. tipc link set LINK priority PRIO
|
||||
|
||||
Link might seem redundant in (1). However, if the command should live for many
|
||||
years and be able to evolve example (2) limits the set command to only work on a
|
||||
single link with no ability to extend. As an example, lets say we introduce
|
||||
grouping on the kernel side.
|
||||
|
||||
1. tipc link set priority PRIO group GROUP
|
||||
2. tipc link set ??? priority PRIO group GROUP
|
||||
|
||||
2. breaks, we can't extend the command to cover a group.
|
||||
|
||||
PARSING
|
||||
~~~~~~~
|
||||
Commands are single words. As an example, all words in "tipc link list" are
|
||||
commands. Options are key-values that can be given in any order. In
|
||||
"tipc link set priority PRIO link LINK" "tipc link set" are commands while
|
||||
priority and link are options. Meaning that they can be given like
|
||||
"tipc link set link LINK priority PRIO".
|
||||
|
||||
Abbreviation matching works for both command and options. Meaning that
|
||||
"tipc link set priority PRIO link LINK" could be given as
|
||||
"tipc l s p PRIO l LINK" and "tipc link list" as "tipc l l".
|
||||
|
||||
MEMORY
|
||||
~~~~~~
|
||||
The tool strives to avoid allocating memory on the heap. Most (if not all)
|
||||
memory allocations are on the stack.
|
||||
|
||||
RETURNING
|
||||
~~~~~~~~~
|
||||
The tool could throw exit() deep down in functions but doing so always seems
|
||||
to limit the program in the long run. So we output the error and return an
|
||||
appropriate error code upon failure.
|
725
tipc/bearer.c
Normal file
725
tipc/bearer.c
Normal file
@ -0,0 +1,725 @@
|
||||
/*
|
||||
* 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 <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"
|
||||
|
||||
static void _print_bearer_opts(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"\nOPTIONS\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)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s bearer enable media MEDIA device DEVICE [OPTIONS]\n"
|
||||
"\nOPTIONS\n"
|
||||
" domain DOMAIN - Discovery domain\n"
|
||||
" priority PRIORITY - Bearer priority\n",
|
||||
cmdl->argv[0]);
|
||||
}
|
||||
|
||||
static void cmd_bearer_enable_udp_help(struct cmdl *cmdl)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s bearer enable media udp name NAME localip IP [OPTIONS]\n"
|
||||
"\nOPTIONS\n"
|
||||
" domain DOMAIN - Discovery domain\n"
|
||||
" priority PRIORITY - Bearer priority\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]);
|
||||
}
|
||||
|
||||
static int enable_l2_bearer(struct nlmsghdr *nlh, struct opt *opts,
|
||||
struct cmdl *cmdl)
|
||||
{
|
||||
struct opt *opt;
|
||||
char id[TIPC_MAX_BEARER_NAME];
|
||||
|
||||
if (!(opt = get_opt(opts, "device"))) {
|
||||
fprintf(stderr, "error: missing bearer device\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
snprintf(id, sizeof(id), "eth:%s", opt->val);
|
||||
mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 enable_udp_bearer(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;
|
||||
char name[TIPC_MAX_BEARER_NAME];
|
||||
struct addrinfo *loc = NULL;
|
||||
struct addrinfo *rem = NULL;
|
||||
struct addrinfo hints = {
|
||||
.ai_family = AF_UNSPEC,
|
||||
.ai_socktype = SOCK_DGRAM
|
||||
};
|
||||
|
||||
if (help_flag) {
|
||||
cmd_bearer_enable_udp_help(cmdl);
|
||||
/* TODO find a better error code? */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(opt = get_opt(opts, "name"))) {
|
||||
fprintf(stderr, "error, udp bearer name missing\n");
|
||||
cmd_bearer_enable_udp_help(cmdl);
|
||||
return -EINVAL;
|
||||
}
|
||||
snprintf(name, sizeof(name), "udp:%s", opt->val);
|
||||
|
||||
if (!(opt = get_opt(opts, "localip"))) {
|
||||
fprintf(stderr, "error, udp bearer localip missing\n");
|
||||
cmd_bearer_enable_udp_help(cmdl);
|
||||
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;
|
||||
}
|
||||
|
||||
mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, name);
|
||||
|
||||
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 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];
|
||||
char *media;
|
||||
struct opt opts[] = {
|
||||
{ "device", NULL },
|
||||
{ "domain", NULL },
|
||||
{ "localip", NULL },
|
||||
{ "localport", NULL },
|
||||
{ "media", NULL },
|
||||
{ "name", NULL },
|
||||
{ "priority", NULL },
|
||||
{ "remoteip", NULL },
|
||||
{ "remoteport", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
if (parse_opts(opts, cmdl) < 0) {
|
||||
if (help_flag)
|
||||
(cmd->help)(cmdl);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (strcmp(media, "udp") == 0) {
|
||||
if (help_flag) {
|
||||
cmd_bearer_enable_udp_help(cmdl);
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((err = enable_udp_bearer(nlh, opts, cmdl)))
|
||||
return err;
|
||||
} else if ((strcmp(media, "eth") == 0) || (strcmp(media, "udp") == 0)) {
|
||||
if (help_flag) {
|
||||
cmd_bearer_enable_l2_help(cmdl);
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((err = enable_l2_bearer(nlh, opts, cmdl)))
|
||||
return err;
|
||||
} else {
|
||||
fprintf(stderr, "error, invalid media type \"%s\"\n", media);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mnl_attr_nest_end(nlh, nest);
|
||||
|
||||
return msg_doit(nlh, NULL, NULL);
|
||||
}
|
||||
|
||||
static int add_l2_bearer(struct nlmsghdr *nlh, struct opt *opts)
|
||||
{
|
||||
struct opt *opt;
|
||||
char id[TIPC_MAX_BEARER_NAME];
|
||||
|
||||
if (!(opt = get_opt(opts, "device"))) {
|
||||
fprintf(stderr, "error: missing bearer device\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
snprintf(id, sizeof(id), "eth:%s", opt->val);
|
||||
|
||||
mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_udp_bearer(struct nlmsghdr *nlh, struct opt *opts)
|
||||
{
|
||||
struct opt *opt;
|
||||
char id[TIPC_MAX_BEARER_NAME];
|
||||
|
||||
if (!(opt = get_opt(opts, "name"))) {
|
||||
fprintf(stderr, "error: missing bearer name\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
snprintf(id, sizeof(id), "udp:%s", opt->val);
|
||||
|
||||
mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cmd_bearer_disable_l2_help(struct cmdl *cmdl)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s bearer disable media udp device DEVICE\n",
|
||||
cmdl->argv[0]);
|
||||
}
|
||||
|
||||
static void cmd_bearer_disable_udp_help(struct cmdl *cmdl)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s bearer disable media udp name NAME\n",
|
||||
cmdl->argv[0]);
|
||||
}
|
||||
|
||||
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 *media;
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
struct nlattr *nest;
|
||||
struct opt *opt;
|
||||
struct opt opts[] = {
|
||||
{ "device", NULL },
|
||||
{ "name", NULL },
|
||||
{ "media", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
if (parse_opts(opts, cmdl) < 0) {
|
||||
if (help_flag)
|
||||
(cmd->help)(cmdl);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
if (strcmp(media, "udp") == 0) {
|
||||
if (help_flag) {
|
||||
cmd_bearer_disable_udp_help(cmdl);
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((err = add_udp_bearer(nlh, opts)))
|
||||
return err;
|
||||
} else if ((strcmp(media, "eth") == 0) || (strcmp(media, "udp") == 0)) {
|
||||
if (help_flag) {
|
||||
cmd_bearer_disable_l2_help(cmdl);
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((err = add_l2_bearer(nlh, opts)))
|
||||
return err;
|
||||
} else {
|
||||
fprintf(stderr, "error, invalid media type \"%s\"\n", media);
|
||||
return -EINVAL;
|
||||
}
|
||||
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 [OPTIONS] media MEDIA ARGS...\n",
|
||||
cmdl->argv[0]);
|
||||
_print_bearer_opts();
|
||||
_print_bearer_media();
|
||||
}
|
||||
|
||||
static void cmd_bearer_set_udp_help(struct cmdl *cmdl)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s bearer set [OPTIONS] media udp name NAME\n\n",
|
||||
cmdl->argv[0]);
|
||||
_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 *media;
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
struct nlattr *props;
|
||||
struct nlattr *attrs;
|
||||
struct opt *opt;
|
||||
struct opt opts[] = {
|
||||
{ "device", NULL },
|
||||
{ "media", NULL },
|
||||
{ "name", NULL },
|
||||
{ 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 (help_flag) {
|
||||
(cmd->help)(cmdl);
|
||||
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);
|
||||
|
||||
if (!(opt = get_opt(opts, "media"))) {
|
||||
fprintf(stderr, "error, missing media\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
media = opt->val;
|
||||
|
||||
if (strcmp(media, "udp") == 0) {
|
||||
if (help_flag) {
|
||||
cmd_bearer_set_udp_help(cmdl);
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((err = add_udp_bearer(nlh, opts)))
|
||||
return err;
|
||||
} else if ((strcmp(media, "eth") == 0) || (strcmp(media, "udp") == 0)) {
|
||||
if (help_flag) {
|
||||
cmd_bearer_set_l2_help(cmdl, media);
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((err = add_l2_bearer(nlh, opts)))
|
||||
return err;
|
||||
} else {
|
||||
fprintf(stderr, "error, invalid media type \"%s\"\n", media);
|
||||
return -EINVAL;
|
||||
}
|
||||
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 [OPTIONS] media MEDIA ARGS...\n",
|
||||
cmdl->argv[0]);
|
||||
_print_bearer_opts();
|
||||
_print_bearer_media();
|
||||
}
|
||||
|
||||
static void cmd_bearer_get_udp_help(struct cmdl *cmdl)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s bearer get [OPTIONS] media udp name NAME\n\n",
|
||||
cmdl->argv[0]);
|
||||
_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_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_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
|
||||
struct cmdl *cmdl, void *data)
|
||||
{
|
||||
int err;
|
||||
int prop;
|
||||
char *media;
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
struct nlattr *attrs;
|
||||
struct opt *opt;
|
||||
struct opt opts[] = {
|
||||
{ "device", NULL },
|
||||
{ "media", NULL },
|
||||
{ "name", NULL },
|
||||
{ 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 (help_flag) {
|
||||
(cmd->help)(cmdl);
|
||||
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;
|
||||
}
|
||||
|
||||
if (!(opt = get_opt(opts, "media"))) {
|
||||
fprintf(stderr, "error, missing media\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
media = opt->val;
|
||||
|
||||
attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
|
||||
if (strcmp(media, "udp") == 0) {
|
||||
if (help_flag) {
|
||||
cmd_bearer_get_udp_help(cmdl);
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((err = add_udp_bearer(nlh, opts)))
|
||||
return err;
|
||||
} else if ((strcmp(media, "eth") == 0) || (strcmp(media, "udp") == 0)) {
|
||||
if (help_flag) {
|
||||
cmd_bearer_get_l2_help(cmdl, media);
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((err = add_l2_bearer(nlh, opts)))
|
||||
return err;
|
||||
} else {
|
||||
fprintf(stderr, "error, invalid media type \"%s\"\n", media);
|
||||
return -EINVAL;
|
||||
}
|
||||
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 },
|
||||
{ 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"
|
||||
" 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[] = {
|
||||
{ "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);
|
||||
}
|
22
tipc/bearer.h
Normal file
22
tipc/bearer.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* bearer.h 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>
|
||||
*/
|
||||
|
||||
#ifndef _TIPC_BEARER_H
|
||||
#define _TIPC_BEARER_H
|
||||
|
||||
#include "cmdl.h"
|
||||
|
||||
extern int help_flag;
|
||||
|
||||
int cmd_bearer(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data);
|
||||
void cmd_bearer_help(struct cmdl *cmdl);
|
||||
|
||||
#endif
|
127
tipc/cmdl.c
Normal file
127
tipc/cmdl.c
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* cmdl.c Framework for handling command line options.
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <libmnl/libmnl.h>
|
||||
|
||||
#include "cmdl.h"
|
||||
|
||||
const struct cmd *find_cmd(const struct cmd *cmds, char *str)
|
||||
{
|
||||
const struct cmd *c;
|
||||
const struct cmd *match = NULL;
|
||||
|
||||
for (c = cmds; c->cmd; c++) {
|
||||
if (strstr(c->cmd, str) != c->cmd)
|
||||
continue;
|
||||
if (match)
|
||||
return NULL;
|
||||
match = c;
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
static struct opt *find_opt(struct opt *opts, char *str)
|
||||
{
|
||||
struct opt *o;
|
||||
struct opt *match = NULL;
|
||||
|
||||
for (o = opts; o->key; o++) {
|
||||
if (strstr(o->key, str) != o->key)
|
||||
continue;
|
||||
if (match)
|
||||
return NULL;
|
||||
|
||||
match = o;
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
struct opt *get_opt(struct opt *opts, char *key)
|
||||
{
|
||||
struct opt *o;
|
||||
|
||||
for (o = opts; o->key; o++) {
|
||||
if (strcmp(o->key, key) == 0 && o->val)
|
||||
return o;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *shift_cmdl(struct cmdl *cmdl)
|
||||
{
|
||||
int next;
|
||||
|
||||
if (cmdl->optind < cmdl->argc)
|
||||
next = (cmdl->optind)++;
|
||||
else
|
||||
next = cmdl->argc;
|
||||
|
||||
return cmdl->argv[next];
|
||||
}
|
||||
|
||||
/* Returns the number of options parsed or a negative error code upon failure */
|
||||
int parse_opts(struct opt *opts, struct cmdl *cmdl)
|
||||
{
|
||||
int i;
|
||||
int cnt = 0;
|
||||
|
||||
for (i = cmdl->optind; i < cmdl->argc; i += 2) {
|
||||
struct opt *o;
|
||||
|
||||
o = find_opt(opts, cmdl->argv[i]);
|
||||
if (!o) {
|
||||
fprintf(stderr, "error, invalid option \"%s\"\n",
|
||||
cmdl->argv[i]);
|
||||
return -EINVAL;
|
||||
}
|
||||
cnt++;
|
||||
o->val = cmdl->argv[i + 1];
|
||||
cmdl->optind += 2;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
int run_cmd(struct nlmsghdr *nlh, const struct cmd *caller,
|
||||
const struct cmd *cmds, struct cmdl *cmdl, void *data)
|
||||
{
|
||||
char *name;
|
||||
const struct cmd *cmd;
|
||||
|
||||
if ((cmdl->optind) >= cmdl->argc) {
|
||||
if (caller->help)
|
||||
(caller->help)(cmdl);
|
||||
return -EINVAL;
|
||||
}
|
||||
name = cmdl->argv[cmdl->optind];
|
||||
(cmdl->optind)++;
|
||||
|
||||
cmd = find_cmd(cmds, name);
|
||||
if (!cmd) {
|
||||
/* Show help about last command if we don't find this one */
|
||||
if (help_flag && caller->help) {
|
||||
(caller->help)(cmdl);
|
||||
} else {
|
||||
fprintf(stderr, "error, invalid command \"%s\"\n", name);
|
||||
fprintf(stderr, "use --help for command help\n");
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return (cmd->func)(nlh, cmd, cmdl, data);
|
||||
}
|
46
tipc/cmdl.h
Normal file
46
tipc/cmdl.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* cmdl.h Framework for handling command line options.
|
||||
*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#ifndef _TIPC_CMDL_H
|
||||
#define _TIPC_CMDL_H
|
||||
|
||||
#include <libmnl/libmnl.h>
|
||||
|
||||
extern int help_flag;
|
||||
|
||||
struct cmdl {
|
||||
int optind;
|
||||
int argc;
|
||||
char **argv;
|
||||
};
|
||||
|
||||
struct cmd {
|
||||
const char *cmd;
|
||||
int (*func)(struct nlmsghdr *nlh, const struct cmd *cmd,
|
||||
struct cmdl *cmdl, void *data);
|
||||
void (*help)(struct cmdl *cmdl);
|
||||
};
|
||||
|
||||
struct opt {
|
||||
const char *key;
|
||||
char *val;
|
||||
};
|
||||
|
||||
struct opt *get_opt(struct opt *opts, char *key);
|
||||
int parse_opts(struct opt *opts, struct cmdl *cmdl);
|
||||
char *shift_cmdl(struct cmdl *cmdl);
|
||||
|
||||
int run_cmd(struct nlmsghdr *nlh, const struct cmd *caller,
|
||||
const struct cmd *cmds, struct cmdl *cmdl, void *data);
|
||||
|
||||
const struct cmd *find_cmd(const struct cmd *cmds, char *str);
|
||||
|
||||
#endif
|
520
tipc/link.c
Normal file
520
tipc/link.c
Normal file
@ -0,0 +1,520 @@
|
||||
/*
|
||||
* link.c TIPC link 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 <errno.h>
|
||||
|
||||
#include <linux/tipc_netlink.h>
|
||||
#include <linux/tipc.h>
|
||||
#include <linux/genetlink.h>
|
||||
#include <libmnl/libmnl.h>
|
||||
|
||||
#include "cmdl.h"
|
||||
#include "msg.h"
|
||||
#include "link.h"
|
||||
|
||||
static int link_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_LINK_MAX + 1] = {};
|
||||
|
||||
mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
|
||||
if (!info[TIPC_NLA_LINK])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
mnl_attr_parse_nested(info[TIPC_NLA_LINK], parse_attrs, attrs);
|
||||
if (!attrs[TIPC_NLA_LINK_NAME])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
printf("%s: ", mnl_attr_get_str(attrs[TIPC_NLA_LINK_NAME]));
|
||||
|
||||
if (attrs[TIPC_NLA_LINK_UP])
|
||||
printf("up\n");
|
||||
else
|
||||
printf("down\n");
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int cmd_link_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 link list\n", cmdl->argv[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(nlh = msg_init(buf, TIPC_NL_LINK_GET))) {
|
||||
fprintf(stderr, "error, message initialisation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return msg_dumpit(nlh, link_list_cb, NULL);
|
||||
}
|
||||
|
||||
static int link_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_LINK_MAX + 1] = {};
|
||||
struct nlattr *props[TIPC_NLA_PROP_MAX + 1] = {};
|
||||
|
||||
mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
|
||||
if (!info[TIPC_NLA_LINK])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
mnl_attr_parse_nested(info[TIPC_NLA_LINK], parse_attrs, attrs);
|
||||
if (!attrs[TIPC_NLA_LINK_PROP])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
mnl_attr_parse_nested(attrs[TIPC_NLA_LINK_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_link_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
|
||||
struct cmdl *cmdl, void *data)
|
||||
{
|
||||
int prop;
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
struct opt *opt;
|
||||
struct opt opts[] = {
|
||||
{ "link", NULL },
|
||||
{ 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 (help_flag) {
|
||||
(cmd->help)(cmdl);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (parse_opts(opts, cmdl) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!(nlh = msg_init(buf, TIPC_NL_LINK_GET))) {
|
||||
fprintf(stderr, "error, message initialisation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(opt = get_opt(opts, "link"))) {
|
||||
fprintf(stderr, "error, missing link\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
mnl_attr_put_strz(nlh, TIPC_NLA_LINK_NAME, opt->val);
|
||||
|
||||
return msg_doit(nlh, link_get_cb, &prop);
|
||||
}
|
||||
|
||||
static void cmd_link_get_help(struct cmdl *cmdl)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s link get PPROPERTY link LINK\n\n"
|
||||
"PROPERTIES\n"
|
||||
" tolerance - Get link tolerance\n"
|
||||
" priority - Get link priority\n"
|
||||
" window - Get link window\n",
|
||||
cmdl->argv[0]);
|
||||
}
|
||||
|
||||
static int cmd_link_get(struct nlmsghdr *nlh, const struct cmd *cmd,
|
||||
struct cmdl *cmdl, void *data)
|
||||
{
|
||||
const struct cmd cmds[] = {
|
||||
{ "priority", cmd_link_get_prop, cmd_link_get_help },
|
||||
{ "tolerance", cmd_link_get_prop, cmd_link_get_help },
|
||||
{ "window", cmd_link_get_prop, cmd_link_get_help },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return run_cmd(nlh, cmd, cmds, cmdl, NULL);
|
||||
}
|
||||
|
||||
static void cmd_link_stat_reset_help(struct cmdl *cmdl)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s link stat reset link LINK\n\n", cmdl->argv[0]);
|
||||
}
|
||||
|
||||
static int cmd_link_stat_reset(struct nlmsghdr *nlh, const struct cmd *cmd,
|
||||
struct cmdl *cmdl, void *data)
|
||||
{
|
||||
char *link;
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
struct opt *opt;
|
||||
struct nlattr *nest;
|
||||
struct opt opts[] = {
|
||||
{ "link", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
if (help_flag) {
|
||||
(cmd->help)(cmdl);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (parse_opts(opts, cmdl) != 1) {
|
||||
(cmd->help)(cmdl);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(nlh = msg_init(buf, TIPC_NL_LINK_RESET_STATS))) {
|
||||
fprintf(stderr, "error, message initialisation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(opt = get_opt(opts, "link"))) {
|
||||
fprintf(stderr, "error, missing link\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
link = opt->val;
|
||||
|
||||
nest = mnl_attr_nest_start(nlh, TIPC_NLA_LINK);
|
||||
mnl_attr_put_strz(nlh, TIPC_NLA_LINK_NAME, link);
|
||||
mnl_attr_nest_end(nlh, nest);
|
||||
|
||||
return msg_doit(nlh, NULL, NULL);
|
||||
}
|
||||
|
||||
static uint32_t perc(uint32_t count, uint32_t total)
|
||||
{
|
||||
return (count * 100 + (total / 2)) / total;
|
||||
}
|
||||
|
||||
static int _show_link_stat(struct nlattr *attrs[], struct nlattr *prop[],
|
||||
struct nlattr *stats[])
|
||||
{
|
||||
uint32_t proft;
|
||||
|
||||
if (attrs[TIPC_NLA_LINK_ACTIVE])
|
||||
printf(" ACTIVE");
|
||||
else if (attrs[TIPC_NLA_LINK_UP])
|
||||
printf(" STANDBY");
|
||||
else
|
||||
printf(" DEFUNCT");
|
||||
|
||||
printf(" MTU:%u Priority:%u Tolerance:%u ms Window:%u packets\n",
|
||||
mnl_attr_get_u32(attrs[TIPC_NLA_LINK_MTU]),
|
||||
mnl_attr_get_u32(prop[TIPC_NLA_PROP_PRIO]),
|
||||
mnl_attr_get_u32(prop[TIPC_NLA_PROP_TOL]),
|
||||
mnl_attr_get_u32(prop[TIPC_NLA_PROP_WIN]));
|
||||
|
||||
printf(" RX packets:%u fragments:%u/%u bundles:%u/%u\n",
|
||||
mnl_attr_get_u32(attrs[TIPC_NLA_LINK_RX]) -
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_INFO]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTS]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTED]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLES]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLED]));
|
||||
|
||||
printf(" TX packets:%u fragments:%u/%u bundles:%u/%u\n",
|
||||
mnl_attr_get_u32(attrs[TIPC_NLA_LINK_TX]) -
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_INFO]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTS]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTED]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLES]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLED]));
|
||||
|
||||
proft = mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT]);
|
||||
printf(" TX profile sample:%u packets average:%u octets\n",
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_CNT]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_TOT]) / proft);
|
||||
|
||||
printf(" 0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% "
|
||||
"-16384:%u%% -32768:%u%% -66000:%u%%\n",
|
||||
perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P0]), proft),
|
||||
perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P1]), proft),
|
||||
perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P2]), proft),
|
||||
perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P3]), proft),
|
||||
perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P4]), proft),
|
||||
perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P5]), proft),
|
||||
perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P6]), proft));
|
||||
|
||||
printf(" RX states:%u probes:%u naks:%u defs:%u dups:%u\n",
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_STATES]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_PROBES]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_NACKS]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_DEFERRED]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_DUPLICATES]));
|
||||
|
||||
printf(" TX states:%u probes:%u naks:%u acks:%u dups:%u\n",
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_STATES]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_PROBES]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_NACKS]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_ACKS]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_RETRANSMITTED]));
|
||||
|
||||
printf(" Congestion link:%u Send queue max:%u avg:%u\n",
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_LINK_CONGS]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_MAX_QUEUE]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_AVG_QUEUE]));
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int _show_bc_link_stat(struct nlattr *prop[], struct nlattr *stats[])
|
||||
{
|
||||
printf(" Window:%u packets\n",
|
||||
mnl_attr_get_u32(prop[TIPC_NLA_PROP_WIN]));
|
||||
|
||||
printf(" RX packets:%u fragments:%u/%u bundles:%u/%u\n",
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_INFO]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTS]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTED]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLES]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLED]));
|
||||
|
||||
printf(" TX packets:%u fragments:%u/%u bundles:%u/%u\n",
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_INFO]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTS]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTED]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLES]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLED]));
|
||||
|
||||
printf(" RX naks:%u defs:%u dups:%u\n",
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_NACKS]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_DEFERRED]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_DUPLICATES]));
|
||||
|
||||
printf(" TX naks:%u acks:%u dups:%u\n",
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_NACKS]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_ACKS]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_RETRANSMITTED]));
|
||||
|
||||
printf(" Congestion link:%u Send queue max:%u avg:%u\n",
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_LINK_CONGS]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_MAX_QUEUE]),
|
||||
mnl_attr_get_u32(stats[TIPC_NLA_STATS_AVG_QUEUE]));
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int link_stat_show_cb(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
const char *name;
|
||||
const char *link = data;
|
||||
struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
|
||||
struct nlattr *info[TIPC_NLA_MAX + 1] = {};
|
||||
struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1] = {};
|
||||
struct nlattr *prop[TIPC_NLA_PROP_MAX + 1] = {};
|
||||
struct nlattr *stats[TIPC_NLA_STATS_MAX + 1] = {};
|
||||
|
||||
mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
|
||||
if (!info[TIPC_NLA_LINK])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
mnl_attr_parse_nested(info[TIPC_NLA_LINK], parse_attrs, attrs);
|
||||
if (!attrs[TIPC_NLA_LINK_NAME] || !attrs[TIPC_NLA_LINK_PROP] ||
|
||||
!attrs[TIPC_NLA_LINK_STATS])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
mnl_attr_parse_nested(attrs[TIPC_NLA_LINK_PROP], parse_attrs, prop);
|
||||
mnl_attr_parse_nested(attrs[TIPC_NLA_LINK_STATS], parse_attrs, stats);
|
||||
|
||||
name = mnl_attr_get_str(attrs[TIPC_NLA_LINK_NAME]);
|
||||
|
||||
/* If a link is passed, skip all but that link */
|
||||
if (link && (strcmp(name, link) != 0))
|
||||
return MNL_CB_OK;
|
||||
|
||||
if (attrs[TIPC_NLA_LINK_BROADCAST]) {
|
||||
printf("Link <%s>\n", name);
|
||||
return _show_bc_link_stat(prop, stats);
|
||||
}
|
||||
|
||||
printf("\nLink <%s>\n", name);
|
||||
|
||||
return _show_link_stat(attrs, prop, stats);
|
||||
}
|
||||
|
||||
static void cmd_link_stat_show_help(struct cmdl *cmdl)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s link stat show [ link LINK ]\n",
|
||||
cmdl->argv[0]);
|
||||
}
|
||||
|
||||
static int cmd_link_stat_show(struct nlmsghdr *nlh, const struct cmd *cmd,
|
||||
struct cmdl *cmdl, void *data)
|
||||
{
|
||||
char *link = NULL;
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
struct opt *opt;
|
||||
struct opt opts[] = {
|
||||
{ "link", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
if (help_flag) {
|
||||
(cmd->help)(cmdl);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(nlh = msg_init(buf, TIPC_NL_LINK_GET))) {
|
||||
fprintf(stderr, "error, message initialisation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (parse_opts(opts, cmdl) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if ((opt = get_opt(opts, "link")))
|
||||
link = opt->val;
|
||||
|
||||
return msg_dumpit(nlh, link_stat_show_cb, link);
|
||||
}
|
||||
|
||||
static void cmd_link_stat_help(struct cmdl *cmdl)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s link stat COMMAND [ARGS]\n\n"
|
||||
"COMMANDS:\n"
|
||||
" reset - Reset link statistics for link\n"
|
||||
" show - Get link priority\n",
|
||||
cmdl->argv[0]);
|
||||
}
|
||||
|
||||
static int cmd_link_stat(struct nlmsghdr *nlh, const struct cmd *cmd,
|
||||
struct cmdl *cmdl, void *data)
|
||||
{
|
||||
const struct cmd cmds[] = {
|
||||
{ "reset", cmd_link_stat_reset, cmd_link_stat_reset_help },
|
||||
{ "show", cmd_link_stat_show, cmd_link_stat_show_help },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return run_cmd(nlh, cmd, cmds, cmdl, NULL);
|
||||
}
|
||||
|
||||
static void cmd_link_set_help(struct cmdl *cmdl)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s link set PPROPERTY link LINK\n\n"
|
||||
"PROPERTIES\n"
|
||||
" tolerance TOLERANCE - Set link tolerance\n"
|
||||
" priority PRIORITY - Set link priority\n"
|
||||
" window WINDOW - Set link window\n",
|
||||
cmdl->argv[0]);
|
||||
}
|
||||
|
||||
static int cmd_link_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
|
||||
struct cmdl *cmdl, void *data)
|
||||
{
|
||||
int val;
|
||||
int prop;
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
struct nlattr *props;
|
||||
struct nlattr *attrs;
|
||||
struct opt *opt;
|
||||
struct opt opts[] = {
|
||||
{ "link", NULL },
|
||||
{ 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 (help_flag) {
|
||||
(cmd->help)(cmdl);
|
||||
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_LINK_SET))) {
|
||||
fprintf(stderr, "error, message initialisation failed\n");
|
||||
return -1;
|
||||
}
|
||||
attrs = mnl_attr_nest_start(nlh, TIPC_NLA_LINK);
|
||||
|
||||
if (!(opt = get_opt(opts, "link"))) {
|
||||
fprintf(stderr, "error, missing link\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
mnl_attr_put_strz(nlh, TIPC_NLA_LINK_NAME, opt->val);
|
||||
|
||||
props = mnl_attr_nest_start(nlh, TIPC_NLA_LINK_PROP);
|
||||
mnl_attr_put_u32(nlh, prop, val);
|
||||
mnl_attr_nest_end(nlh, props);
|
||||
|
||||
mnl_attr_nest_end(nlh, attrs);
|
||||
|
||||
return msg_doit(nlh, link_get_cb, &prop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_link_set(struct nlmsghdr *nlh, const struct cmd *cmd,
|
||||
struct cmdl *cmdl, void *data)
|
||||
{
|
||||
const struct cmd cmds[] = {
|
||||
{ "priority", cmd_link_set_prop, cmd_link_set_help },
|
||||
{ "tolerance", cmd_link_set_prop, cmd_link_set_help },
|
||||
{ "window", cmd_link_set_prop, cmd_link_set_help },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return run_cmd(nlh, cmd, cmds, cmdl, NULL);
|
||||
}
|
||||
|
||||
void cmd_link_help(struct cmdl *cmdl)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s link COMMAND [ARGS] ...\n"
|
||||
"\n"
|
||||
"COMMANDS\n"
|
||||
" list - List links\n"
|
||||
" get - Get various link properties\n"
|
||||
" set - Set various link properties\n"
|
||||
" statistics - Show or reset statistics\n",
|
||||
cmdl->argv[0]);
|
||||
}
|
||||
|
||||
int cmd_link(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl,
|
||||
void *data)
|
||||
{
|
||||
const struct cmd cmds[] = {
|
||||
{ "get", cmd_link_get, cmd_link_get_help },
|
||||
{ "list", cmd_link_list, NULL },
|
||||
{ "set", cmd_link_set, cmd_link_set_help },
|
||||
{ "statistics", cmd_link_stat, cmd_link_stat_help },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return run_cmd(nlh, cmd, cmds, cmdl, NULL);
|
||||
}
|
21
tipc/link.h
Normal file
21
tipc/link.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* link.c TIPC link 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>
|
||||
*/
|
||||
|
||||
#ifndef _TIPC_LINK_H
|
||||
#define _TIPC_LINK_H
|
||||
|
||||
extern int help_flag;
|
||||
|
||||
int cmd_link(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl,
|
||||
void *data);
|
||||
void cmd_link_help(struct cmdl *cmdl);
|
||||
|
||||
#endif
|
260
tipc/media.c
Normal file
260
tipc/media.c
Normal file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* media.c TIPC link 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 <errno.h>
|
||||
|
||||
#include <linux/tipc_netlink.h>
|
||||
#include <linux/tipc.h>
|
||||
#include <linux/genetlink.h>
|
||||
#include <libmnl/libmnl.h>
|
||||
|
||||
#include "cmdl.h"
|
||||
#include "msg.h"
|
||||
#include "media.h"
|
||||
|
||||
static int media_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_MEDIA_MAX + 1] = {};
|
||||
|
||||
mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
|
||||
if (!info[TIPC_NLA_MEDIA])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
mnl_attr_parse_nested(info[TIPC_NLA_MEDIA], parse_attrs, attrs);
|
||||
if (!attrs[TIPC_NLA_MEDIA_NAME])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
printf("%s\n", mnl_attr_get_str(attrs[TIPC_NLA_MEDIA_NAME]));
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int cmd_media_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 media list\n", cmdl->argv[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(nlh = msg_init(buf, TIPC_NL_MEDIA_GET))) {
|
||||
fprintf(stderr, "error, message initialisation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return msg_dumpit(nlh, media_list_cb, NULL);
|
||||
}
|
||||
|
||||
static int media_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_MEDIA_MAX + 1] = {};
|
||||
struct nlattr *props[TIPC_NLA_PROP_MAX + 1] = {};
|
||||
|
||||
mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
|
||||
if (!info[TIPC_NLA_MEDIA])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
mnl_attr_parse_nested(info[TIPC_NLA_MEDIA], parse_attrs, attrs);
|
||||
if (!attrs[TIPC_NLA_MEDIA_PROP])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
mnl_attr_parse_nested(attrs[TIPC_NLA_MEDIA_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_media_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
|
||||
struct cmdl *cmdl, void *data)
|
||||
{
|
||||
int prop;
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
struct nlattr *nest;
|
||||
struct opt *opt;
|
||||
struct opt opts[] = {
|
||||
{ "media", NULL },
|
||||
{ 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 (help_flag) {
|
||||
(cmd->help)(cmdl);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (parse_opts(opts, cmdl) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!(nlh = msg_init(buf, TIPC_NL_MEDIA_GET))) {
|
||||
fprintf(stderr, "error, message initialisation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(opt = get_opt(opts, "media"))) {
|
||||
fprintf(stderr, "error, missing media\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
nest = mnl_attr_nest_start(nlh, TIPC_NLA_MEDIA);
|
||||
mnl_attr_put_strz(nlh, TIPC_NLA_MEDIA_NAME, opt->val);
|
||||
mnl_attr_nest_end(nlh, nest);
|
||||
|
||||
return msg_doit(nlh, media_get_cb, &prop);
|
||||
}
|
||||
|
||||
static void cmd_media_get_help(struct cmdl *cmdl)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s media get PPROPERTY media MEDIA\n\n"
|
||||
"PROPERTIES\n"
|
||||
" tolerance - Get media tolerance\n"
|
||||
" priority - Get media priority\n"
|
||||
" window - Get media window\n",
|
||||
cmdl->argv[0]);
|
||||
}
|
||||
|
||||
static int cmd_media_get(struct nlmsghdr *nlh, const struct cmd *cmd,
|
||||
struct cmdl *cmdl, void *data)
|
||||
{
|
||||
const struct cmd cmds[] = {
|
||||
{ "priority", cmd_media_get_prop, cmd_media_get_help },
|
||||
{ "tolerance", cmd_media_get_prop, cmd_media_get_help },
|
||||
{ "window", cmd_media_get_prop, cmd_media_get_help },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return run_cmd(nlh, cmd, cmds, cmdl, NULL);
|
||||
}
|
||||
|
||||
static void cmd_media_set_help(struct cmdl *cmdl)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s media set PPROPERTY media MEDIA\n\n"
|
||||
"PROPERTIES\n"
|
||||
" tolerance TOLERANCE - Set media tolerance\n"
|
||||
" priority PRIORITY - Set media priority\n"
|
||||
" window WINDOW - Set media window\n",
|
||||
cmdl->argv[0]);
|
||||
}
|
||||
|
||||
static int cmd_media_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
|
||||
struct cmdl *cmdl, void *data)
|
||||
{
|
||||
int val;
|
||||
int prop;
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
struct nlattr *props;
|
||||
struct nlattr *attrs;
|
||||
struct opt *opt;
|
||||
struct opt opts[] = {
|
||||
{ "media", NULL },
|
||||
{ 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 (help_flag) {
|
||||
(cmd->help)(cmdl);
|
||||
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_MEDIA_SET))) {
|
||||
fprintf(stderr, "error, message initialisation failed\n");
|
||||
return -1;
|
||||
}
|
||||
attrs = mnl_attr_nest_start(nlh, TIPC_NLA_MEDIA);
|
||||
|
||||
if (!(opt = get_opt(opts, "media"))) {
|
||||
fprintf(stderr, "error, missing media\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
mnl_attr_put_strz(nlh, TIPC_NLA_MEDIA_NAME, opt->val);
|
||||
|
||||
props = mnl_attr_nest_start(nlh, TIPC_NLA_MEDIA_PROP);
|
||||
mnl_attr_put_u32(nlh, prop, val);
|
||||
mnl_attr_nest_end(nlh, props);
|
||||
|
||||
mnl_attr_nest_end(nlh, attrs);
|
||||
|
||||
return msg_doit(nlh, NULL, NULL);
|
||||
}
|
||||
|
||||
static int cmd_media_set(struct nlmsghdr *nlh, const struct cmd *cmd,
|
||||
struct cmdl *cmdl, void *data)
|
||||
{
|
||||
const struct cmd cmds[] = {
|
||||
{ "priority", cmd_media_set_prop, cmd_media_set_help },
|
||||
{ "tolerance", cmd_media_set_prop, cmd_media_set_help },
|
||||
{ "window", cmd_media_set_prop, cmd_media_set_help },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return run_cmd(nlh, cmd, cmds, cmdl, NULL);
|
||||
}
|
||||
|
||||
void cmd_media_help(struct cmdl *cmdl)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s media COMMAND [ARGS] ...\n"
|
||||
"\n"
|
||||
"Commands:\n"
|
||||
" list - List active media types\n"
|
||||
" get - Get various media properties\n"
|
||||
" set - Set various media properties\n",
|
||||
cmdl->argv[0]);
|
||||
}
|
||||
|
||||
int cmd_media(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl,
|
||||
void *data)
|
||||
{
|
||||
const struct cmd cmds[] = {
|
||||
{ "get", cmd_media_get, cmd_media_get_help },
|
||||
{ "list", cmd_media_list, NULL },
|
||||
{ "set", cmd_media_set, cmd_media_set_help },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return run_cmd(nlh, cmd, cmds, cmdl, NULL);
|
||||
}
|
21
tipc/media.h
Normal file
21
tipc/media.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* media.h TIPC link 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>
|
||||
*/
|
||||
|
||||
#ifndef _TIPC_MEDIA_H
|
||||
#define _TIPC_MEDIA_H
|
||||
|
||||
extern int help_flag;
|
||||
|
||||
int cmd_media(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl,
|
||||
void *data);
|
||||
void cmd_media_help(struct cmdl *cmdl);
|
||||
|
||||
#endif
|
35
tipc/misc.c
Normal file
35
tipc/misc.c
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* misc.c Miscellaneous TIPC helper functions.
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <linux/tipc.h>
|
||||
|
||||
#include "misc.h"
|
||||
|
||||
#define IN_RANGE(val, low, high) ((val) <= (high) && (val) >= (low))
|
||||
|
||||
uint32_t str2addr(char *str)
|
||||
{
|
||||
unsigned int z, c, n;
|
||||
char dummy;
|
||||
|
||||
if (sscanf(str, "%u.%u.%u%c", &z, &c, &n, &dummy) != 3) {
|
||||
fprintf(stderr, "invalid network address, syntax: Z.C.N\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (IN_RANGE(z, 0, 255) && IN_RANGE(c, 0, 4095) && IN_RANGE(n, 0, 4095))
|
||||
return tipc_addr(z, c, n);
|
||||
|
||||
fprintf(stderr, "invalid network address \"%s\"\n", str);
|
||||
return 0;
|
||||
}
|
19
tipc/misc.h
Normal file
19
tipc/misc.h
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* misc.h Miscellaneous TIPC helper functions.
|
||||
*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#ifndef _TIPC_MISC_H
|
||||
#define _TIPC_MISC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint32_t str2addr(char *str);
|
||||
|
||||
#endif
|
170
tipc/msg.c
Normal file
170
tipc/msg.c
Normal file
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* msg.c Messaging (netlink) helper functions.
|
||||
*
|
||||
* 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 <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <linux/tipc_netlink.h>
|
||||
#include <linux/tipc.h>
|
||||
#include <linux/genetlink.h>
|
||||
#include <libmnl/libmnl.h>
|
||||
|
||||
#include "msg.h"
|
||||
|
||||
int parse_attrs(const struct nlattr *attr, void *data)
|
||||
{
|
||||
const struct nlattr **tb = data;
|
||||
int type = mnl_attr_get_type(attr);
|
||||
|
||||
tb[type] = attr;
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int family_id_cb(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
struct nlattr *tb[CTRL_ATTR_MAX + 1] = {};
|
||||
struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
|
||||
int *id = data;
|
||||
|
||||
mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, tb);
|
||||
if (!tb[CTRL_ATTR_FAMILY_ID])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
*id = mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static struct mnl_socket *msg_send(struct nlmsghdr *nlh)
|
||||
{
|
||||
int ret;
|
||||
struct mnl_socket *nl;
|
||||
|
||||
nl = mnl_socket_open(NETLINK_GENERIC);
|
||||
if (nl == NULL) {
|
||||
perror("mnl_socket_open");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID);
|
||||
if (ret < 0) {
|
||||
perror("mnl_socket_bind");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = mnl_socket_sendto(nl, nlh, nlh->nlmsg_len);
|
||||
if (ret < 0) {
|
||||
perror("mnl_socket_send");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return nl;
|
||||
}
|
||||
|
||||
static int msg_recv(struct mnl_socket *nl, mnl_cb_t callback, void *data, int seq)
|
||||
{
|
||||
int ret;
|
||||
unsigned int portid;
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
|
||||
portid = mnl_socket_get_portid(nl);
|
||||
|
||||
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
||||
while (ret > 0) {
|
||||
ret = mnl_cb_run(buf, ret, seq, portid, callback, data);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
||||
}
|
||||
if (ret == -1)
|
||||
perror("error");
|
||||
|
||||
mnl_socket_close(nl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msg_query(struct nlmsghdr *nlh, mnl_cb_t callback, void *data)
|
||||
{
|
||||
unsigned int seq;
|
||||
struct mnl_socket *nl;
|
||||
|
||||
seq = time(NULL);
|
||||
nlh->nlmsg_seq = seq;
|
||||
|
||||
nl = msg_send(nlh);
|
||||
if (!nl)
|
||||
return -ENOTSUP;
|
||||
|
||||
return msg_recv(nl, callback, data, seq);
|
||||
}
|
||||
|
||||
static int get_family(void)
|
||||
{
|
||||
int err;
|
||||
int nl_family;
|
||||
struct nlmsghdr *nlh;
|
||||
struct genlmsghdr *genl;
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
|
||||
nlh = mnl_nlmsg_put_header(buf);
|
||||
nlh->nlmsg_type = GENL_ID_CTRL;
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
|
||||
genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
|
||||
genl->cmd = CTRL_CMD_GETFAMILY;
|
||||
genl->version = 1;
|
||||
|
||||
mnl_attr_put_u32(nlh, CTRL_ATTR_FAMILY_ID, GENL_ID_CTRL);
|
||||
mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, TIPC_GENL_V2_NAME);
|
||||
|
||||
if ((err = msg_query(nlh, family_id_cb, &nl_family)))
|
||||
return err;
|
||||
|
||||
return nl_family;
|
||||
}
|
||||
|
||||
int msg_doit(struct nlmsghdr *nlh, mnl_cb_t callback, void *data)
|
||||
{
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
return msg_query(nlh, callback, data);
|
||||
}
|
||||
|
||||
int msg_dumpit(struct nlmsghdr *nlh, mnl_cb_t callback, void *data)
|
||||
{
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
|
||||
return msg_query(nlh, callback, data);
|
||||
}
|
||||
|
||||
struct nlmsghdr *msg_init(char *buf, int cmd)
|
||||
{
|
||||
int family;
|
||||
struct nlmsghdr *nlh;
|
||||
struct genlmsghdr *genl;
|
||||
|
||||
family = get_family();
|
||||
if (family <= 0) {
|
||||
fprintf(stderr,
|
||||
"Unable to get TIPC nl family id (module loaded?)\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nlh = mnl_nlmsg_put_header(buf);
|
||||
nlh->nlmsg_type = family;
|
||||
|
||||
genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
|
||||
genl->cmd = cmd;
|
||||
genl->version = 1;
|
||||
|
||||
return nlh;
|
||||
}
|
20
tipc/msg.h
Normal file
20
tipc/msg.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* msg.h Messaging (netlink) helper functions.
|
||||
*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#ifndef _TIPC_MSG_H
|
||||
#define _TIPC_MSG_H
|
||||
|
||||
struct nlmsghdr *msg_init(char *buf, int cmd);
|
||||
int msg_doit(struct nlmsghdr *nlh, mnl_cb_t callback, void *data);
|
||||
int msg_dumpit(struct nlmsghdr *nlh, mnl_cb_t callback, void *data);
|
||||
int parse_attrs(const struct nlattr *attr, void *data);
|
||||
|
||||
#endif
|
109
tipc/nametable.c
Normal file
109
tipc/nametable.c
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* nametable.c TIPC nametable 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 <errno.h>
|
||||
|
||||
#include <linux/tipc_netlink.h>
|
||||
#include <linux/tipc.h>
|
||||
#include <linux/genetlink.h>
|
||||
#include <libmnl/libmnl.h>
|
||||
|
||||
#include "cmdl.h"
|
||||
#include "msg.h"
|
||||
#include "nametable.h"
|
||||
|
||||
#define PORTID_STR_LEN 45 /* Four u32 and five delimiter chars */
|
||||
|
||||
static int nametable_show_cb(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
int *iteration = data;
|
||||
char port_id[PORTID_STR_LEN];
|
||||
struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
|
||||
struct nlattr *info[TIPC_NLA_MAX + 1] = {};
|
||||
struct nlattr *attrs[TIPC_NLA_NAME_TABLE_MAX + 1] = {};
|
||||
struct nlattr *publ[TIPC_NLA_PUBL_MAX + 1] = {};
|
||||
const char *scope[] = { "", "zone", "cluster", "node" };
|
||||
|
||||
mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
|
||||
if (!info[TIPC_NLA_NAME_TABLE])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
mnl_attr_parse_nested(info[TIPC_NLA_NAME_TABLE], parse_attrs, attrs);
|
||||
if (!attrs[TIPC_NLA_NAME_TABLE_PUBL])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
mnl_attr_parse_nested(attrs[TIPC_NLA_NAME_TABLE_PUBL], parse_attrs, publ);
|
||||
if (!publ[TIPC_NLA_NAME_TABLE_PUBL])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
if (!*iteration)
|
||||
printf("%-10s %-10s %-10s %-26s %-10s\n",
|
||||
"Type", "Lower", "Upper", "Port Identity",
|
||||
"Publication Scope");
|
||||
(*iteration)++;
|
||||
|
||||
snprintf(port_id, sizeof(port_id), "<%u.%u.%u:%u>",
|
||||
tipc_zone(mnl_attr_get_u32(publ[TIPC_NLA_PUBL_NODE])),
|
||||
tipc_cluster(mnl_attr_get_u32(publ[TIPC_NLA_PUBL_NODE])),
|
||||
tipc_node(mnl_attr_get_u32(publ[TIPC_NLA_PUBL_NODE])),
|
||||
mnl_attr_get_u32(publ[TIPC_NLA_PUBL_REF]));
|
||||
|
||||
printf("%-10u %-10u %-10u %-26s %-12u",
|
||||
mnl_attr_get_u32(publ[TIPC_NLA_PUBL_TYPE]),
|
||||
mnl_attr_get_u32(publ[TIPC_NLA_PUBL_LOWER]),
|
||||
mnl_attr_get_u32(publ[TIPC_NLA_PUBL_UPPER]),
|
||||
port_id,
|
||||
mnl_attr_get_u32(publ[TIPC_NLA_PUBL_KEY]));
|
||||
|
||||
printf("%s\n", scope[mnl_attr_get_u32(publ[TIPC_NLA_PUBL_SCOPE])]);
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int cmd_nametable_show(struct nlmsghdr *nlh, const struct cmd *cmd,
|
||||
struct cmdl *cmdl, void *data)
|
||||
{
|
||||
int iteration = 0;
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
|
||||
if (help_flag) {
|
||||
fprintf(stderr, "Usage: %s nametable show\n", cmdl->argv[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(nlh = msg_init(buf, TIPC_NL_NAME_TABLE_GET))) {
|
||||
fprintf(stderr, "error, message initialisation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return msg_dumpit(nlh, nametable_show_cb, &iteration);
|
||||
}
|
||||
|
||||
void cmd_nametable_help(struct cmdl *cmdl)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s nametable COMMAND\n\n"
|
||||
"COMMANDS\n"
|
||||
" show - Show nametable\n",
|
||||
cmdl->argv[0]);
|
||||
}
|
||||
|
||||
int cmd_nametable(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl,
|
||||
void *data)
|
||||
{
|
||||
const struct cmd cmds[] = {
|
||||
{ "show", cmd_nametable_show, NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return run_cmd(nlh, cmd, cmds, cmdl, NULL);
|
||||
}
|
21
tipc/nametable.h
Normal file
21
tipc/nametable.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* nametable.h TIPC nametable 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>
|
||||
*/
|
||||
|
||||
#ifndef _TIPC_NAMETABLE_H
|
||||
#define _TIPC_NAMETABLE_H
|
||||
|
||||
extern int help_flag;
|
||||
|
||||
void cmd_nametable_help(struct cmdl *cmdl);
|
||||
int cmd_nametable(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl,
|
||||
void *data);
|
||||
|
||||
#endif
|
267
tipc/node.c
Normal file
267
tipc/node.c
Normal file
@ -0,0 +1,267 @@
|
||||
/*
|
||||
* node.c TIPC node 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 <errno.h>
|
||||
|
||||
#include <linux/tipc_netlink.h>
|
||||
#include <linux/tipc.h>
|
||||
#include <linux/genetlink.h>
|
||||
#include <libmnl/libmnl.h>
|
||||
|
||||
#include "cmdl.h"
|
||||
#include "msg.h"
|
||||
#include "misc.h"
|
||||
#include "node.h"
|
||||
|
||||
static int node_list_cb(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
uint32_t addr;
|
||||
struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
|
||||
struct nlattr *info[TIPC_NLA_MAX + 1] = {};
|
||||
struct nlattr *attrs[TIPC_NLA_NODE_MAX + 1] = {};
|
||||
|
||||
mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
|
||||
if (!info[TIPC_NLA_NODE])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
mnl_attr_parse_nested(info[TIPC_NLA_NODE], parse_attrs, attrs);
|
||||
if (!attrs[TIPC_NLA_NODE_ADDR])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
addr = mnl_attr_get_u32(attrs[TIPC_NLA_NODE_ADDR]);
|
||||
printf("<%u.%u.%u>: ",
|
||||
tipc_zone(addr),
|
||||
tipc_cluster(addr),
|
||||
tipc_node(addr));
|
||||
|
||||
if (attrs[TIPC_NLA_NODE_UP])
|
||||
printf("up\n");
|
||||
else
|
||||
printf("down\n");
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int cmd_node_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 node list\n", cmdl->argv[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(nlh = msg_init(buf, TIPC_NL_NODE_GET))) {
|
||||
fprintf(stderr, "error, message initialisation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return msg_dumpit(nlh, node_list_cb, NULL);
|
||||
}
|
||||
|
||||
static int cmd_node_set_addr(struct nlmsghdr *nlh, const struct cmd *cmd,
|
||||
struct cmdl *cmdl, void *data)
|
||||
{
|
||||
char *str;
|
||||
uint32_t addr;
|
||||
struct nlattr *nest;
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
|
||||
if (cmdl->argc != cmdl->optind + 1) {
|
||||
fprintf(stderr, "Usage: %s node set address ADDRESS\n",
|
||||
cmdl->argv[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
str = shift_cmdl(cmdl);
|
||||
addr = str2addr(str);
|
||||
if (!addr)
|
||||
return -1;
|
||||
|
||||
if (!(nlh = msg_init(buf, TIPC_NL_NET_SET))) {
|
||||
fprintf(stderr, "error, message initialisation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
nest = mnl_attr_nest_start(nlh, TIPC_NLA_NET);
|
||||
mnl_attr_put_u32(nlh, TIPC_NLA_NET_ADDR, addr);
|
||||
mnl_attr_nest_end(nlh, nest);
|
||||
|
||||
return msg_doit(nlh, NULL, NULL);
|
||||
}
|
||||
|
||||
static int cmd_node_get_addr(struct nlmsghdr *nlh, const struct cmd *cmd,
|
||||
struct cmdl *cmdl, void *data)
|
||||
{
|
||||
int sk;
|
||||
socklen_t sz = sizeof(struct sockaddr_tipc);
|
||||
struct sockaddr_tipc addr;
|
||||
|
||||
if (!(sk = socket(AF_TIPC, SOCK_RDM, 0))) {
|
||||
fprintf(stderr, "opening TIPC socket: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (getsockname(sk, (struct sockaddr *)&addr, &sz) < 0) {
|
||||
fprintf(stderr, "getting TIPC socket address: %s\n",
|
||||
strerror(errno));
|
||||
close(sk);
|
||||
return -1;
|
||||
}
|
||||
close(sk);
|
||||
|
||||
printf("<%u.%u.%u>\n",
|
||||
tipc_zone(addr.addr.id.node),
|
||||
tipc_cluster(addr.addr.id.node),
|
||||
tipc_node(addr.addr.id.node));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netid_get_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] = {};
|
||||
|
||||
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;
|
||||
|
||||
printf("%u\n", mnl_attr_get_u32(attrs[TIPC_NLA_NET_ID]));
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int cmd_node_get_netid(struct nlmsghdr *nlh, const struct cmd *cmd,
|
||||
struct cmdl *cmdl, void *data)
|
||||
{
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
|
||||
if (help_flag) {
|
||||
(cmd->help)(cmdl);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(nlh = msg_init(buf, TIPC_NL_NET_GET))) {
|
||||
fprintf(stderr, "error, message initialisation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return msg_dumpit(nlh, netid_get_cb, NULL);
|
||||
}
|
||||
|
||||
static int cmd_node_set_netid(struct nlmsghdr *nlh, const struct cmd *cmd,
|
||||
struct cmdl *cmdl, void *data)
|
||||
{
|
||||
int netid;
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
struct nlattr *nest;
|
||||
|
||||
if (help_flag) {
|
||||
(cmd->help)(cmdl);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(nlh = msg_init(buf, TIPC_NL_NET_SET))) {
|
||||
fprintf(stderr, "error, message initialisation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cmdl->argc != cmdl->optind + 1) {
|
||||
fprintf(stderr, "Usage: %s node set netid NETID\n",
|
||||
cmdl->argv[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
netid = atoi(shift_cmdl(cmdl));
|
||||
|
||||
nest = mnl_attr_nest_start(nlh, TIPC_NLA_NET);
|
||||
mnl_attr_put_u32(nlh, TIPC_NLA_NET_ID, netid);
|
||||
mnl_attr_nest_end(nlh, nest);
|
||||
|
||||
return msg_doit(nlh, NULL, NULL);
|
||||
}
|
||||
|
||||
static void cmd_node_set_help(struct cmdl *cmdl)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s node set PROPERTY\n\n"
|
||||
"PROPERTIES\n"
|
||||
" address ADDRESS - Set local address\n"
|
||||
" netid NETID - Set local netid\n",
|
||||
cmdl->argv[0]);
|
||||
}
|
||||
|
||||
static int cmd_node_set(struct nlmsghdr *nlh, const struct cmd *cmd,
|
||||
struct cmdl *cmdl, void *data)
|
||||
{
|
||||
const struct cmd cmds[] = {
|
||||
{ "address", cmd_node_set_addr, NULL },
|
||||
{ "netid", cmd_node_set_netid, NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return run_cmd(nlh, cmd, cmds, cmdl, NULL);
|
||||
}
|
||||
|
||||
static void cmd_node_get_help(struct cmdl *cmdl)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s node get PROPERTY\n\n"
|
||||
"PROPERTIES\n"
|
||||
" address - Get local address\n"
|
||||
" netid - Get local netid\n",
|
||||
cmdl->argv[0]);
|
||||
}
|
||||
|
||||
static int cmd_node_get(struct nlmsghdr *nlh, const struct cmd *cmd,
|
||||
struct cmdl *cmdl, void *data)
|
||||
{
|
||||
const struct cmd cmds[] = {
|
||||
{ "address", cmd_node_get_addr, NULL },
|
||||
{ "netid", cmd_node_get_netid, NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return run_cmd(nlh, cmd, cmds, cmdl, NULL);
|
||||
}
|
||||
|
||||
void cmd_node_help(struct cmdl *cmdl)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s media COMMAND [ARGS] ...\n\n"
|
||||
"COMMANDS\n"
|
||||
" list - List remote nodes\n"
|
||||
" get - Get local node parameters\n"
|
||||
" set - Set local node parameters\n",
|
||||
cmdl->argv[0]);
|
||||
}
|
||||
|
||||
int cmd_node(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl,
|
||||
void *data)
|
||||
{
|
||||
const struct cmd cmds[] = {
|
||||
{ "list", cmd_node_list, NULL },
|
||||
{ "get", cmd_node_get, cmd_node_get_help },
|
||||
{ "set", cmd_node_set, cmd_node_set_help },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return run_cmd(nlh, cmd, cmds, cmdl, NULL);
|
||||
}
|
21
tipc/node.h
Normal file
21
tipc/node.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* node.h TIPC node 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>
|
||||
*/
|
||||
|
||||
#ifndef _TIPC_NODE_H
|
||||
#define _TIPC_NODE_H
|
||||
|
||||
extern int help_flag;
|
||||
|
||||
int cmd_node(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl,
|
||||
void *data);
|
||||
void cmd_node_help(struct cmdl *cmdl);
|
||||
|
||||
#endif
|
140
tipc/socket.c
Normal file
140
tipc/socket.c
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* socket.c TIPC socket 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 <errno.h>
|
||||
|
||||
#include <linux/tipc.h>
|
||||
#include <linux/tipc_netlink.h>
|
||||
#include <linux/genetlink.h>
|
||||
#include <libmnl/libmnl.h>
|
||||
|
||||
#include "cmdl.h"
|
||||
#include "msg.h"
|
||||
#include "socket.h"
|
||||
|
||||
#define PORTID_STR_LEN 45 /* Four u32 and five delimiter chars */
|
||||
|
||||
static int publ_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_SOCK_MAX + 1] = {};
|
||||
|
||||
mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
|
||||
if (!info[TIPC_NLA_PUBL])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
mnl_attr_parse_nested(info[TIPC_NLA_PUBL], parse_attrs, attrs);
|
||||
|
||||
printf(" bound to {%u,%u,%u}\n",
|
||||
mnl_attr_get_u32(attrs[TIPC_NLA_PUBL_TYPE]),
|
||||
mnl_attr_get_u32(attrs[TIPC_NLA_PUBL_LOWER]),
|
||||
mnl_attr_get_u32(attrs[TIPC_NLA_PUBL_UPPER]));
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int publ_list(uint32_t sock)
|
||||
{
|
||||
struct nlmsghdr *nlh;
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
struct nlattr *nest;
|
||||
|
||||
if (!(nlh = msg_init(buf, TIPC_NL_PUBL_GET))) {
|
||||
fprintf(stderr, "error, message initialisation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
nest = mnl_attr_nest_start(nlh, TIPC_NLA_SOCK);
|
||||
mnl_attr_put_u32(nlh, TIPC_NLA_SOCK_REF, sock);
|
||||
mnl_attr_nest_end(nlh, nest);
|
||||
|
||||
return msg_dumpit(nlh, publ_list_cb, NULL);
|
||||
}
|
||||
|
||||
static int sock_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_SOCK_MAX + 1] = {};
|
||||
|
||||
mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
|
||||
if (!info[TIPC_NLA_SOCK])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
mnl_attr_parse_nested(info[TIPC_NLA_SOCK], parse_attrs, attrs);
|
||||
if (!attrs[TIPC_NLA_SOCK_REF])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
printf("socket %u\n", mnl_attr_get_u32(attrs[TIPC_NLA_SOCK_REF]));
|
||||
|
||||
if (attrs[TIPC_NLA_SOCK_CON]) {
|
||||
uint32_t node;
|
||||
struct nlattr *con[TIPC_NLA_CON_MAX + 1] = {};
|
||||
|
||||
mnl_attr_parse_nested(attrs[TIPC_NLA_SOCK_CON], parse_attrs, con);
|
||||
node = mnl_attr_get_u32(con[TIPC_NLA_CON_NODE]);
|
||||
|
||||
printf(" connected to <%u.%u.%u:%u>", tipc_zone(node),
|
||||
tipc_cluster(node), tipc_node(node),
|
||||
mnl_attr_get_u32(con[TIPC_NLA_CON_SOCK]));
|
||||
|
||||
if (con[TIPC_NLA_CON_FLAG])
|
||||
printf(" via {%u,%u}\n",
|
||||
mnl_attr_get_u32(con[TIPC_NLA_CON_TYPE]),
|
||||
mnl_attr_get_u32(con[TIPC_NLA_CON_INST]));
|
||||
else
|
||||
printf("\n");
|
||||
} else if (attrs[TIPC_NLA_SOCK_HAS_PUBL]) {
|
||||
publ_list(mnl_attr_get_u32(attrs[TIPC_NLA_SOCK_REF]));
|
||||
}
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int cmd_socket_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 socket list\n", cmdl->argv[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(nlh = msg_init(buf, TIPC_NL_SOCK_GET))) {
|
||||
fprintf(stderr, "error, message initialisation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return msg_dumpit(nlh, sock_list_cb, NULL);
|
||||
}
|
||||
|
||||
void cmd_socket_help(struct cmdl *cmdl)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s socket COMMAND\n\n"
|
||||
"Commands:\n"
|
||||
" list - List sockets (ports)\n",
|
||||
cmdl->argv[0]);
|
||||
}
|
||||
|
||||
int cmd_socket(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl,
|
||||
void *data)
|
||||
{
|
||||
const struct cmd cmds[] = {
|
||||
{ "list", cmd_socket_list, NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return run_cmd(nlh, cmd, cmds, cmdl, NULL);
|
||||
}
|
21
tipc/socket.h
Normal file
21
tipc/socket.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* socket.h TIPC socket 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>
|
||||
*/
|
||||
|
||||
#ifndef _TIPC_SOCKET_H
|
||||
#define _TIPC_SOCKET_H
|
||||
|
||||
extern int help_flag;
|
||||
|
||||
void cmd_socket_help(struct cmdl *cmdl);
|
||||
int cmd_socket(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl,
|
||||
void *data);
|
||||
|
||||
#endif
|
96
tipc/tipc.c
Normal file
96
tipc/tipc.c
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* tipc. TIPC utility frontend.
|
||||
*
|
||||
* 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 <getopt.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "bearer.h"
|
||||
#include "link.h"
|
||||
#include "nametable.h"
|
||||
#include "socket.h"
|
||||
#include "media.h"
|
||||
#include "node.h"
|
||||
#include "cmdl.h"
|
||||
|
||||
int help_flag;
|
||||
|
||||
static void about(struct cmdl *cmdl)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Transparent Inter-Process Communication Protocol\n"
|
||||
"Usage: %s [OPTIONS] COMMAND [ARGS] ...\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -h, --help \t\tPrint help for last given command\n"
|
||||
"\n"
|
||||
"Commands:\n"
|
||||
" bearer - Show or modify bearers\n"
|
||||
" link - Show or modify links\n"
|
||||
" media - Show or modify media\n"
|
||||
" nametable - Show nametable\n"
|
||||
" node - Show or modify node related parameters\n"
|
||||
" socket - Show sockets\n",
|
||||
cmdl->argv[0]);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
int res;
|
||||
struct cmdl cmdl;
|
||||
const struct cmd cmd = {"tipc", NULL, about};
|
||||
struct option long_options[] = {
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
const struct cmd cmds[] = {
|
||||
{ "bearer", cmd_bearer, cmd_bearer_help},
|
||||
{ "link", cmd_link, cmd_link_help},
|
||||
{ "media", cmd_media, cmd_media_help},
|
||||
{ "nametable", cmd_nametable, cmd_nametable_help},
|
||||
{ "node", cmd_node, cmd_node_help},
|
||||
{ "socket", cmd_socket, cmd_socket_help},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
do {
|
||||
int option_index = 0;
|
||||
|
||||
i = getopt_long(argc, argv, "h", long_options, &option_index);
|
||||
|
||||
switch (i) {
|
||||
case 'h':
|
||||
/*
|
||||
* We want the help for the last command, so we flag
|
||||
* here in order to print later.
|
||||
*/
|
||||
help_flag = 1;
|
||||
break;
|
||||
case -1:
|
||||
/* End of options */
|
||||
break;
|
||||
default:
|
||||
/* Invalid option, error msg is printed by getopts */
|
||||
return 1;
|
||||
}
|
||||
} while (i != -1);
|
||||
|
||||
cmdl.optind = optind;
|
||||
cmdl.argc = argc;
|
||||
cmdl.argv = argv;
|
||||
|
||||
if ((res = run_cmd(NULL, &cmd, cmds, &cmdl, NULL)) != 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user