Commit f9b00402 authored by Stephen Hemminger's avatar Stephen Hemminger

Merge branch 'master' into net-next

parents 8f42ceaf 2631b856
......@@ -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)
......
/*
* 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;
......
......@@ -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.
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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);
......
## -- 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 \
......
#!/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
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)
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.
This diff is collapsed.
/*
* 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
/*
* 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);
}
/*
* 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
This diff is collapsed.
/*
* 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
/*
* 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);
}
/*
* 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
/*
* 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;
}
/*
* 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
/*
* 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;
}
/*
* 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
/*
* 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);
}
/*
* 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
/*
* 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);
}
/*
* 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
/*
* 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);
}
/*
* 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
/*
* 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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment