Merge branch 'master' into net-next
diff --git a/bridge/vlan.c b/bridge/vlan.c
index d3505b5..0b6c690 100644
--- a/bridge/vlan.c
+++ b/bridge/vlan.c
@@ -15,14 +15,16 @@
#include "utils.h"
static unsigned int filter_index, filter_vlan;
+static int last_ifidx = -1;
json_writer_t *jw_global = NULL;
static void usage(void)
{
- fprintf(stderr, "Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ pvid] [ untagged ]\n");
+ fprintf(stderr, "Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ pvid ] [ untagged ]\n");
fprintf(stderr, " [ self ] [ master ]\n");
fprintf(stderr, " bridge vlan { show } [ dev DEV ] [ vid VLAN_ID ]\n");
+ fprintf(stderr, " bridge vlan { stats } [ dev DEV ] [ vid VLAN_ID ]\n");
exit(-1);
}
@@ -298,6 +300,88 @@
return 0;
}
+static void print_one_vlan_stats(FILE *fp,
+ const struct bridge_vlan_xstats *vstats,
+ int ifindex)
+{
+ const char *ifname = "";
+
+ if (filter_vlan && filter_vlan != vstats->vid)
+ return;
+ /* skip pure port entries, they'll be dumped via the slave stats call */
+ if ((vstats->flags & BRIDGE_VLAN_INFO_MASTER) &&
+ !(vstats->flags & BRIDGE_VLAN_INFO_BRENTRY))
+ return;
+
+ if (last_ifidx != ifindex) {
+ ifname = ll_index_to_name(ifindex);
+ last_ifidx = ifindex;
+ }
+ fprintf(fp, "%-16s %hu", ifname, vstats->vid);
+ if (vstats->flags & BRIDGE_VLAN_INFO_PVID)
+ fprintf(fp, " PVID");
+ if (vstats->flags & BRIDGE_VLAN_INFO_UNTAGGED)
+ fprintf(fp, " Egress Untagged");
+ fprintf(fp, "\n");
+ fprintf(fp, "%-16s RX: %llu bytes %llu packets\n",
+ "", vstats->rx_bytes, vstats->rx_packets);
+ fprintf(fp, "%-16s TX: %llu bytes %llu packets\n",
+ "", vstats->tx_bytes, vstats->tx_packets);
+}
+
+static void print_vlan_stats_attr(FILE *fp, struct rtattr *attr, int ifindex)
+{
+ struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1];
+ struct rtattr *i, *list;
+ int rem;
+
+ parse_rtattr(brtb, LINK_XSTATS_TYPE_MAX, RTA_DATA(attr),
+ RTA_PAYLOAD(attr));
+ if (!brtb[LINK_XSTATS_TYPE_BRIDGE])
+ return;
+
+ list = brtb[LINK_XSTATS_TYPE_BRIDGE];
+ rem = RTA_PAYLOAD(list);
+ for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+ if (i->rta_type != BRIDGE_XSTATS_VLAN)
+ continue;
+ print_one_vlan_stats(fp, RTA_DATA(i), ifindex);
+ }
+}
+
+static int print_vlan_stats(const struct sockaddr_nl *who,
+ struct nlmsghdr *n,
+ void *arg)
+{
+ struct if_stats_msg *ifsm = NLMSG_DATA(n);
+ struct rtattr *tb[IFLA_STATS_MAX+1];
+ int len = n->nlmsg_len;
+ FILE *fp = arg;
+
+ len -= NLMSG_LENGTH(sizeof(*ifsm));
+ if (len < 0) {
+ fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+ return -1;
+ }
+
+ if (filter_index && filter_index != ifsm->ifindex)
+ return 0;
+
+ parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len);
+
+ /* We have to check if any of the two attrs are usable */
+ if (tb[IFLA_STATS_LINK_XSTATS])
+ print_vlan_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS],
+ ifsm->ifindex);
+
+ if (tb[IFLA_STATS_LINK_XSTATS_SLAVE])
+ print_vlan_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS_SLAVE],
+ ifsm->ifindex);
+
+ fflush(fp);
+ return 0;
+}
+
static int vlan_show(int argc, char **argv)
{
char *filter_dev = NULL;
@@ -325,28 +409,58 @@
}
}
- if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK,
- (compress_vlans ?
- RTEXT_FILTER_BRVLAN_COMPRESSED :
- RTEXT_FILTER_BRVLAN)) < 0) {
- perror("Cannont send dump request");
- exit(1);
- }
-
- if (json_output) {
- jw_global = jsonw_new(stdout);
- if (!jw_global) {
- fprintf(stderr, "Error allocation json object\n");
+ if (!show_stats) {
+ if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK,
+ (compress_vlans ?
+ RTEXT_FILTER_BRVLAN_COMPRESSED :
+ RTEXT_FILTER_BRVLAN)) < 0) {
+ perror("Cannont send dump request");
exit(1);
}
- jsonw_start_object(jw_global);
- } else {
- printf("port\tvlan ids\n");
- }
+ if (json_output) {
+ jw_global = jsonw_new(stdout);
+ if (!jw_global) {
+ fprintf(stderr, "Error allocation json object\n");
+ exit(1);
+ }
+ jsonw_start_object(jw_global);
+ } else {
+ printf("port\tvlan ids\n");
+ }
- if (rtnl_dump_filter(&rth, print_vlan, stdout) < 0) {
- fprintf(stderr, "Dump ternminated\n");
- exit(1);
+ if (rtnl_dump_filter(&rth, print_vlan, stdout) < 0) {
+ fprintf(stderr, "Dump ternminated\n");
+ exit(1);
+ }
+ } else {
+ __u32 filt_mask;
+
+ filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS);
+ if (rtnl_wilddump_stats_req_filter(&rth, AF_UNSPEC,
+ RTM_GETSTATS,
+ filt_mask) < 0) {
+ perror("Cannont send dump request");
+ exit(1);
+ }
+
+ printf("%-16s vlan id\n", "port");
+ if (rtnl_dump_filter(&rth, print_vlan_stats, stdout) < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ exit(1);
+ }
+
+ filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS_SLAVE);
+ if (rtnl_wilddump_stats_req_filter(&rth, AF_UNSPEC,
+ RTM_GETSTATS,
+ filt_mask) < 0) {
+ perror("Cannont send slave dump request");
+ exit(1);
+ }
+
+ if (rtnl_dump_filter(&rth, print_vlan_stats, stdout) < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ exit(1);
+ }
}
if (jw_global) {
@@ -357,7 +471,6 @@
return 0;
}
-
int do_vlan(int argc, char **argv)
{
ll_init_map(&rth);
@@ -373,8 +486,9 @@
return vlan_show(argc-1, argv+1);
if (matches(*argv, "help") == 0)
usage();
- } else
+ } else {
return vlan_show(0, NULL);
+ }
fprintf(stderr, "Command \"%s\" is unknown, try \"bridge vlan help\".\n", *argv);
exit(-1);
diff --git a/include/libnetlink.h b/include/libnetlink.h
index f7b85dc..483509c 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -44,6 +44,9 @@
int rtnl_wilddump_req_filter_fn(struct rtnl_handle *rth, int fam, int type,
req_filter_fn_t fn)
__attribute__((warn_unused_result));
+int rtnl_wilddump_stats_req_filter(struct rtnl_handle *rth, int fam, int type,
+ __u32 filt_mask)
+ __attribute__((warn_unused_result));
int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req,
int len)
__attribute__((warn_unused_result));
@@ -202,6 +205,11 @@
#define NETNS_PAYLOAD(n) NLMSG_PAYLOAD(n, sizeof(struct rtgenmsg))
#endif
+#ifndef IFLA_STATS_RTA
+#define IFLA_STATS_RTA(r) \
+ ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct if_stats_msg))))
+#endif
+
/* User defined nlmsg_type which is used mostly for logging netlink
* messages from dump file */
#define NLMSG_TSTAMP 15
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 766db7f..d4a6e1f 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -95,6 +95,7 @@
BPF_PROG_TYPE_SCHED_ACT,
BPF_PROG_TYPE_TRACEPOINT,
BPF_PROG_TYPE_XDP,
+ BPF_PROG_TYPE_PERF_EVENT,
};
#define BPF_PSEUDO_MAP_FD 1
@@ -375,6 +376,56 @@
*/
BPF_FUNC_probe_write_user,
+ /**
+ * bpf_current_task_under_cgroup(map, index) - Check cgroup2 membership of current task
+ * @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type
+ * @index: index of the cgroup in the bpf_map
+ * Return:
+ * == 0 current failed the cgroup2 descendant test
+ * == 1 current succeeded the cgroup2 descendant test
+ * < 0 error
+ */
+ BPF_FUNC_current_task_under_cgroup,
+
+ /**
+ * bpf_skb_change_tail(skb, len, flags)
+ * The helper will resize the skb to the given new size,
+ * to be used f.e. with control messages.
+ * @skb: pointer to skb
+ * @len: new skb length
+ * @flags: reserved
+ * Return: 0 on success or negative error
+ */
+ BPF_FUNC_skb_change_tail,
+
+ /**
+ * bpf_skb_pull_data(skb, len)
+ * The helper will pull in non-linear data in case the
+ * skb is non-linear and not all of len are part of the
+ * linear section. Only needed for read/write with direct
+ * packet access.
+ * @skb: pointer to skb
+ * @len: len to make read/writeable
+ * Return: 0 on success or negative error
+ */
+ BPF_FUNC_skb_pull_data,
+
+ /**
+ * bpf_csum_update(skb, csum)
+ * Adds csum into skb->csum in case of CHECKSUM_COMPLETE.
+ * @skb: pointer to skb
+ * @csum: csum to add
+ * Return: csum on success or negative error
+ */
+ BPF_FUNC_csum_update,
+
+ /**
+ * bpf_set_hash_invalid(skb)
+ * Invalidate current skb>hash.
+ * @skb: pointer to skb
+ */
+ BPF_FUNC_set_hash_invalid,
+
__BPF_FUNC_MAX_ID,
};
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index d9c76fe..b7393dd 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -140,7 +140,7 @@
__u64 tx_bytes;
__u64 tx_packets;
__u16 vid;
- __u16 pad1;
+ __u16 flags;
__u32 pad2;
};
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 1feb708..20965c9 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -316,6 +316,7 @@
IFLA_BRPORT_FLUSH,
IFLA_BRPORT_MULTICAST_ROUTER,
IFLA_BRPORT_PAD,
+ IFLA_BRPORT_MCAST_FLOOD,
__IFLA_BRPORT_MAX
};
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
@@ -461,6 +462,7 @@
enum ipvlan_mode {
IPVLAN_MODE_L2 = 0,
IPVLAN_MODE_L3,
+ IPVLAN_MODE_L3S,
IPVLAN_MODE_MAX
};
@@ -615,7 +617,7 @@
enum {
IFLA_VF_UNSPEC,
IFLA_VF_MAC, /* Hardware queue specific attributes */
- IFLA_VF_VLAN,
+ IFLA_VF_VLAN, /* VLAN ID and QoS */
IFLA_VF_TX_RATE, /* Max TX Bandwidth Allocation */
IFLA_VF_SPOOFCHK, /* Spoof Checking on/off switch */
IFLA_VF_LINK_STATE, /* link state enable/disable/auto switch */
@@ -627,6 +629,7 @@
IFLA_VF_TRUST, /* Trust VF */
IFLA_VF_IB_NODE_GUID, /* VF Infiniband node GUID */
IFLA_VF_IB_PORT_GUID, /* VF Infiniband port GUID */
+ IFLA_VF_VLAN_LIST, /* nested list of vlans, option for QinQ */
__IFLA_VF_MAX,
};
@@ -643,6 +646,22 @@
__u32 qos;
};
+enum {
+ IFLA_VF_VLAN_INFO_UNSPEC,
+ IFLA_VF_VLAN_INFO, /* VLAN ID, QoS and VLAN protocol */
+ __IFLA_VF_VLAN_INFO_MAX,
+};
+
+#define IFLA_VF_VLAN_INFO_MAX (__IFLA_VF_VLAN_INFO_MAX - 1)
+#define MAX_VLAN_LIST_LEN 1
+
+struct ifla_vf_vlan_info {
+ __u32 vf;
+ __u32 vlan; /* 0 - 4095, 0 disables VLAN filter */
+ __u32 qos;
+ __be16 vlan_proto; /* VLAN protocol either 802.1Q or 802.1ad */
+};
+
struct ifla_vf_tx_rate {
__u32 vf;
__u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */
@@ -823,6 +842,7 @@
IFLA_STATS_LINK_64,
IFLA_STATS_LINK_XSTATS,
IFLA_STATS_LINK_XSTATS_SLAVE,
+ IFLA_STATS_LINK_OFFLOAD_XSTATS,
__IFLA_STATS_MAX,
};
@@ -842,6 +862,14 @@
};
#define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1)
+/* These are stats embedded into IFLA_STATS_LINK_OFFLOAD_XSTATS */
+enum {
+ IFLA_OFFLOAD_XSTATS_UNSPEC,
+ IFLA_OFFLOAD_XSTATS_CPU_HIT, /* struct rtnl_link_stats64 */
+ __IFLA_OFFLOAD_XSTATS_MAX
+};
+#define IFLA_OFFLOAD_XSTATS_MAX (__IFLA_OFFLOAD_XSTATS_MAX - 1)
+
/* XDP section */
enum {
diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h
index 24aa175..4f975f5 100644
--- a/include/linux/if_tunnel.h
+++ b/include/linux/if_tunnel.h
@@ -27,9 +27,23 @@
#define GRE_SEQ __cpu_to_be16(0x1000)
#define GRE_STRICT __cpu_to_be16(0x0800)
#define GRE_REC __cpu_to_be16(0x0700)
-#define GRE_FLAGS __cpu_to_be16(0x00F8)
+#define GRE_ACK __cpu_to_be16(0x0080)
+#define GRE_FLAGS __cpu_to_be16(0x0078)
#define GRE_VERSION __cpu_to_be16(0x0007)
+#define GRE_IS_CSUM(f) ((f) & GRE_CSUM)
+#define GRE_IS_ROUTING(f) ((f) & GRE_ROUTING)
+#define GRE_IS_KEY(f) ((f) & GRE_KEY)
+#define GRE_IS_SEQ(f) ((f) & GRE_SEQ)
+#define GRE_IS_STRICT(f) ((f) & GRE_STRICT)
+#define GRE_IS_REC(f) ((f) & GRE_REC)
+#define GRE_IS_ACK(f) ((f) & GRE_ACK)
+
+#define GRE_VERSION_0 __cpu_to_be16(0x0000)
+#define GRE_VERSION_1 __cpu_to_be16(0x0001)
+#define GRE_PROTO_PPP __cpu_to_be16(0x880b)
+#define GRE_PPTP_KEY_MASK __cpu_to_be32(0xffff)
+
struct ip_tunnel_parm {
char name[IFNAMSIZ];
int link;
@@ -60,6 +74,7 @@
IFLA_IPTUN_ENCAP_FLAGS,
IFLA_IPTUN_ENCAP_SPORT,
IFLA_IPTUN_ENCAP_DPORT,
+ IFLA_IPTUN_COLLECT_METADATA,
__IFLA_IPTUN_MAX,
};
#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1)
diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h
index beb74ee..f5f5c1b 100644
--- a/include/linux/inet_diag.h
+++ b/include/linux/inet_diag.h
@@ -73,6 +73,7 @@
INET_DIAG_BC_S_COND,
INET_DIAG_BC_D_COND,
INET_DIAG_BC_DEV_COND, /* u32 ifindex */
+ INET_DIAG_BC_MARK_COND,
};
struct inet_diag_hostcond {
@@ -82,6 +83,11 @@
__be32 addr[0];
};
+struct inet_diag_markcond {
+ __u32 mark;
+ __u32 mask;
+};
+
/* Base info structure. It contains socket identity (addrs/ports/cookie)
* and, alas, the information shown by netstat. */
struct inet_diag_msg {
@@ -117,6 +123,8 @@
INET_DIAG_LOCALS,
INET_DIAG_PEERS,
INET_DIAG_PAD,
+ INET_DIAG_MARK,
+ INET_DIAG_BBRINFO,
__INET_DIAG_MAX,
};
@@ -150,8 +158,20 @@
__u32 dctcp_ab_tot;
};
+/* INET_DIAG_BBRINFO */
+
+struct tcp_bbr_info {
+ /* u64 bw: max-filtered BW (app throughput) estimate in Byte per sec: */
+ __u32 bbr_bw_lo; /* lower 32 bits of bw */
+ __u32 bbr_bw_hi; /* upper 32 bits of bw */
+ __u32 bbr_min_rtt; /* min-filtered RTT in uSec */
+ __u32 bbr_pacing_gain; /* pacing gain shifted left 8 bits */
+ __u32 bbr_cwnd_gain; /* cwnd gain shifted left 8 bits */
+};
+
union tcp_cc_info {
struct tcpvegas_info vegas;
struct tcp_dctcp_info dctcp;
+ struct tcp_bbr_info bbr;
};
#endif /* _INET_DIAG_H_ */
diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h
index 5e6c61e..b47ed3a 100644
--- a/include/linux/pkt_cls.h
+++ b/include/linux/pkt_cls.h
@@ -342,6 +342,7 @@
TCA_BPF_FD,
TCA_BPF_NAME,
TCA_BPF_FLAGS,
+ TCA_BPF_FLAGS_GEN,
__TCA_BPF_MAX,
};
@@ -374,6 +375,24 @@
TCA_FLOWER_KEY_UDP_DST, /* be16 */
TCA_FLOWER_FLAGS,
+ TCA_FLOWER_KEY_VLAN_ID, /* be16 */
+ TCA_FLOWER_KEY_VLAN_PRIO, /* u8 */
+ TCA_FLOWER_KEY_VLAN_ETH_TYPE, /* be16 */
+
+ TCA_FLOWER_KEY_ENC_KEY_ID, /* be32 */
+ TCA_FLOWER_KEY_ENC_IPV4_SRC, /* be32 */
+ TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,/* be32 */
+ TCA_FLOWER_KEY_ENC_IPV4_DST, /* be32 */
+ TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,/* be32 */
+ TCA_FLOWER_KEY_ENC_IPV6_SRC, /* struct in6_addr */
+ TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,/* struct in6_addr */
+ TCA_FLOWER_KEY_ENC_IPV6_DST, /* struct in6_addr */
+ TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,/* struct in6_addr */
+
+ TCA_FLOWER_KEY_TCP_SRC_MASK, /* be16 */
+ TCA_FLOWER_KEY_TCP_DST_MASK, /* be16 */
+ TCA_FLOWER_KEY_UDP_SRC_MASK, /* be16 */
+ TCA_FLOWER_KEY_UDP_DST_MASK, /* be16 */
__TCA_FLOWER_MAX,
};
diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
index 2382eed..df7451d 100644
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h
@@ -792,6 +792,8 @@
TCA_FQ_ORPHAN_MASK, /* mask applied to orphaned skb hashes */
+ TCA_FQ_LOW_RATE_THRESHOLD, /* per packet delay under this rate */
+
__TCA_FQ_MAX
};
@@ -809,7 +811,7 @@
__u32 flows;
__u32 inactive_flows;
__u32 throttled_flows;
- __u32 pad;
+ __u32 unthrottle_latency_ns;
};
/* Heavy-Hitter Filter */
diff --git a/include/linux/tc_act/tc_ife.h b/include/linux/tc_act/tc_ife.h
index 4ece02a..cd18360 100644
--- a/include/linux/tc_act/tc_ife.h
+++ b/include/linux/tc_act/tc_ife.h
@@ -32,8 +32,9 @@
#define IFE_META_HASHID 2
#define IFE_META_PRIO 3
#define IFE_META_QMAP 4
+#define IFE_META_TCINDEX 5
/*Can be overridden at runtime by module option*/
-#define __IFE_META_MAX 5
+#define __IFE_META_MAX 6
#define IFE_META_MAX (__IFE_META_MAX - 1)
#endif
diff --git a/include/linux/tc_act/tc_vlan.h b/include/linux/tc_act/tc_vlan.h
index 31151ff..bddb272 100644
--- a/include/linux/tc_act/tc_vlan.h
+++ b/include/linux/tc_act/tc_vlan.h
@@ -16,6 +16,7 @@
#define TCA_VLAN_ACT_POP 1
#define TCA_VLAN_ACT_PUSH 2
+#define TCA_VLAN_ACT_MODIFY 3
struct tc_vlan {
tc_gen;
@@ -29,6 +30,7 @@
TCA_VLAN_PUSH_VLAN_ID,
TCA_VLAN_PUSH_VLAN_PROTOCOL,
TCA_VLAN_PAD,
+ TCA_VLAN_PUSH_VLAN_PRIORITY,
__TCA_VLAN_MAX,
};
#define TCA_VLAN_MAX (__TCA_VLAN_MAX - 1)
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index f3dcdb7..cffa3bb 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -167,6 +167,7 @@
__u8 tcpi_backoff;
__u8 tcpi_options;
__u8 tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4;
+ __u8 tcpi_delivery_rate_app_limited:1;
__u32 tcpi_rto;
__u32 tcpi_ato;
@@ -211,6 +212,8 @@
__u32 tcpi_min_rtt;
__u32 tcpi_data_segs_in; /* RFC4898 tcpEStatsDataSegsIn */
__u32 tcpi_data_segs_out; /* RFC4898 tcpEStatsDataSegsOut */
+
+ __u64 tcpi_delivery_rate;
};
/* for TCP_MD5SIG socket option */
diff --git a/include/linux/tipc_netlink.h b/include/linux/tipc_netlink.h
index 5f3f6d0..f9edd20 100644
--- a/include/linux/tipc_netlink.h
+++ b/include/linux/tipc_netlink.h
@@ -59,6 +59,9 @@
TIPC_NL_MON_SET,
TIPC_NL_MON_GET,
TIPC_NL_MON_PEER_GET,
+ TIPC_NL_PEER_REMOVE,
+ TIPC_NL_BEARER_ADD,
+ TIPC_NL_UDP_GET_REMOTEIP,
__TIPC_NL_CMD_MAX,
TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1
@@ -98,6 +101,7 @@
TIPC_NLA_UDP_UNSPEC,
TIPC_NLA_UDP_LOCAL, /* sockaddr_storage */
TIPC_NLA_UDP_REMOTE, /* sockaddr_storage */
+ TIPC_NLA_UDP_MULTI_REMOTEIP, /* flag */
__TIPC_NLA_UDP_MAX,
TIPC_NLA_UDP_MAX = __TIPC_NLA_UDP_MAX - 1
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index d09be24..d2dd1fd 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -298,7 +298,7 @@
XFRMA_ALG_AUTH_TRUNC, /* struct xfrm_algo_auth */
XFRMA_MARK, /* struct xfrm_mark */
XFRMA_TFCPAD, /* __u32 */
- XFRMA_REPLAY_ESN_VAL, /* struct xfrm_replay_esn */
+ XFRMA_REPLAY_ESN_VAL, /* struct xfrm_replay_state_esn */
XFRMA_SA_EXTRA_FLAGS, /* __u32 */
XFRMA_PROTO, /* __u8 */
XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */
diff --git a/ip/ip_common.h b/ip/ip_common.h
index 1c1cbdf..0147f45 100644
--- a/ip/ip_common.h
+++ b/ip/ip_common.h
@@ -31,6 +31,7 @@
struct rtnl_ctrl_data *ctrl,
struct nlmsghdr *n, void *arg);
void netns_map_init(void);
+void netns_nsid_socket_init(void);
int print_nsid(const struct sockaddr_nl *who,
struct nlmsghdr *n, void *arg);
int do_ipaddr(int argc, char **argv);
diff --git a/ip/iplink_ipvlan.c b/ip/iplink_ipvlan.c
index a6273be..f7735f3 100644
--- a/ip/iplink_ipvlan.c
+++ b/ip/iplink_ipvlan.c
@@ -20,18 +20,7 @@
static void ipvlan_explain(FILE *f)
{
- fprintf(f, "Usage: ... ipvlan [ mode { l2 | l3 } ]\n");
-}
-
-static void explain(void)
-{
- ipvlan_explain(stderr);
-}
-
-static int mode_arg(void)
-{
- fprintf(stderr, "Error: argument of \"mode\" must be either \"l2\", or \"l3\"\n");
- return -1;
+ fprintf(f, "Usage: ... ipvlan [ mode { l2 | l3 | l3s } ]\n");
}
static int ipvlan_parse_opt(struct link_util *lu, int argc, char **argv,
@@ -47,20 +36,24 @@
mode = IPVLAN_MODE_L2;
else if (strcmp(*argv, "l3") == 0)
mode = IPVLAN_MODE_L3;
- else
- return mode_arg();
-
+ else if (strcmp(*argv, "l3s") == 0)
+ mode = IPVLAN_MODE_L3S;
+ else {
+ fprintf(stderr, "Error: argument of \"mode\" must be either \"l2\", \"l3\" or \"l3s\"\n");
+ return -1;
+ }
addattr16(n, 1024, IFLA_IPVLAN_MODE, mode);
} else if (matches(*argv, "help") == 0) {
- explain();
+ ipvlan_explain(stderr);
return -1;
} else {
fprintf(stderr, "ipvlan: unknown option \"%s\"?\n",
*argv);
- explain();
+ ipvlan_explain(stderr);
return -1;
}
- argc--, argv++;
+ argc--;
+ argv++;
}
return 0;
@@ -78,7 +71,8 @@
fprintf(f, " mode %s ",
mode == IPVLAN_MODE_L2 ? "l2" :
- mode == IPVLAN_MODE_L3 ? "l3" : "unknown");
+ mode == IPVLAN_MODE_L3 ? "l3" :
+ mode == IPVLAN_MODE_L3S ? "l3s" : "unknown");
}
}
}
diff --git a/ip/ipmonitor.c b/ip/ipmonitor.c
index 2090a45..c892b8f 100644
--- a/ip/ipmonitor.c
+++ b/ip/ipmonitor.c
@@ -301,6 +301,7 @@
exit(1);
ll_init_map(&rth);
+ netns_nsid_socket_init();
netns_map_init();
if (rtnl_listen(&rth, accept_msg, stdout) < 0)
diff --git a/ip/ipnetns.c b/ip/ipnetns.c
index ccc652c..bd1e901 100644
--- a/ip/ipnetns.c
+++ b/ip/ipnetns.c
@@ -194,6 +194,18 @@
free(c);
}
+void netns_nsid_socket_init(void)
+{
+ if (rtnsh.fd > -1 || !ipnetns_have_nsid())
+ return;
+
+ if (rtnl_open(&rtnsh, 0) < 0) {
+ fprintf(stderr, "Cannot open rtnetlink\n");
+ exit(1);
+ }
+
+}
+
void netns_map_init(void)
{
static int initialized;
@@ -204,11 +216,6 @@
if (initialized || !ipnetns_have_nsid())
return;
- if (rtnl_open(&rtnsh, 0) < 0) {
- fprintf(stderr, "Cannot open rtnetlink\n");
- exit(1);
- }
-
dir = opendir(NETNS_RUN_DIR);
if (!dir)
return;
@@ -775,17 +782,23 @@
int do_netns(int argc, char **argv)
{
- netns_map_init();
+ netns_nsid_socket_init();
- if (argc < 1)
+ if (argc < 1) {
+ netns_map_init();
return netns_list(0, NULL);
+ }
if ((matches(*argv, "list") == 0) || (matches(*argv, "show") == 0) ||
- (matches(*argv, "lst") == 0))
+ (matches(*argv, "lst") == 0)) {
+ netns_map_init();
return netns_list(argc-1, argv+1);
+ }
- if ((matches(*argv, "list-id") == 0))
+ if ((matches(*argv, "list-id") == 0)) {
+ netns_map_init();
return netns_list_id(argc-1, argv+1);
+ }
if (matches(*argv, "help") == 0)
return usage();
diff --git a/ip/link_ip6tnl.c b/ip/link_ip6tnl.c
index 59162a3..051c89f 100644
--- a/ip/link_ip6tnl.c
+++ b/ip/link_ip6tnl.c
@@ -40,6 +40,7 @@
fprintf(f, " [ noencap ] [ encap { fou | gue | none } ]\n");
fprintf(f, " [ encap-sport PORT ] [ encap-dport PORT ]\n");
fprintf(f, " [ [no]encap-csum ] [ [no]encap-csum6 ] [ [no]encap-remcsum ]\n");
+ fprintf(f, " [ external ]\n");
fprintf(f, "\n");
fprintf(f, "Where: NAME := STRING\n");
fprintf(f, " ADDR := IPV6_ADDRESS\n");
@@ -89,6 +90,7 @@
__u16 encapflags = TUNNEL_ENCAP_FLAG_CSUM6;
__u16 encapsport = 0;
__u16 encapdport = 0;
+ __u8 metadata = 0;
if (!(n->nlmsg_flags & NLM_F_CREATE)) {
if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
@@ -141,6 +143,8 @@
if (iptuninfo[IFLA_IPTUN_PROTO])
proto = rta_getattr_u8(iptuninfo[IFLA_IPTUN_PROTO]);
+ if (iptuninfo[IFLA_IPTUN_COLLECT_METADATA])
+ metadata = 1;
}
while (argc > 0) {
@@ -277,12 +281,18 @@
encapflags |= TUNNEL_ENCAP_FLAG_REMCSUM;
} else if (strcmp(*argv, "noencap-remcsum") == 0) {
encapflags |= ~TUNNEL_ENCAP_FLAG_REMCSUM;
+ } else if (strcmp(*argv, "external") == 0) {
+ metadata = 1;
} else
usage();
argc--, argv++;
}
addattr8(n, 1024, IFLA_IPTUN_PROTO, proto);
+ if (metadata) {
+ addattr_l(n, 1024, IFLA_IPTUN_COLLECT_METADATA, NULL, 0);
+ return 0;
+ }
addattr_l(n, 1024, IFLA_IPTUN_LOCAL, &laddr, sizeof(laddr));
addattr_l(n, 1024, IFLA_IPTUN_REMOTE, &raddr, sizeof(raddr));
addattr8(n, 1024, IFLA_IPTUN_TTL, hop_limit);
diff --git a/ip/link_iptnl.c b/ip/link_iptnl.c
index 7ec3777..1875348 100644
--- a/ip/link_iptnl.c
+++ b/ip/link_iptnl.c
@@ -36,6 +36,7 @@
fprintf(f, " [ mode { ip6ip | ipip | any } ]\n");
fprintf(f, " [ isatap ]\n");
}
+ fprintf(f, " [ external ]\n");
fprintf(f, "\n");
fprintf(f, "Where: NAME := STRING\n");
fprintf(f, " ADDR := { IP_ADDRESS | any }\n");
@@ -85,6 +86,7 @@
__u16 encapflags = 0;
__u16 encapsport = 0;
__u16 encapdport = 0;
+ __u8 metadata = 0;
if (!(n->nlmsg_flags & NLM_F_CREATE)) {
if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
@@ -161,6 +163,8 @@
if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN])
ip6rdrelayprefixlen =
rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]);
+ if (iptuninfo[IFLA_IPTUN_COLLECT_METADATA])
+ metadata = 1;
}
while (argc > 0) {
@@ -257,6 +261,8 @@
encapflags |= TUNNEL_ENCAP_FLAG_REMCSUM;
} else if (strcmp(*argv, "noencap-remcsum") == 0) {
encapflags &= ~TUNNEL_ENCAP_FLAG_REMCSUM;
+ } else if (strcmp(*argv, "external") == 0) {
+ metadata = 1;
} else if (strcmp(*argv, "6rd-prefix") == 0) {
inet_prefix prefix;
@@ -291,6 +297,11 @@
exit(-1);
}
+ if (metadata) {
+ addattr_l(n, 1024, IFLA_IPTUN_COLLECT_METADATA, NULL, 0);
+ return 0;
+ }
+
addattr32(n, 1024, IFLA_IPTUN_LINK, link);
addattr32(n, 1024, IFLA_IPTUN_LOCAL, laddr);
addattr32(n, 1024, IFLA_IPTUN_REMOTE, raddr);
diff --git a/lib/libnetlink.c b/lib/libnetlink.c
index a02cf9f..2279935 100644
--- a/lib/libnetlink.c
+++ b/lib/libnetlink.c
@@ -152,6 +152,26 @@
return send(rth->fd, (void*)&req, sizeof(req), 0);
}
+int rtnl_wilddump_stats_req_filter(struct rtnl_handle *rth, int fam, int type,
+ __u32 filt_mask)
+{
+ struct {
+ struct nlmsghdr nlh;
+ struct if_stats_msg ifsm;
+ } req;
+
+ memset(&req, 0, sizeof(req));
+ req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct if_stats_msg));
+ req.nlh.nlmsg_type = type;
+ req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
+ req.nlh.nlmsg_pid = 0;
+ req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
+ req.ifsm.family = fam;
+ req.ifsm.filter_mask = filt_mask;
+
+ return send(rth->fd, (void *)&req, sizeof(req), 0);
+}
+
int rtnl_send(struct rtnl_handle *rth, const void *buf, int len)
{
return send(rth->fd, buf, len, 0);
diff --git a/man/man8/bridge.8 b/man/man8/bridge.8
index bb70442..7bfb068 100644
--- a/man/man8/bridge.8
+++ b/man/man8/bridge.8
@@ -570,6 +570,11 @@
This command displays the current VLAN filter table.
+.PP
+With the
+.B -statistics
+option, the command displays per-vlan traffic statistics.
+
.SH bridge monitor - state monitoring
The
diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8
index 9ae10e6..74f7664 100644
--- a/man/man8/tc-flower.8
+++ b/man/man8/tc-flower.8
@@ -23,7 +23,13 @@
.R " | { "
.BR dst_mac " | " src_mac " } "
.IR mac_address " | "
-.BR eth_type " { " ipv4 " | " ipv6 " | "
+.BR eth_type " { " ipv4 " | " ipv6 " | " 802.1Q " | "
+.IR ETH_TYPE " } | "
+.B vlan_id
+.IR VID " | "
+.B vlan_prio
+.IR PRIORITY " | "
+.BR vlan_eth_type " { " ipv4 " | " ipv6 " | "
.IR ETH_TYPE " } | "
.BR ip_proto " { " tcp " | " udp " | "
.IR IP_PROTO " } | { "
@@ -70,6 +76,23 @@
Match on source or destination MAC address.
.TP
.BI eth_type " ETH_TYPE"
+Match on the next protocol.
+.I ETH_TYPE
+may be either
+.BR ipv4 , ipv6 , 802.1Q ,
+or an unsigned 16bit value in hexadecimal format.
+.TP
+.BI vlan_id " VID"
+Match on vlan tag id.
+.I VID
+is an unsigned 12bit value in decimal format.
+.TP
+.BI vlan_prio " priority"
+Match on vlan tag priority.
+.I PRIORITY
+is an unsigned 3bit value in decimal format.
+.TP
+.BI vlan_eth_type " VLAN_ETH_TYPE"
Match on layer three protocol.
.I ETH_TYPE
may be either
diff --git a/man/man8/tc-vlan.8 b/man/man8/tc-vlan.8
index 4bfd72b..4d0c5c8 100644
--- a/man/man8/tc-vlan.8
+++ b/man/man8/tc-vlan.8
@@ -12,6 +12,8 @@
.IR PUSH " := "
.BR push " [ " protocol
.IR VLANPROTO " ]"
+.BR " [ " priority
+.IR VLANPRIO " ] "
.BI id " VLANID"
.ti -8
@@ -55,6 +57,9 @@
Choose the VLAN protocol to use. At the time of writing, the kernel accepts only
.BR 802.1Q " or " 802.1ad .
.TP
+.BI priority " VLANPRIO"
+Choose the VLAN priority to use. Decimal number in range of 0-7.
+.TP
.I CONTROL
How to continue after executing this action.
.RS
diff --git a/man/man8/tipc-bearer.8 b/man/man8/tipc-bearer.8
index 846f1db..d95b1e1 100644
--- a/man/man8/tipc-bearer.8
+++ b/man/man8/tipc-bearer.8
@@ -11,6 +11,11 @@
.in +8
.ti -8
+.B tipc bearer add media udp name
+.IB "NAME " "remoteip " REMOTEIP
+.br
+
+.ti -8
.B tipc bearer enable
.RB "[ " domain
.IR DOMAIN " ]"
@@ -68,7 +73,7 @@
.ti -8
.B tipc bearer get
-.RB "{ " "priority" " | " tolerance " | " window " } " media
+.RB "[ " "priority" " | " tolerance " | " window " ] " media
.br
.RB "{ { " eth " | " ib " } " device
.IR "DEVICE" " }"
@@ -76,7 +81,8 @@
.br
.RB "{ " udp
.B name
-.IR NAME " }"
+.IR NAME
+.RB "[ " "localip " "| " "localport " "| " "remoteip " "| " "remoteport " "] }"
.br
.ti -8
@@ -196,6 +202,25 @@
.B udp
bearer runs in point-to-point mode.
+Multiple
+.B remoteip
+addresses can be added via the
+.B bearer add
+command. Adding one or more unicast
+.B remoteip
+addresses to an existing
+.B udp
+bearer puts the bearer in replicast mode where IP
+multicast is emulated by sending multiple unicast messages to each configured
+.B remoteip.
+When a peer sees a TIPC discovery message from an unknown peer the peer address
+is automatically added to the
+.B remoteip
+(replicast) list, thus only one side of
+a link needs to be manually configured. A
+.B remoteip
+address cannot be added to a multicast bearer.
+
.TP
.BI "remoteport " REMOTEPORT
.br
@@ -212,6 +237,7 @@
.BR tipc-media (8),
.BR tipc-nametable (8),
.BR tipc-node (8),
+.BR tipc-peer (8),
.BR tipc-socket (8)
.br
.SH REPORTING BUGS
diff --git a/man/man8/tipc-link.8 b/man/man8/tipc-link.8
index 3be8c9a..fee283e 100644
--- a/man/man8/tipc-link.8
+++ b/man/man8/tipc-link.8
@@ -39,6 +39,29 @@
.B tipc link list
.br
+.ti -8
+.B tipc link monitor set
+.RB "{ " "threshold" " } "
+
+.ti -8
+.B tipc link monitor get
+.RB "{ " "threshold" " } "
+
+.ti -8
+.B tipc link monitor summary
+.br
+
+.ti -8
+.B tipc link monitor list
+.br
+.RB "[ " "media " " { " eth " | " ib " } " device
+.IR "DEVICE" " ]"
+.RB "|"
+.br
+.RB "[ " "media udp name"
+.IR NAME " ]"
+.br
+
.SH OPTIONS
Options (flags) that can be passed anywhere in the command chain.
.TP
@@ -204,6 +227,87 @@
have in its transmit queue before TIPC's congestion control mechanism is
activated.
+.SS Monitor properties
+
+.TP
+.B threshold
+.br
+The threshold specifies the cluster size exceeding which the link monitoring
+algorithm will switch from "full-mesh" to "overlapping-ring".
+If set of 0 the overlapping-ring monitoring is always on and if set to a
+value larger than anticipated cluster size the overlapping-ring is disabled.
+The default value is 32.
+
+.SS Monitor information
+
+.TP
+.B table_generation
+.br
+Represents the event count in a node's local monitoring list. It steps every
+time something changes in the local monitor list, including changes in the
+local domain.
+
+.TP
+.B cluster_size
+.br
+Represents the current count of cluster members.
+
+.TP
+.B algorithm
+.br
+The current supervision algorithm used for neighbour monitoring for the bearer.
+Possible values are full-mesh or overlapping-ring.
+
+.TP
+.B status
+.br
+The node status derived by the local node.
+Possible status are up or down.
+
+.TP
+.B monitored
+.br
+Represent the type of monitoring chosen by the local node.
+Possible values are direct or indirect.
+
+.TP
+.B generation
+.br
+Represents the domain generation which is the event count in a node's local
+domain. Every time something changes (peer add/remove/up/down) the domain
+generation is stepped and a new version of node record is sent to inform
+the neighbors about this change. The domain generation helps the receiver
+of a domain record to know if it should ignore or process the record.
+
+.TP
+.B applied_node_status
+.br
+The node status reported by the peer node for the succeeding peers in
+the node list. The Node list is a circular list of ascending addresses
+starting with the local node.
+Possible status are: U or D. The status U implies up and D down.
+
+.TP
+.B [non_applied_node:status]
+.br
+Represents the nodes and their status as reported by the peer node.
+These nodes were not applied to the monitoring list for this peer node.
+They are usually transient and occur during the cluster startup phase
+or network reconfiguration.
+Possible status are: U or D. The status U implies up and D down.
+
+.SH EXAMPLES
+.PP
+tipc link monitor list
+.RS 4
+Shows the link monitoring information for cluster members on device data0.
+.RE
+.PP
+tipc link monitor summary
+.RS 4
+The monitor summary command prints the basic attributes.
+.RE
+
.SH EXIT STATUS
Exit status is 0 if command was successful or a positive integer upon failure.
@@ -213,6 +317,7 @@
.BR tipc-bearer (8),
.BR tipc-nametable (8),
.BR tipc-node (8),
+.BR tipc-peer (8),
.BR tipc-socket (8)
.br
.SH REPORTING BUGS
diff --git a/man/man8/tipc-media.8 b/man/man8/tipc-media.8
index 6c6e2b1..4689cb3 100644
--- a/man/man8/tipc-media.8
+++ b/man/man8/tipc-media.8
@@ -74,6 +74,7 @@
.BR tipc-link (8),
.BR tipc-nametable (8),
.BR tipc-node (8),
+.BR tipc-peer (8),
.BR tipc-socket (8)
.br
.SH REPORTING BUGS
diff --git a/man/man8/tipc-nametable.8 b/man/man8/tipc-nametable.8
index d3397f9..4bcefe4 100644
--- a/man/man8/tipc-nametable.8
+++ b/man/man8/tipc-nametable.8
@@ -87,6 +87,7 @@
.BR tipc-link (8),
.BR tipc-media (8),
.BR tipc-node (8),
+.BR tipc-peer (8),
.BR tipc-socket (8)
.br
.SH REPORTING BUGS
diff --git a/man/man8/tipc-node.8 b/man/man8/tipc-node.8
index ef32ec7..a72a409 100644
--- a/man/man8/tipc-node.8
+++ b/man/man8/tipc-node.8
@@ -59,6 +59,7 @@
.BR tipc-link (8),
.BR tipc-media (8),
.BR tipc-nametable (8),
+.BR tipc-peer (8),
.BR tipc-socket (8)
.br
.SH REPORTING BUGS
diff --git a/man/man8/tipc-peer.8 b/man/man8/tipc-peer.8
new file mode 100644
index 0000000..430651f
--- /dev/null
+++ b/man/man8/tipc-peer.8
@@ -0,0 +1,52 @@
+.TH TIPC-PEER 8 "04 Dec 2015" "iproute2" "Linux"
+
+.\" For consistency, please keep padding right aligned.
+.\" For example '.B "foo " bar' and not '.B foo " bar"'
+
+.SH NAME
+tipc-peer \- modify peer information
+
+.SH SYNOPSIS
+.ad l
+.in +8
+
+.ti -8
+.B tipc peer remove address
+.IR ADDRESS
+
+.SH OPTIONS
+Options (flags) that can be passed anywhere in the command chain.
+.TP
+.BR "\-h" , " --help"
+Show help about last valid command. For example
+.B tipc peer --help
+will show peer help and
+.B tipc --help
+will show general help. The position of the option in the string is irrelevant.
+.SH DESCRIPTION
+
+.SS Peer remove
+Remove an offline peer node from the local data structures. The peer is
+identified by its
+.B address
+
+.SH EXIT STATUS
+Exit status is 0 if command was successful or a positive integer upon failure.
+
+.SH SEE ALSO
+.BR tipc (8),
+.BR tipc-bearer (8),
+.BR tipc-link (8),
+.BR tipc-media (8),
+.BR tipc-nametable (8),
+.BR tipc-node (8),
+.BR tipc-socket (8)
+.br
+.SH REPORTING BUGS
+Report any bugs to the Network Developers mailing list
+.B <netdev@vger.kernel.org>
+where the development and maintenance is primarily done.
+You do not have to be subscribed to the list to send a message there.
+
+.SH AUTHOR
+Richard Alpe <richard.alpe@ericsson.com>
diff --git a/man/man8/tipc.8 b/man/man8/tipc.8
index c116552..32943fa 100644
--- a/man/man8/tipc.8
+++ b/man/man8/tipc.8
@@ -87,6 +87,7 @@
.BR tipc-media (8),
.BR tipc-nametable (8),
.BR tipc-node (8),
+.BR tipc-peer (8),
.BR tipc-socket (8)
.br
.SH REPORTING BUGS
diff --git a/misc/ss.c b/misc/ss.c
index f67557a..dd77b81 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -737,6 +737,7 @@
unsigned long long sk;
char *name;
char *peer_name;
+ __u32 mark;
};
struct dctcpstat {
@@ -789,6 +790,7 @@
bool has_fastopen_opt;
bool has_wscale_opt;
struct dctcpstat *dctcp;
+ struct tcp_bbr_info *bbr_info;
};
static void sock_state_print(struct sockstat *s, const char *sock_name)
@@ -808,6 +810,9 @@
printf(" ino:%u", s->ino);
printf(" sk:%llx", s->sk);
+
+ if (s->mark)
+ printf(" fwmark:0x%x", s->mark);
}
static void sock_addr_print_width(int addr_len, const char *addr, char *delim,
@@ -1047,6 +1052,8 @@
inet_prefix addr;
int port;
unsigned int iface;
+ __u32 mark;
+ __u32 mask;
struct aafilter *next;
};
@@ -1167,6 +1174,12 @@
return s->iface == a->iface;
}
+ case SSF_MARKMASK:
+ {
+ struct aafilter *a = (void *)f->pred;
+
+ return (s->mark & a->mask) == a->mark;
+ }
/* Yup. It is recursion. Sorry. */
case SSF_AND:
return run_ssfilter(f->pred, s) && run_ssfilter(f->post, s);
@@ -1342,6 +1355,23 @@
/* bytecompile for SSF_DEVCOND not supported yet */
return 0;
}
+ case SSF_MARKMASK:
+ {
+ struct aafilter *a = (void *)f->pred;
+ struct instr {
+ struct inet_diag_bc_op op;
+ struct inet_diag_markcond cond;
+ };
+ int inslen = sizeof(struct instr);
+
+ if (!(*bytecode = malloc(inslen))) abort();
+ ((struct instr *)*bytecode)[0] = (struct instr) {
+ { INET_DIAG_BC_MARK_COND, inslen, inslen + 4 },
+ { a->mark, a->mask},
+ };
+
+ return inslen;
+ }
default:
abort();
}
@@ -1621,6 +1651,25 @@
return res;
}
+void *parse_markmask(const char *markmask)
+{
+ struct aafilter a, *res;
+
+ if (strchr(markmask, '/')) {
+ if (sscanf(markmask, "%i/%i", &a.mark, &a.mask) != 2)
+ return NULL;
+ } else {
+ a.mask = 0xffffffff;
+ if (sscanf(markmask, "%i", &a.mark) != 1)
+ return NULL;
+ }
+
+ res = malloc(sizeof(*res));
+ if (res)
+ memcpy(res, &a, sizeof(a));
+ return res;
+}
+
static char *proto_name(int protocol)
{
switch (protocol) {
@@ -1784,6 +1833,25 @@
printf(" dctcp:fallback_mode");
}
+ if (s->bbr_info) {
+ __u64 bw;
+
+ bw = s->bbr_info->bbr_bw_hi;
+ bw <<= 32;
+ bw |= s->bbr_info->bbr_bw_lo;
+
+ printf(" bbr:(bw:%sbps,mrtt:%g",
+ sprint_bw(b1, bw * 8.0),
+ (double)s->bbr_info->bbr_min_rtt / 1000.0);
+ if (s->bbr_info->bbr_pacing_gain)
+ printf(",pacing_gain:%g",
+ (double)s->bbr_info->bbr_pacing_gain / 256.0);
+ if (s->bbr_info->bbr_cwnd_gain)
+ printf(",cwnd_gain:%g",
+ (double)s->bbr_info->bbr_cwnd_gain / 256.0);
+ printf(")");
+ }
+
if (s->send_bps)
printf(" send %sbps", sprint_bw(b1, s->send_bps));
if (s->lastsnd)
@@ -2062,6 +2130,16 @@
s.dctcp = dctcp;
}
+ if (tb[INET_DIAG_BBRINFO]) {
+ const void *bbr_info = RTA_DATA(tb[INET_DIAG_BBRINFO]);
+ int len = min(RTA_PAYLOAD(tb[INET_DIAG_BBRINFO]),
+ sizeof(*s.bbr_info));
+
+ s.bbr_info = calloc(1, sizeof(*s.bbr_info));
+ if (s.bbr_info && bbr_info)
+ memcpy(s.bbr_info, bbr_info, len);
+ }
+
if (rtt > 0 && info->tcpi_snd_mss && info->tcpi_snd_cwnd) {
s.send_bps = (double) info->tcpi_snd_cwnd *
(double)info->tcpi_snd_mss * 8000000. / rtt;
@@ -2086,6 +2164,7 @@
s.min_rtt = (double) info->tcpi_min_rtt / 1000;
tcp_stats_print(&s);
free(s.dctcp);
+ free(s.bbr_info);
}
}
@@ -2108,6 +2187,10 @@
s->iface = r->id.idiag_if;
s->sk = cookie_sk_get(&r->id.idiag_cookie[0]);
+ s->mark = 0;
+ if (tb[INET_DIAG_MARK])
+ s->mark = *(__u32 *) RTA_DATA(tb[INET_DIAG_MARK]);
+
if (s->local.family == AF_INET)
s->local.bytelen = s->remote.bytelen = 4;
else
diff --git a/misc/ssfilter.h b/misc/ssfilter.h
index c7db8ee..dfc5b93 100644
--- a/misc/ssfilter.h
+++ b/misc/ssfilter.h
@@ -9,6 +9,7 @@
#define SSF_S_LE 8
#define SSF_S_AUTO 9
#define SSF_DEVCOND 10
+#define SSF_MARKMASK 11
#include <stdbool.h>
@@ -22,3 +23,4 @@
int ssfilter_parse(struct ssfilter **f, int argc, char **argv, FILE *fp);
void *parse_hostcond(char *addr, bool is_port);
void *parse_devcond(char *name);
+void *parse_markmask(const char *markmask);
diff --git a/misc/ssfilter.y b/misc/ssfilter.y
index 14bf981..ba82b65 100644
--- a/misc/ssfilter.y
+++ b/misc/ssfilter.y
@@ -36,7 +36,7 @@
%}
-%token HOSTCOND DCOND SCOND DPORT SPORT LEQ GEQ NEQ AUTOBOUND DEVCOND DEVNAME
+%token HOSTCOND DCOND SCOND DPORT SPORT LEQ GEQ NEQ AUTOBOUND DEVCOND DEVNAME MARKMASK FWMARK
%left '|'
%left '&'
%nonassoc '!'
@@ -116,7 +116,14 @@
{
$$ = alloc_node(SSF_NOT, alloc_node(SSF_DEVCOND, $3));
}
-
+ | FWMARK '=' MARKMASK
+ {
+ $$ = alloc_node(SSF_MARKMASK, $3);
+ }
+ | FWMARK NEQ MARKMASK
+ {
+ $$ = alloc_node(SSF_NOT, alloc_node(SSF_MARKMASK, $3));
+ }
| AUTOBOUND
{
$$ = alloc_node(SSF_S_AUTO, NULL);
@@ -249,6 +256,10 @@
tok_type = DEVNAME;
return DEVNAME;
}
+ if (strcmp(curtok, "fwmark") == 0) {
+ tok_type = FWMARK;
+ return FWMARK;
+ }
if (strcmp(curtok, ">=") == 0 ||
strcmp(curtok, "ge") == 0 ||
strcmp(curtok, "geq") == 0)
@@ -283,6 +294,14 @@
}
return DEVCOND;
}
+ if (tok_type == FWMARK) {
+ yylval = (void*)parse_markmask(curtok);
+ if (yylval == NULL) {
+ fprintf(stderr, "Cannot parse mark %s.\n", curtok);
+ exit(1);
+ }
+ return MARKMASK;
+ }
yylval = (void*)parse_hostcond(curtok, tok_type == SPORT || tok_type == DPORT);
if (yylval == NULL) {
fprintf(stderr, "Cannot parse dst/src address.\n");
diff --git a/tc/f_flower.c b/tc/f_flower.c
index 791ade7..2d31d1a 100644
--- a/tc/f_flower.c
+++ b/tc/f_flower.c
@@ -17,6 +17,7 @@
#include <net/if.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
+#include <linux/tc_act/tc_vlan.h>
#include "utils.h"
#include "tc_util.h"
@@ -30,6 +31,9 @@
fprintf(stderr, "\n");
fprintf(stderr, "Where: MATCH-LIST := [ MATCH-LIST ] MATCH\n");
fprintf(stderr, " MATCH := { indev DEV-NAME |\n");
+ fprintf(stderr, " vlan_id VID |\n");
+ fprintf(stderr, " vlan_prio PRIORITY |\n");
+ fprintf(stderr, " vlan_ethtype [ ipv4 | ipv6 | ETH-TYPE ] |\n");
fprintf(stderr, " dst_mac MAC-ADDR |\n");
fprintf(stderr, " src_mac MAC-ADDR |\n");
fprintf(stderr, " [ipv4 | ipv6 ] |\n");
@@ -61,6 +65,23 @@
return 0;
}
+static int flower_parse_vlan_eth_type(char *str, __be16 eth_type, int type,
+ __be16 *p_vlan_eth_type, struct nlmsghdr *n)
+{
+ __be16 vlan_eth_type;
+
+ if (eth_type != htons(ETH_P_8021Q)) {
+ fprintf(stderr, "Can't set \"vlan_ethtype\" if ethertype isn't 802.1Q\n");
+ return -1;
+ }
+
+ if (ll_proto_a2n(&vlan_eth_type, str))
+ invarg("invalid vlan_ethtype", str);
+ addattr16(n, MAX_MSG, type, vlan_eth_type);
+ *p_vlan_eth_type = vlan_eth_type;
+ return 0;
+}
+
static int flower_parse_ip_proto(char *str, __be16 eth_type, int type,
__u8 *p_ip_proto, struct nlmsghdr *n)
{
@@ -167,6 +188,7 @@
struct tcmsg *t = NLMSG_DATA(n);
struct rtattr *tail;
__be16 eth_type = TC_H_MIN(t->tcm_info);
+ __be16 vlan_ethtype = 0;
__u8 ip_proto = 0xff;
__u32 flags = 0;
@@ -208,6 +230,41 @@
NEXT_ARG();
strncpy(ifname, *argv, sizeof(ifname) - 1);
addattrstrz(n, MAX_MSG, TCA_FLOWER_INDEV, ifname);
+ } else if (matches(*argv, "vlan_id") == 0) {
+ __u16 vid;
+
+ NEXT_ARG();
+ if (eth_type != htons(ETH_P_8021Q)) {
+ fprintf(stderr, "Can't set \"vlan_id\" if ethertype isn't 802.1Q\n");
+ return -1;
+ }
+ ret = get_u16(&vid, *argv, 10);
+ if (ret < 0 || vid & ~0xfff) {
+ fprintf(stderr, "Illegal \"vlan_id\"\n");
+ return -1;
+ }
+ addattr16(n, MAX_MSG, TCA_FLOWER_KEY_VLAN_ID, vid);
+ } else if (matches(*argv, "vlan_prio") == 0) {
+ __u8 vlan_prio;
+
+ NEXT_ARG();
+ if (eth_type != htons(ETH_P_8021Q)) {
+ fprintf(stderr, "Can't set \"vlan_prio\" if ethertype isn't 802.1Q\n");
+ return -1;
+ }
+ ret = get_u8(&vlan_prio, *argv, 10);
+ if (ret < 0 || vlan_prio & ~0x7) {
+ fprintf(stderr, "Illegal \"vlan_prio\"\n");
+ return -1;
+ }
+ addattr8(n, MAX_MSG, TCA_FLOWER_KEY_VLAN_PRIO, vlan_prio);
+ } else if (matches(*argv, "vlan_ethtype") == 0) {
+ NEXT_ARG();
+ ret = flower_parse_vlan_eth_type(*argv, eth_type,
+ TCA_FLOWER_KEY_VLAN_ETH_TYPE,
+ &vlan_ethtype, n);
+ if (ret < 0)
+ return -1;
} else if (matches(*argv, "dst_mac") == 0) {
NEXT_ARG();
ret = flower_parse_eth_addr(*argv,
@@ -230,7 +287,8 @@
}
} else if (matches(*argv, "ip_proto") == 0) {
NEXT_ARG();
- ret = flower_parse_ip_proto(*argv, eth_type,
+ ret = flower_parse_ip_proto(*argv, vlan_ethtype ?
+ vlan_ethtype : eth_type,
TCA_FLOWER_KEY_IP_PROTO,
&ip_proto, n);
if (ret < 0) {
@@ -239,7 +297,8 @@
}
} else if (matches(*argv, "dst_ip") == 0) {
NEXT_ARG();
- ret = flower_parse_ip_addr(*argv, eth_type,
+ ret = flower_parse_ip_addr(*argv, vlan_ethtype ?
+ vlan_ethtype : eth_type,
TCA_FLOWER_KEY_IPV4_DST,
TCA_FLOWER_KEY_IPV4_DST_MASK,
TCA_FLOWER_KEY_IPV6_DST,
@@ -251,7 +310,8 @@
}
} else if (matches(*argv, "src_ip") == 0) {
NEXT_ARG();
- ret = flower_parse_ip_addr(*argv, eth_type,
+ ret = flower_parse_ip_addr(*argv, vlan_ethtype ?
+ vlan_ethtype : eth_type,
TCA_FLOWER_KEY_IPV4_SRC,
TCA_FLOWER_KEY_IPV4_SRC_MASK,
TCA_FLOWER_KEY_IPV6_SRC,
@@ -477,6 +537,18 @@
fprintf(f, "\n indev %s", rta_getattr_str(attr));
}
+ if (tb[TCA_FLOWER_KEY_VLAN_ID]) {
+ struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_ID];
+
+ fprintf(f, "\n vlan_id %d", rta_getattr_u16(attr));
+ }
+
+ if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) {
+ struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_PRIO];
+
+ fprintf(f, "\n vlan_prio %d", rta_getattr_u8(attr));
+ }
+
flower_print_eth_addr(f, "dst_mac", tb[TCA_FLOWER_KEY_ETH_DST],
tb[TCA_FLOWER_KEY_ETH_DST_MASK]);
flower_print_eth_addr(f, "src_mac", tb[TCA_FLOWER_KEY_ETH_SRC],
diff --git a/tc/m_vlan.c b/tc/m_vlan.c
index ac63d9e..05a63b4 100644
--- a/tc/m_vlan.c
+++ b/tc/m_vlan.c
@@ -22,7 +22,7 @@
static void explain(void)
{
fprintf(stderr, "Usage: vlan pop\n");
- fprintf(stderr, " vlan push [ protocol VLANPROTO ] id VLANID [CONTROL]\n");
+ fprintf(stderr, " vlan push [ protocol VLANPROTO ] id VLANID [ priority VLANPRIO ] [CONTROL]\n");
fprintf(stderr, " VLANPROTO is one of 802.1Q or 802.1AD\n");
fprintf(stderr, " with default: 802.1Q\n");
fprintf(stderr, " CONTROL := reclassify | pipe | drop | continue | pass\n");
@@ -45,6 +45,8 @@
int id_set = 0;
__u16 proto;
int proto_set = 0;
+ __u8 prio;
+ int prio_set = 0;
struct tc_vlan parm = { 0 };
if (matches(*argv, "vlan") != 0)
@@ -91,6 +93,17 @@
if (ll_proto_a2n(&proto, *argv))
invarg("protocol is invalid", *argv);
proto_set = 1;
+ } else if (matches(*argv, "priority") == 0) {
+ if (action != TCA_VLAN_ACT_PUSH) {
+ fprintf(stderr, "\"%s\" is only valid for push\n",
+ *argv);
+ explain();
+ return -1;
+ }
+ NEXT_ARG();
+ if (get_u8(&prio, *argv, 0) || (prio & ~0x7))
+ invarg("prio is invalid", *argv);
+ prio_set = 1;
} else if (matches(*argv, "help") == 0) {
usage();
} else {
@@ -138,6 +151,9 @@
addattr_l(n, MAX_MSG, TCA_VLAN_PUSH_VLAN_PROTOCOL, &proto, 2);
}
+ if (prio_set)
+ addattr8(n, MAX_MSG, TCA_VLAN_PUSH_VLAN_PRIORITY, prio);
+
tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
*argc_p = argc;
@@ -180,6 +196,10 @@
ll_proto_n2a(rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]),
b1, sizeof(b1)));
}
+ if (tb[TCA_VLAN_PUSH_VLAN_PRIORITY]) {
+ val = rta_getattr_u8(tb[TCA_VLAN_PUSH_VLAN_PRIORITY]);
+ fprintf(f, " priority %u", val);
+ }
break;
}
fprintf(f, " %s", action_n2a(parm->action));
diff --git a/testsuite/tests/ip/netns/set_nsid.t b/testsuite/tests/ip/netns/set_nsid.t
new file mode 100755
index 0000000..606d45a
--- /dev/null
+++ b/testsuite/tests/ip/netns/set_nsid.t
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+source lib/generic.sh
+
+ts_log "[Testing netns nsid]"
+
+NS=testnsid
+NSID=99
+
+ts_ip "$0" "Add new netns $NS" netns add $NS
+ts_ip "$0" "Set $NS nsid to $NSID" netns set $NS $NSID
+
+ts_ip "$0" "List netns" netns list
+test_on "$NS \(id: $NSID\)"
+
+ts_ip "$0" "List netns without explicit list or show" netns
+test_on "$NS \(id: $NSID\)"
+
+ts_ip "$0" "List nsid" netns list-id
+test_on "$NSID \(iproute2 netns name: $NS\)"
+
+ts_ip "$0" "Delete netns $NS" netns del $NS
diff --git a/testsuite/tests/ip/netns/set_nsid_batch.t b/testsuite/tests/ip/netns/set_nsid_batch.t
new file mode 100755
index 0000000..abb3f1b
--- /dev/null
+++ b/testsuite/tests/ip/netns/set_nsid_batch.t
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+source lib/generic.sh
+
+ts_log "[Testing netns nsid in batch mode]"
+
+NS=testnsid
+NSID=99
+BATCHFILE=`mktemp`
+
+echo "netns add $NS" >> $BATCHFILE
+echo "netns set $NS $NSID" >> $BATCHFILE
+echo "netns list-id" >> $BATCHFILE
+ts_ip "$0" "Add ns, set nsid and list in batch mode" -b $BATCHFILE
+test_on "nsid $NSID \(iproute2 netns name: $NS\)"
+rm -f $BATCHFILE
+
+ts_ip "$0" "Delete netns $NS" netns del $NS
diff --git a/tipc/Makefile b/tipc/Makefile
index 868d13a..87e3cac 100644
--- a/tipc/Makefile
+++ b/tipc/Makefile
@@ -6,7 +6,7 @@
media.o misc.o \
msg.o nametable.o \
node.o socket.o \
- tipc.o
+ peer.o tipc.o
include ../Config
diff --git a/tipc/bearer.c b/tipc/bearer.c
index 05dabe6..810344f 100644
--- a/tipc/bearer.c
+++ b/tipc/bearer.c
@@ -14,6 +14,7 @@
#include <string.h>
#include <netdb.h>
#include <errno.h>
+#include <arpa/inet.h>
#include <linux/tipc_netlink.h>
#include <linux/tipc.h>
@@ -26,6 +27,15 @@
#include "msg.h"
#include "bearer.h"
+#define UDP_PROP_IP 1
+#define UDP_PROP_PORT 2
+
+struct cb_data {
+ int attr;
+ int prop;
+ struct nlmsghdr *nlh;
+};
+
static void _print_bearer_opts(void)
{
fprintf(stderr,
@@ -35,7 +45,7 @@
" window - Bearer link window\n");
}
-static void _print_bearer_media(void)
+void print_bearer_media(void)
{
fprintf(stderr,
"\nMEDIA\n"
@@ -57,14 +67,17 @@
static void cmd_bearer_enable_udp_help(struct cmdl *cmdl, char *media)
{
fprintf(stderr,
- "Usage: %s bearer enable media %s name NAME localip IP [OPTIONS]\n"
- "\nOPTIONS\n"
+ "Usage: %s bearer enable [OPTIONS] media %s name NAME localip IP [UDP OPTIONS]\n\n",
+ cmdl->argv[0], media);
+ fprintf(stderr,
+ "OPTIONS\n"
" domain DOMAIN - Discovery domain\n"
- " priority PRIORITY - Bearer priority\n"
+ " priority PRIORITY - Bearer priority\n\n");
+ fprintf(stderr,
+ "UDP OPTIONS\n"
" localport PORT - Local UDP port (default 6118)\n"
" remoteip IP - Remote IP address\n"
- " remoteport IP - Remote UDP port (default 6118)\n",
- cmdl->argv[0], media);
+ " remoteport PORT - Remote UDP port (default 6118)\n");
}
static int get_netid_cb(const struct nlmsghdr *nlh, void *data)
@@ -179,14 +192,28 @@
}
static int nl_add_bearer_name(struct nlmsghdr *nlh, const struct cmd *cmd,
- struct cmdl *cmdl, struct opt *opts,
- struct tipc_sup_media sup_media[])
+ struct cmdl *cmdl, struct opt *opts,
+ const struct tipc_sup_media *sup_media)
{
- char id[TIPC_MAX_BEARER_NAME];
+ char bname[TIPC_MAX_BEARER_NAME];
+ int err;
+
+ if ((err = cmd_get_unique_bearer_name(cmd, cmdl, opts, bname, sup_media)))
+ return err;
+
+ mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, bname);
+ return 0;
+}
+
+int cmd_get_unique_bearer_name(const struct cmd *cmd, struct cmdl *cmdl,
+ struct opt *opts, char *bname,
+ const struct tipc_sup_media *sup_media)
+{
char *media;
char *identifier;
struct opt *opt;
- struct tipc_sup_media *entry;
+ const struct tipc_sup_media *entry;
+
if (!(opt = get_opt(opts, "media"))) {
if (help_flag)
@@ -206,13 +233,12 @@
(entry->help)(cmdl, media);
else
fprintf(stderr, "error, missing bearer %s\n",
- entry->identifier);
+ entry->identifier);
return -EINVAL;
}
identifier = opt->val;
- snprintf(id, sizeof(id), "%s:%s", media, identifier);
- mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, id);
+ snprintf(bname, TIPC_MAX_BEARER_NAME, "%s:%s", media, identifier);
return 0;
}
@@ -222,6 +248,129 @@
return -EINVAL;
}
+static void cmd_bearer_add_udp_help(struct cmdl *cmdl, char *media)
+{
+ fprintf(stderr, "Usage: %s bearer add media %s name NAME remoteip REMOTEIP\n\n",
+ cmdl->argv[0], media);
+}
+
+static void cmd_bearer_add_help(struct cmdl *cmdl)
+{
+ fprintf(stderr, "Usage: %s bearer add media udp name NAME remoteip REMOTEIP\n",
+ cmdl->argv[0]);
+}
+
+static int udp_bearer_add(struct nlmsghdr *nlh, struct opt *opts,
+ struct cmdl *cmdl)
+{
+ int err;
+ struct opt *opt;
+ struct nlattr *opts_nest;
+ char *remport = "6118";
+
+ opts_nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_UDP_OPTS);
+
+ if ((opt = get_opt(opts, "remoteport")))
+ remport = opt->val;
+
+ if ((opt = get_opt(opts, "remoteip"))) {
+ char *ip = opt->val;
+ struct addrinfo *addr = NULL;
+ struct addrinfo hints = {
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_DGRAM
+ };
+
+ if ((err = getaddrinfo(ip, remport, &hints, &addr))) {
+ fprintf(stderr, "UDP address error: %s\n",
+ gai_strerror(err));
+ freeaddrinfo(addr);
+ return err;
+ }
+
+ mnl_attr_put(nlh, TIPC_NLA_UDP_REMOTE, addr->ai_addrlen,
+ addr->ai_addr);
+ freeaddrinfo(addr);
+ } else {
+ fprintf(stderr, "error, missing remoteip\n");
+ return -EINVAL;
+ }
+ mnl_attr_nest_end(nlh, opts_nest);
+
+ return 0;
+}
+
+static int cmd_bearer_add_media(struct nlmsghdr *nlh, const struct cmd *cmd,
+ struct cmdl *cmdl, void *data)
+{
+ int err;
+ char *media;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct opt *opt;
+ struct nlattr *attrs;
+ struct opt opts[] = {
+ { "remoteip", OPT_KEYVAL, NULL },
+ { "remoteport", OPT_KEYVAL, NULL },
+ { "name", OPT_KEYVAL, NULL },
+ { "media", OPT_KEYVAL, NULL },
+ { NULL }
+ };
+ const struct tipc_sup_media sup_media[] = {
+ { "udp", "name", cmd_bearer_add_udp_help},
+ { NULL, },
+ };
+
+ /* Rewind optind to include media in the option list */
+ cmdl->optind--;
+ if (parse_opts(opts, cmdl) < 0)
+ return -EINVAL;
+
+ if (!(opt = get_opt(opts, "media"))) {
+ fprintf(stderr, "error, missing media value\n");
+ return -EINVAL;
+ }
+ media = opt->val;
+
+ if (strcmp(media, "udp") != 0) {
+ fprintf(stderr, "error, no \"%s\" media specific options available\n",
+ media);
+ return -EINVAL;
+ }
+ if (!(opt = get_opt(opts, "name"))) {
+ fprintf(stderr, "error, missing media name\n");
+ return -EINVAL;
+ }
+
+ if (!(nlh = msg_init(buf, TIPC_NL_BEARER_ADD))) {
+ fprintf(stderr, "error, message initialisation failed\n");
+ return -1;
+ }
+
+ attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
+ err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
+ if (err)
+ return err;
+
+ err = udp_bearer_add(nlh, opts, cmdl);
+ if (err)
+ return err;
+
+ mnl_attr_nest_end(nlh, attrs);
+
+ return msg_doit(nlh, NULL, NULL);
+}
+
+static int cmd_bearer_add(struct nlmsghdr *nlh, const struct cmd *cmd,
+ struct cmdl *cmdl, void *data)
+{
+ const struct cmd cmds[] = {
+ { "media", cmd_bearer_add_media, cmd_bearer_add_help },
+ { NULL }
+ };
+
+ return run_cmd(nlh, cmd, cmds, cmdl, NULL);
+}
+
static void cmd_bearer_enable_help(struct cmdl *cmdl)
{
fprintf(stderr,
@@ -230,7 +379,7 @@
" domain DOMAIN - Discovery domain\n"
" priority PRIORITY - Bearer priority\n",
cmdl->argv[0]);
- _print_bearer_media();
+ print_bearer_media();
}
static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd,
@@ -241,21 +390,21 @@
struct nlattr *nest;
char buf[MNL_SOCKET_BUFFER_SIZE];
struct opt opts[] = {
- { "device", NULL },
- { "domain", NULL },
- { "localip", NULL },
- { "localport", NULL },
- { "media", NULL },
- { "name", NULL },
- { "priority", NULL },
- { "remoteip", NULL },
- { "remoteport", NULL },
+ { "device", OPT_KEYVAL, NULL },
+ { "domain", OPT_KEYVAL, NULL },
+ { "localip", OPT_KEYVAL, NULL },
+ { "localport", OPT_KEYVAL, NULL },
+ { "media", OPT_KEYVAL, NULL },
+ { "name", OPT_KEYVAL, NULL },
+ { "priority", OPT_KEYVAL, NULL },
+ { "remoteip", OPT_KEYVAL, NULL },
+ { "remoteport", OPT_KEYVAL, NULL },
{ NULL }
};
struct tipc_sup_media sup_media[] = {
- { "udp", "name", cmd_bearer_enable_udp_help},
- { "eth", "device", cmd_bearer_enable_l2_help },
- { "ib", "device", cmd_bearer_enable_l2_help },
+ { "udp", "name", cmd_bearer_enable_udp_help},
+ { "eth", "device", cmd_bearer_enable_l2_help },
+ { "ib", "device", cmd_bearer_enable_l2_help },
{ NULL, },
};
@@ -313,7 +462,7 @@
{
fprintf(stderr, "Usage: %s bearer disable media MEDIA ARGS...\n",
cmdl->argv[0]);
- _print_bearer_media();
+ print_bearer_media();
}
static int cmd_bearer_disable(struct nlmsghdr *nlh, const struct cmd *cmd,
@@ -323,15 +472,15 @@
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlattr *nest;
struct opt opts[] = {
- { "device", NULL },
- { "name", NULL },
- { "media", NULL },
+ { "device", OPT_KEYVAL, NULL },
+ { "name", OPT_KEYVAL, NULL },
+ { "media", OPT_KEYVAL, NULL },
{ NULL }
};
struct tipc_sup_media sup_media[] = {
- { "udp", "name", cmd_bearer_disable_udp_help},
- { "eth", "device", cmd_bearer_disable_l2_help },
- { "ib", "device", cmd_bearer_disable_l2_help },
+ { "udp", "name", cmd_bearer_disable_udp_help},
+ { "eth", "device", cmd_bearer_disable_l2_help },
+ { "ib", "device", cmd_bearer_disable_l2_help },
{ NULL, },
};
@@ -361,7 +510,7 @@
fprintf(stderr, "Usage: %s bearer set OPTION media MEDIA ARGS...\n",
cmdl->argv[0]);
_print_bearer_opts();
- _print_bearer_media();
+ print_bearer_media();
}
static void cmd_bearer_set_udp_help(struct cmdl *cmdl, char *media)
@@ -380,7 +529,7 @@
}
static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
- struct cmdl *cmdl, void *data)
+ struct cmdl *cmdl, void *data)
{
int err;
int val;
@@ -389,15 +538,15 @@
struct nlattr *props;
struct nlattr *attrs;
struct opt opts[] = {
- { "device", NULL },
- { "media", NULL },
- { "name", NULL },
+ { "device", OPT_KEYVAL, NULL },
+ { "media", OPT_KEYVAL, NULL },
+ { "name", OPT_KEYVAL, NULL },
{ NULL }
};
struct tipc_sup_media sup_media[] = {
- { "udp", "name", cmd_bearer_set_udp_help},
- { "eth", "device", cmd_bearer_set_l2_help },
- { "ib", "device", cmd_bearer_set_l2_help },
+ { "udp", "name", cmd_bearer_set_udp_help},
+ { "eth", "device", cmd_bearer_set_l2_help },
+ { "ib", "device", cmd_bearer_set_l2_help },
{ NULL, },
};
@@ -453,16 +602,22 @@
static void cmd_bearer_get_help(struct cmdl *cmdl)
{
- fprintf(stderr, "Usage: %s bearer get OPTION media MEDIA ARGS...\n",
+ fprintf(stderr, "Usage: %s bearer get [OPTION] media MEDIA ARGS...\n",
cmdl->argv[0]);
_print_bearer_opts();
- _print_bearer_media();
+ print_bearer_media();
}
static void cmd_bearer_get_udp_help(struct cmdl *cmdl, char *media)
{
- fprintf(stderr, "Usage: %s bearer get OPTION media %s name NAME\n\n",
+ fprintf(stderr, "Usage: %s bearer get [OPTION] media %s name NAME [UDP OPTIONS]\n\n",
cmdl->argv[0], media);
+ fprintf(stderr,
+ "UDP OPTIONS\n"
+ " remoteip - Remote ip address\n"
+ " remoteport - Remote port\n"
+ " localip - Local ip address\n"
+ " localport - Local port\n\n");
_print_bearer_opts();
}
@@ -474,6 +629,115 @@
_print_bearer_opts();
}
+
+static int bearer_dump_udp_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct sockaddr_storage *addr;
+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+ struct nlattr *info[TIPC_NLA_UDP_MAX + 1] = {};
+
+ mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
+
+ if (!info[TIPC_NLA_UDP_REMOTE])
+ return MNL_CB_ERROR;
+
+ addr = mnl_attr_get_payload(info[TIPC_NLA_UDP_REMOTE]);
+
+ if (addr->ss_family == AF_INET) {
+ struct sockaddr_in *ipv4 = (struct sockaddr_in *) addr;
+
+ printf("%s\n", inet_ntoa(ipv4->sin_addr));
+ } else if (addr->ss_family == AF_INET6) {
+ char straddr[INET6_ADDRSTRLEN];
+ struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *) addr;
+
+ if (!inet_ntop(AF_INET6, &ipv6->sin6_addr, straddr,
+ sizeof(straddr))) {
+ fprintf(stderr, "error, parsing IPv6 addr\n");
+ return MNL_CB_ERROR;
+ }
+ printf("%s\n", straddr);
+
+ } else {
+ return MNL_CB_ERROR;
+ }
+
+ return MNL_CB_OK;
+}
+
+static int bearer_get_udp_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct cb_data *cb_data = (struct cb_data *) data;
+ struct sockaddr_storage *addr;
+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+ struct nlattr *info[TIPC_NLA_MAX + 1] = {};
+ struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1] = {};
+ struct nlattr *opts[TIPC_NLA_UDP_MAX + 1] = {};
+
+ mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
+ if (!info[TIPC_NLA_BEARER])
+ return MNL_CB_ERROR;
+
+ mnl_attr_parse_nested(info[TIPC_NLA_BEARER], parse_attrs, attrs);
+ if (!attrs[TIPC_NLA_BEARER_UDP_OPTS])
+ return MNL_CB_ERROR;
+
+ mnl_attr_parse_nested(attrs[TIPC_NLA_BEARER_UDP_OPTS], parse_attrs, opts);
+ if (!opts[TIPC_NLA_UDP_LOCAL])
+ return MNL_CB_ERROR;
+
+ if ((cb_data->attr == TIPC_NLA_UDP_REMOTE) &&
+ (cb_data->prop == UDP_PROP_IP) &&
+ opts[TIPC_NLA_UDP_MULTI_REMOTEIP]) {
+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(cb_data->nlh);
+
+ genl->cmd = TIPC_NL_UDP_GET_REMOTEIP;
+ return msg_dumpit(cb_data->nlh, bearer_dump_udp_cb, NULL);
+ }
+
+ addr = mnl_attr_get_payload(opts[cb_data->attr]);
+
+ if (addr->ss_family == AF_INET) {
+ struct sockaddr_in *ipv4 = (struct sockaddr_in *) addr;
+
+ switch (cb_data->prop) {
+ case UDP_PROP_IP:
+ printf("%s\n", inet_ntoa(ipv4->sin_addr));
+ break;
+ case UDP_PROP_PORT:
+ printf("%u\n", ntohs(ipv4->sin_port));
+ break;
+ default:
+ return MNL_CB_ERROR;
+ }
+
+ } else if (addr->ss_family == AF_INET6) {
+ char straddr[INET6_ADDRSTRLEN];
+ struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *) addr;
+
+ switch (cb_data->prop) {
+ case UDP_PROP_IP:
+ if (!inet_ntop(AF_INET6, &ipv6->sin6_addr, straddr,
+ sizeof(straddr))) {
+ fprintf(stderr, "error, parsing IPv6 addr\n");
+ return MNL_CB_ERROR;
+ }
+ printf("%s\n", straddr);
+ break;
+ case UDP_PROP_PORT:
+ printf("%u\n", ntohs(ipv6->sin6_port));
+ break;
+ default:
+ return MNL_CB_ERROR;
+ }
+
+ } else {
+ return MNL_CB_ERROR;
+ }
+
+ return MNL_CB_OK;
+}
+
static int bearer_get_cb(const struct nlmsghdr *nlh, void *data)
{
int *prop = data;
@@ -499,6 +763,86 @@
return MNL_CB_OK;
}
+static int cmd_bearer_get_media(struct nlmsghdr *nlh, const struct cmd *cmd,
+ struct cmdl *cmdl, void *data)
+{
+ int err;
+ char *media;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct opt *opt;
+ struct cb_data cb_data = {0};
+ struct nlattr *attrs;
+ struct opt opts[] = {
+ { "localip", OPT_KEY, NULL },
+ { "localport", OPT_KEY, NULL },
+ { "remoteip", OPT_KEY, NULL },
+ { "remoteport", OPT_KEY, NULL },
+ { "name", OPT_KEYVAL, NULL },
+ { "media", OPT_KEYVAL, NULL },
+ { NULL }
+ };
+ struct tipc_sup_media sup_media[] = {
+ { "udp", "name", cmd_bearer_get_udp_help},
+ { NULL, },
+ };
+
+ /* Rewind optind to include media in the option list */
+ cmdl->optind--;
+ if (parse_opts(opts, cmdl) < 0)
+ return -EINVAL;
+
+ if (!(opt = get_opt(opts, "media"))) {
+ fprintf(stderr, "error, missing media value\n");
+ return -EINVAL;
+ }
+ media = opt->val;
+
+ if (help_flag) {
+ cmd_bearer_get_udp_help(cmdl, media);
+ return -EINVAL;
+ }
+ if (strcmp(media, "udp") != 0) {
+ fprintf(stderr, "error, no \"%s\" media specific options\n", media);
+ return -EINVAL;
+ }
+ if (!(opt = get_opt(opts, "name"))) {
+ fprintf(stderr, "error, missing media name\n");
+ return -EINVAL;
+ }
+
+ if (!(nlh = msg_init(buf, TIPC_NL_BEARER_GET))) {
+ fprintf(stderr, "error, message initialisation failed\n");
+ return -1;
+ }
+
+ attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
+ err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
+ if (err)
+ return err;
+ mnl_attr_nest_end(nlh, attrs);
+ cb_data.nlh = nlh;
+
+ if (has_opt(opts, "localip")) {
+ cb_data.attr = TIPC_NLA_UDP_LOCAL;
+ cb_data.prop = UDP_PROP_IP;
+ return msg_doit(nlh, bearer_get_udp_cb, &cb_data);
+ } else if (has_opt(opts, "localport")) {
+ cb_data.attr = TIPC_NLA_UDP_LOCAL;
+ cb_data.prop = UDP_PROP_PORT;
+ return msg_doit(nlh, bearer_get_udp_cb, &cb_data);
+ } else if (has_opt(opts, "remoteip")) {
+ cb_data.attr = TIPC_NLA_UDP_REMOTE;
+ cb_data.prop = UDP_PROP_IP;
+ return msg_doit(nlh, bearer_get_udp_cb, &cb_data);
+ } else if (has_opt(opts, "remoteport")) {
+ cb_data.attr = TIPC_NLA_UDP_REMOTE;
+ cb_data.prop = UDP_PROP_PORT;
+ return msg_doit(nlh, bearer_get_udp_cb, &cb_data);
+ }
+ fprintf(stderr, "error, missing UDP option\n");
+ return -EINVAL;
+}
+
static int cmd_bearer_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
struct cmdl *cmdl, void *data)
{
@@ -507,18 +851,23 @@
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlattr *attrs;
struct opt opts[] = {
- { "device", NULL },
- { "media", NULL },
- { "name", NULL },
+ { "device", OPT_KEYVAL, NULL },
+ { "media", OPT_KEYVAL, NULL },
+ { "name", OPT_KEYVAL, NULL },
{ NULL }
};
struct tipc_sup_media sup_media[] = {
- { "udp", "name", cmd_bearer_get_udp_help},
- { "eth", "device", cmd_bearer_get_l2_help },
- { "ib", "device", cmd_bearer_get_l2_help },
+ { "udp", "name", cmd_bearer_get_udp_help},
+ { "eth", "device", cmd_bearer_get_l2_help },
+ { "ib", "device", cmd_bearer_get_l2_help },
{ NULL, },
};
+ if (help_flag) {
+ (cmd->help)(cmdl);
+ return -EINVAL;
+ }
+
if (strcmp(cmd->cmd, "priority") == 0)
prop = TIPC_NLA_PROP_PRIO;
else if ((strcmp(cmd->cmd, "tolerance") == 0))
@@ -552,6 +901,7 @@
{ "priority", cmd_bearer_get_prop, cmd_bearer_get_help },
{ "tolerance", cmd_bearer_get_prop, cmd_bearer_get_help },
{ "window", cmd_bearer_get_prop, cmd_bearer_get_help },
+ { "media", cmd_bearer_get_media, cmd_bearer_get_help },
{ NULL }
};
@@ -605,6 +955,7 @@
"Usage: %s bearer COMMAND [ARGS] ...\n"
"\n"
"COMMANDS\n"
+ " add - Add data to existing bearer\n"
" enable - Enable a bearer\n"
" disable - Disable a bearer\n"
" set - Set various bearer properties\n"
@@ -616,6 +967,7 @@
void *data)
{
const struct cmd cmds[] = {
+ { "add", cmd_bearer_add, cmd_bearer_add_help },
{ "disable", cmd_bearer_disable, cmd_bearer_disable_help },
{ "enable", cmd_bearer_enable, cmd_bearer_enable_help },
{ "get", cmd_bearer_get, cmd_bearer_get_help },
diff --git a/tipc/bearer.h b/tipc/bearer.h
index 9459d65..c0d0996 100644
--- a/tipc/bearer.h
+++ b/tipc/bearer.h
@@ -19,4 +19,8 @@
int cmd_bearer(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data);
void cmd_bearer_help(struct cmdl *cmdl);
+void print_bearer_media(void);
+int cmd_get_unique_bearer_name(const struct cmd *cmd, struct cmdl *cmdl,
+ struct opt *opts, char *bname,
+ const struct tipc_sup_media *sup_media);
#endif
diff --git a/tipc/cmdl.c b/tipc/cmdl.c
index b816f7d..4a2f4fd 100644
--- a/tipc/cmdl.c
+++ b/tipc/cmdl.c
@@ -62,6 +62,11 @@
return NULL;
}
+bool has_opt(struct opt *opts, char *key)
+{
+ return get_opt(opts, key) ? true : false;
+}
+
char *shift_cmdl(struct cmdl *cmdl)
{
int next;
@@ -80,7 +85,7 @@
int i;
int cnt = 0;
- for (i = cmdl->optind; i < cmdl->argc; i += 2) {
+ for (i = cmdl->optind; i < cmdl->argc; i++) {
struct opt *o;
o = find_opt(opts, cmdl->argv[i]);
@@ -89,9 +94,13 @@
cmdl->argv[i]);
return -EINVAL;
}
+ if (o->flag & OPT_KEYVAL) {
+ cmdl->optind++;
+ i++;
+ }
cnt++;
- o->val = cmdl->argv[i + 1];
- cmdl->optind += 2;
+ o->val = cmdl->argv[i];
+ cmdl->optind++;
}
return cnt;
diff --git a/tipc/cmdl.h b/tipc/cmdl.h
index d4795cf..d37239f 100644
--- a/tipc/cmdl.h
+++ b/tipc/cmdl.h
@@ -16,6 +16,11 @@
extern int help_flag;
+enum {
+ OPT_KEY = (1 << 0),
+ OPT_KEYVAL = (1 << 1),
+};
+
struct cmdl {
int optind;
int argc;
@@ -37,10 +42,12 @@
struct opt {
const char *key;
+ uint16_t flag;
char *val;
};
struct opt *get_opt(struct opt *opts, char *key);
+bool has_opt(struct opt *opts, char *key);
int parse_opts(struct opt *opts, struct cmdl *cmdl);
char *shift_cmdl(struct cmdl *cmdl);
diff --git a/tipc/link.c b/tipc/link.c
index 89fb4ff..4ae1c91 100644
--- a/tipc/link.c
+++ b/tipc/link.c
@@ -22,6 +22,7 @@
#include "cmdl.h"
#include "msg.h"
#include "link.h"
+#include "bearer.h"
static int link_list_cb(const struct nlmsghdr *nlh, void *data)
{
@@ -57,7 +58,8 @@
return -EINVAL;
}
- if (!(nlh = msg_init(buf, TIPC_NL_LINK_GET))) {
+ nlh = msg_init(buf, TIPC_NL_LINK_GET);
+ if (!nlh) {
fprintf(stderr, "error, message initialisation failed\n");
return -1;
}
@@ -90,7 +92,6 @@
return MNL_CB_OK;
}
-
static int cmd_link_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
struct cmdl *cmdl, void *data)
{
@@ -98,7 +99,7 @@
char buf[MNL_SOCKET_BUFFER_SIZE];
struct opt *opt;
struct opt opts[] = {
- { "link", NULL },
+ { "link", OPT_KEYVAL, NULL },
{ NULL }
};
@@ -119,12 +120,14 @@
if (parse_opts(opts, cmdl) < 0)
return -EINVAL;
- if (!(nlh = msg_init(buf, TIPC_NL_LINK_GET))) {
+ nlh = msg_init(buf, TIPC_NL_LINK_GET);
+ if (!nlh) {
fprintf(stderr, "error, message initialisation failed\n");
return -1;
}
- if (!(opt = get_opt(opts, "link"))) {
+ opt = get_opt(opts, "link");
+ if (!opt) {
fprintf(stderr, "error, missing link\n");
return -EINVAL;
}
@@ -169,7 +172,7 @@
struct opt *opt;
struct nlattr *nest;
struct opt opts[] = {
- { "link", NULL },
+ { "link", OPT_KEYVAL, NULL },
{ NULL }
};
@@ -183,12 +186,14 @@
return -EINVAL;
}
- if (!(nlh = msg_init(buf, TIPC_NL_LINK_RESET_STATS))) {
+ nlh = msg_init(buf, TIPC_NL_LINK_RESET_STATS);
+ if (!nlh) {
fprintf(stderr, "error, message initialisation failed\n");
return -1;
}
- if (!(opt = get_opt(opts, "link"))) {
+ opt = get_opt(opts, "link");
+ if (!opt) {
fprintf(stderr, "error, missing link\n");
return -EINVAL;
}
@@ -245,8 +250,7 @@
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",
+ 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),
@@ -365,7 +369,7 @@
char buf[MNL_SOCKET_BUFFER_SIZE];
struct opt *opt;
struct opt opts[] = {
- { "link", NULL },
+ { "link", OPT_KEYVAL, NULL },
{ NULL }
};
@@ -374,7 +378,8 @@
return -EINVAL;
}
- if (!(nlh = msg_init(buf, TIPC_NL_LINK_GET))) {
+ nlh = msg_init(buf, TIPC_NL_LINK_GET);
+ if (!nlh) {
fprintf(stderr, "error, message initialisation failed\n");
return -1;
}
@@ -382,7 +387,8 @@
if (parse_opts(opts, cmdl) < 0)
return -EINVAL;
- if ((opt = get_opt(opts, "link")))
+ opt = get_opt(opts, "link");
+ if (opt)
link = opt->val;
return msg_dumpit(nlh, link_stat_show_cb, link);
@@ -429,7 +435,7 @@
struct nlattr *attrs;
struct opt *opt;
struct opt opts[] = {
- { "link", NULL },
+ { "link", OPT_KEYVAL, NULL },
{ NULL }
};
@@ -456,13 +462,15 @@
if (parse_opts(opts, cmdl) < 0)
return -EINVAL;
- if (!(nlh = msg_init(buf, TIPC_NL_LINK_SET))) {
+ nlh = msg_init(buf, TIPC_NL_LINK_SET);
+ if (!nlh) {
fprintf(stderr, "error, message initialisation failed\n");
return -1;
}
attrs = mnl_attr_nest_start(nlh, TIPC_NLA_LINK);
- if (!(opt = get_opt(opts, "link"))) {
+ opt = get_opt(opts, "link");
+ if (!opt) {
fprintf(stderr, "error, missing link\n");
return -EINVAL;
}
@@ -475,8 +483,6 @@
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,
@@ -492,6 +498,414 @@
return run_cmd(nlh, cmd, cmds, cmdl, NULL);
}
+static int cmd_link_mon_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
+ struct cmdl *cmdl, void *data)
+{
+ int size;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlattr *attrs;
+
+ if (cmdl->argc != cmdl->optind + 1) {
+ fprintf(stderr, "error, missing value\n");
+ return -EINVAL;
+ }
+ size = atoi(shift_cmdl(cmdl));
+
+ nlh = msg_init(buf, TIPC_NL_MON_SET);
+ if (!nlh) {
+ fprintf(stderr, "error, message initialisation failed\n");
+ return -1;
+ }
+ attrs = mnl_attr_nest_start(nlh, TIPC_NLA_MON);
+
+ mnl_attr_put_u32(nlh, TIPC_NLA_MON_ACTIVATION_THRESHOLD, size);
+
+ mnl_attr_nest_end(nlh, attrs);
+
+ return msg_doit(nlh, NULL, NULL);
+}
+
+static int link_mon_summary_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_MON_MAX + 1] = {};
+
+ mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
+ if (!info[TIPC_NLA_MON])
+ return MNL_CB_ERROR;
+
+ mnl_attr_parse_nested(info[TIPC_NLA_MON], parse_attrs, attrs);
+
+ printf("\nbearer %s\n",
+ mnl_attr_get_str(attrs[TIPC_NLA_MON_BEARER_NAME]));
+
+ printf(" table_generation %u\n",
+ mnl_attr_get_u32(attrs[TIPC_NLA_MON_LISTGEN]));
+ printf(" cluster_size %u\n",
+ mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEERCNT]));
+ printf(" algorithm %s\n",
+ attrs[TIPC_NLA_MON_ACTIVE] ? "overlapping-ring" : "full-mesh");
+
+ return MNL_CB_OK;
+}
+
+static int cmd_link_mon_summary(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 monitor summary\n", cmdl->argv[0]);
+ return -EINVAL;
+ }
+
+ nlh = msg_init(buf, TIPC_NL_MON_GET);
+ if (!nlh) {
+ fprintf(stderr, "error, message initialisation failed\n");
+ return -1;
+ }
+
+ return msg_dumpit(nlh, link_mon_summary_cb, NULL);
+}
+
+#define STATUS_WIDTH 7
+#define MAX_NODE_WIDTH 14 /* 255.4095.4095 */
+#define MAX_DOM_GEN_WIDTH 11 /* 65535 */
+#define DIRECTLY_MON_WIDTH 10
+
+#define APPL_NODE_STATUS_WIDTH 5
+
+static int map_get(uint64_t up_map, int i)
+{
+ return (up_map & (1 << i)) >> i;
+}
+
+/* print the applied members, since we know the the members
+ * are listed in ascending order, we print only the state
+ */
+static void link_mon_print_applied(uint16_t applied, uint64_t up_map)
+{
+ int i;
+ char state;
+
+ for (i = 0; i < applied; i++) {
+ /* print the delimiter for every -n- entry */
+ if (i && !(i % APPL_NODE_STATUS_WIDTH))
+ printf(",");
+
+ state = map_get(up_map, i) ? 'U' : 'D';
+ printf("%c", state);
+ }
+}
+
+/* print the non applied members, since we dont know
+ * the members, we print them along with the state
+ */
+static void link_mon_print_non_applied(uint16_t applied, uint16_t member_cnt,
+ uint64_t up_map, uint32_t *members)
+{
+ int i;
+ char state;
+
+ printf(" [");
+ for (i = applied; i < member_cnt; i++) {
+ char addr_str[16];
+
+ /* print the delimiter for every entry */
+ if (i != applied)
+ printf(",");
+
+ sprintf(addr_str, "%u.%u.%u:", tipc_zone(members[i]),
+ tipc_cluster(members[i]), tipc_node(members[i]));
+ state = map_get(up_map, i) ? 'U' : 'D';
+ printf("%s%c", addr_str, state);
+ }
+ printf("]");
+}
+
+static void link_mon_print_peer_state(const uint32_t addr, const char *status,
+ const char *monitored,
+ const uint32_t dom_gen)
+{
+ char addr_str[16];
+
+ sprintf(addr_str, "%u.%u.%u", tipc_zone(addr), tipc_cluster(addr),
+ tipc_node(addr));
+
+ printf("%-*s", MAX_NODE_WIDTH, addr_str);
+ printf("%-*s", STATUS_WIDTH, status);
+ printf("%-*s", DIRECTLY_MON_WIDTH, monitored);
+ printf("%-*u", MAX_DOM_GEN_WIDTH, dom_gen);
+}
+
+static int link_mon_peer_list_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+ struct nlattr *attrs[TIPC_NLA_MON_PEER_MAX + 1] = {};
+ struct nlattr *info[TIPC_NLA_MAX + 1] = {};
+ uint16_t member_cnt;
+ uint32_t applied;
+ uint32_t dom_gen;
+ uint64_t up_map;
+ char status[16];
+ char monitored[16];
+
+ mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
+ if (!info[TIPC_NLA_MON_PEER])
+ return MNL_CB_ERROR;
+
+ mnl_attr_parse_nested(info[TIPC_NLA_MON_PEER], parse_attrs, attrs);
+
+ (attrs[TIPC_NLA_MON_PEER_LOCAL] || attrs[TIPC_NLA_MON_PEER_HEAD]) ?
+ strcpy(monitored, "direct") :
+ strcpy(monitored, "indirect");
+
+ attrs[TIPC_NLA_MON_PEER_UP] ?
+ strcpy(status, "up") :
+ strcpy(status, "down");
+
+ dom_gen = attrs[TIPC_NLA_MON_PEER_DOMGEN] ?
+ mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEER_DOMGEN]) : 0;
+
+ link_mon_print_peer_state(mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEER_ADDR]),
+ status, monitored, dom_gen);
+
+ applied = mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEER_APPLIED]);
+
+ if (!applied)
+ goto exit;
+
+ up_map = mnl_attr_get_u64(attrs[TIPC_NLA_MON_PEER_UPMAP]);
+
+ member_cnt = mnl_attr_get_payload_len(attrs[TIPC_NLA_MON_PEER_MEMBERS]);
+
+ /* each tipc address occupies 4 bytes of payload, hence compensate it */
+ member_cnt /= sizeof(uint32_t);
+
+ link_mon_print_applied(applied, up_map);
+
+ link_mon_print_non_applied(applied, member_cnt, up_map,
+ mnl_attr_get_payload(attrs[TIPC_NLA_MON_PEER_MEMBERS]));
+
+exit:
+ printf("\n");
+
+ return MNL_CB_OK;
+}
+
+static int link_mon_peer_list(uint32_t mon_ref)
+{
+ struct nlmsghdr *nlh;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlattr *nest;
+
+ nlh = msg_init(buf, TIPC_NL_MON_PEER_GET);
+ if (!nlh) {
+ fprintf(stderr, "error, message initialisation failed\n");
+ return -1;
+ }
+
+ nest = mnl_attr_nest_start(nlh, TIPC_NLA_MON);
+ mnl_attr_put_u32(nlh, TIPC_NLA_MON_REF, mon_ref);
+ mnl_attr_nest_end(nlh, nest);
+
+ return msg_dumpit(nlh, link_mon_peer_list_cb, NULL);
+}
+
+static int link_mon_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_MON_MAX + 1] = {};
+ char *req_bearer = data;
+ const char *bname;
+ const char title[] =
+ "node status monitored generation applied_node_status [non_applied_node:status]";
+
+ mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
+ if (!info[TIPC_NLA_MON])
+ return MNL_CB_ERROR;
+
+ mnl_attr_parse_nested(info[TIPC_NLA_MON], parse_attrs, attrs);
+
+ bname = mnl_attr_get_str(attrs[TIPC_NLA_MON_BEARER_NAME]);
+
+ if (*req_bearer && (strcmp(req_bearer, bname) != 0))
+ return MNL_CB_OK;
+
+ printf("\nbearer %s\n", bname);
+ printf("%s\n", title);
+
+ if (mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEERCNT]))
+ link_mon_peer_list(mnl_attr_get_u32(attrs[TIPC_NLA_MON_REF]));
+
+ return MNL_CB_OK;
+}
+
+static void cmd_link_mon_list_help(struct cmdl *cmdl)
+{
+ fprintf(stderr, "Usage: %s monitor list [ media MEDIA ARGS...]\n\n",
+ cmdl->argv[0]);
+ print_bearer_media();
+}
+
+static void cmd_link_mon_list_l2_help(struct cmdl *cmdl, char *media)
+{
+ fprintf(stderr,
+ "Usage: %s monitor list media %s device DEVICE [OPTIONS]\n",
+ cmdl->argv[0], media);
+}
+
+static void cmd_link_mon_list_udp_help(struct cmdl *cmdl, char *media)
+{
+ fprintf(stderr,
+ "Usage: %s monitor list media udp name NAME\n\n",
+ cmdl->argv[0]);
+}
+
+static int cmd_link_mon_list(struct nlmsghdr *nlh, const struct cmd *cmd,
+ struct cmdl *cmdl, void *data)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ char bname[TIPC_MAX_BEARER_NAME] = {0};
+ struct opt opts[] = {
+ { "media", OPT_KEYVAL, NULL },
+ { "device", OPT_KEYVAL, NULL },
+ { "name", OPT_KEYVAL, NULL },
+ { NULL }
+ };
+ struct tipc_sup_media sup_media[] = {
+ { "udp", "name", cmd_link_mon_list_udp_help},
+ { "eth", "device", cmd_link_mon_list_l2_help },
+ { "ib", "device", cmd_link_mon_list_l2_help },
+ { NULL, },
+ };
+
+ int err;
+
+ if (parse_opts(opts, cmdl) < 0)
+ return -EINVAL;
+
+ if (get_opt(opts, "media")) {
+ err = cmd_get_unique_bearer_name(cmd, cmdl, opts, bname,
+ sup_media);
+ if (err)
+ return err;
+ }
+
+ if (help_flag) {
+ cmd->help(cmdl);
+ return -EINVAL;
+ }
+
+ nlh = msg_init(buf, TIPC_NL_MON_GET);
+ if (!nlh) {
+ fprintf(stderr, "error, message initialisation failed\n");
+ return -1;
+ }
+
+ return msg_dumpit(nlh, link_mon_list_cb, bname);
+}
+
+static void cmd_link_mon_set_help(struct cmdl *cmdl)
+{
+ fprintf(stderr, "Usage: %s monitor set PPROPERTY\n\n"
+ "PROPERTIES\n"
+ " threshold SIZE - Set monitor activation threshold\n",
+ cmdl->argv[0]);
+}
+
+static int cmd_link_mon_set(struct nlmsghdr *nlh, const struct cmd *cmd,
+ struct cmdl *cmdl, void *data)
+{
+ const struct cmd cmds[] = {
+ { "threshold", cmd_link_mon_set_prop, NULL },
+ { NULL }
+ };
+
+ return run_cmd(nlh, cmd, cmds, cmdl, NULL);
+}
+
+static void cmd_link_mon_get_help(struct cmdl *cmdl)
+{
+ fprintf(stderr, "Usage: %s monitor get PPROPERTY\n\n"
+ "PROPERTIES\n"
+ " threshold - Get monitor activation threshold\n",
+ cmdl->argv[0]);
+}
+
+static int link_mon_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_MON_MAX + 1] = {};
+
+ mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
+ if (!info[TIPC_NLA_MON])
+ return MNL_CB_ERROR;
+
+ mnl_attr_parse_nested(info[TIPC_NLA_MON], parse_attrs, attrs);
+ if (!attrs[TIPC_NLA_MON_ACTIVATION_THRESHOLD])
+ return MNL_CB_ERROR;
+
+ printf("%u\n",
+ mnl_attr_get_u32(attrs[TIPC_NLA_MON_ACTIVATION_THRESHOLD]));
+
+ return MNL_CB_OK;
+}
+
+static int cmd_link_mon_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
+ struct cmdl *cmdl, void *data)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+
+ nlh = msg_init(buf, TIPC_NL_MON_GET);
+ if (!nlh) {
+ fprintf(stderr, "error, message initialisation failed\n");
+ return -1;
+ }
+
+ return msg_doit(nlh, link_mon_get_cb, NULL);
+}
+
+static int cmd_link_mon_get(struct nlmsghdr *nlh, const struct cmd *cmd,
+ struct cmdl *cmdl, void *data)
+{
+ const struct cmd cmds[] = {
+ { "threshold", cmd_link_mon_get_prop, NULL},
+ { NULL }
+ };
+
+ return run_cmd(nlh, cmd, cmds, cmdl, NULL);
+}
+
+static void cmd_link_mon_help(struct cmdl *cmdl)
+{
+ fprintf(stderr,
+ "Usage: %s montior COMMAND [ARGS] ...\n\n"
+ "COMMANDS\n"
+ " set - Set monitor properties\n"
+ " get - Get monitor properties\n"
+ " list - List all cluster members\n"
+ " summary - Show local node monitor summary\n",
+ cmdl->argv[0]);
+}
+
+static int cmd_link_mon(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl,
+ void *data)
+{
+ const struct cmd cmds[] = {
+ { "set", cmd_link_mon_set, cmd_link_mon_set_help },
+ { "get", cmd_link_mon_get, cmd_link_mon_get_help },
+ { "list", cmd_link_mon_list, cmd_link_mon_list_help },
+ { "summary", cmd_link_mon_summary, NULL },
+ { NULL }
+ };
+
+ return run_cmd(nlh, cmd, cmds, cmdl, NULL);
+}
+
void cmd_link_help(struct cmdl *cmdl)
{
fprintf(stderr,
@@ -501,7 +915,8 @@
" list - List links\n"
" get - Get various link properties\n"
" set - Set various link properties\n"
- " statistics - Show or reset statistics\n",
+ " statistics - Show or reset statistics\n"
+ " monitor - Show or set link supervision\n",
cmdl->argv[0]);
}
@@ -513,6 +928,7 @@
{ "list", cmd_link_list, NULL },
{ "set", cmd_link_set, cmd_link_set_help },
{ "statistics", cmd_link_stat, cmd_link_stat_help },
+ { "monitor", cmd_link_mon, cmd_link_mon_help },
{ NULL }
};
diff --git a/tipc/media.c b/tipc/media.c
index a902ab7..6e10c7e 100644
--- a/tipc/media.c
+++ b/tipc/media.c
@@ -93,7 +93,7 @@
struct nlattr *nest;
struct opt *opt;
struct opt opts[] = {
- { "media", NULL },
+ { "media", OPT_KEYVAL, NULL },
{ NULL }
};
@@ -173,7 +173,7 @@
struct nlattr *attrs;
struct opt *opt;
struct opt opts[] = {
- { "media", NULL },
+ { "media", OPT_KEYVAL, NULL },
{ NULL }
};
diff --git a/tipc/peer.c b/tipc/peer.c
new file mode 100644
index 0000000..de0c73c
--- /dev/null
+++ b/tipc/peer.c
@@ -0,0 +1,93 @@
+/*
+ * peer.c TIPC peer 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 "peer.h"
+
+static int cmd_peer_rm_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) || help_flag) {
+ fprintf(stderr, "Usage: %s peer remove 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_PEER_REMOVE))) {
+ 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 void cmd_peer_rm_help(struct cmdl *cmdl)
+{
+ fprintf(stderr, "Usage: %s peer remove address ADDRESS\n",
+ cmdl->argv[0]);
+}
+
+static int cmd_peer_rm(struct nlmsghdr *nlh, const struct cmd *cmd,
+ struct cmdl *cmdl, void *data)
+{
+ const struct cmd cmds[] = {
+ { "address", cmd_peer_rm_addr, cmd_peer_rm_help },
+ { NULL }
+ };
+
+ return run_cmd(nlh, cmd, cmds, cmdl, NULL);
+}
+
+void cmd_peer_help(struct cmdl *cmdl)
+{
+ fprintf(stderr,
+ "Usage: %s peer COMMAND [ARGS] ...\n\n"
+ "COMMANDS\n"
+ " remove - Remove an offline peer node\n",
+ cmdl->argv[0]);
+}
+
+int cmd_peer(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl,
+ void *data)
+{
+ const struct cmd cmds[] = {
+ { "remove", cmd_peer_rm, cmd_peer_rm_help },
+ { NULL }
+ };
+
+ return run_cmd(nlh, cmd, cmds, cmdl, NULL);
+}
diff --git a/tipc/peer.h b/tipc/peer.h
new file mode 100644
index 0000000..8972261
--- /dev/null
+++ b/tipc/peer.h
@@ -0,0 +1,21 @@
+/*
+ * peer.h TIPC peer 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_PEER_H
+#define _TIPC_PEER_H
+
+extern int help_flag;
+
+int cmd_peer(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl,
+ void *data);
+void cmd_peer_help(struct cmdl *cmdl);
+
+#endif
diff --git a/tipc/tipc.c b/tipc/tipc.c
index 4439805..600d5e2 100644
--- a/tipc/tipc.c
+++ b/tipc/tipc.c
@@ -20,6 +20,7 @@
#include "socket.h"
#include "media.h"
#include "node.h"
+#include "peer.h"
#include "cmdl.h"
int help_flag;
@@ -39,6 +40,7 @@
" media - Show or modify media\n"
" nametable - Show nametable\n"
" node - Show or modify node related parameters\n"
+ " peer - Peer related operations\n"
" socket - Show sockets\n",
cmdl->argv[0]);
}
@@ -59,6 +61,7 @@
{ "media", cmd_media, cmd_media_help},
{ "nametable", cmd_nametable, cmd_nametable_help},
{ "node", cmd_node, cmd_node_help},
+ { "peer", cmd_peer, cmd_peer_help},
{ "socket", cmd_socket, cmd_socket_help},
{ NULL }
};