Merge branch 'master' into net-next

This commit is contained in:
Stephen Hemminger 2016-12-01 10:29:12 -08:00
commit 328374dcfe
24 changed files with 1893 additions and 262 deletions

View File

@ -28,6 +28,10 @@
#define ESWITCH_MODE_LEGACY "legacy"
#define ESWITCH_MODE_SWITCHDEV "switchdev"
#define ESWITCH_INLINE_MODE_NONE "none"
#define ESWITCH_INLINE_MODE_LINK "link"
#define ESWITCH_INLINE_MODE_NETWORK "network"
#define ESWITCH_INLINE_MODE_TRANSPORT "transport"
#define pr_err(args...) fprintf(stderr, ##args)
#define pr_out(args...) fprintf(stdout, ##args)
@ -132,6 +136,7 @@ static void ifname_map_free(struct ifname_map *ifname_map)
#define DL_OPT_SB_TH BIT(9)
#define DL_OPT_SB_TC BIT(10)
#define DL_OPT_ESWITCH_MODE BIT(11)
#define DL_OPT_ESWITCH_INLINE_MODE BIT(12)
struct dl_opts {
uint32_t present; /* flags of present items */
@ -148,6 +153,7 @@ struct dl_opts {
uint32_t sb_threshold;
uint16_t sb_tc_index;
enum devlink_eswitch_mode eswitch_mode;
enum devlink_eswitch_inline_mode eswitch_inline_mode;
};
struct dl {
@ -305,6 +311,9 @@ static int attr_cb(const struct nlattr *attr, void *data)
if (type == DEVLINK_ATTR_ESWITCH_MODE &&
mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
return MNL_CB_ERROR;
if (type == DEVLINK_ATTR_ESWITCH_INLINE_MODE &&
mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
return MNL_CB_ERROR;
tb[type] = attr;
return MNL_CB_OK;
}
@ -682,6 +691,24 @@ static int eswitch_mode_get(const char *typestr,
return 0;
}
static int eswitch_inline_mode_get(const char *typestr,
enum devlink_eswitch_inline_mode *p_mode)
{
if (strcmp(typestr, ESWITCH_INLINE_MODE_NONE) == 0) {
*p_mode = DEVLINK_ESWITCH_INLINE_MODE_NONE;
} else if (strcmp(typestr, ESWITCH_INLINE_MODE_LINK) == 0) {
*p_mode = DEVLINK_ESWITCH_INLINE_MODE_LINK;
} else if (strcmp(typestr, ESWITCH_INLINE_MODE_NETWORK) == 0) {
*p_mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK;
} else if (strcmp(typestr, ESWITCH_INLINE_MODE_TRANSPORT) == 0) {
*p_mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT;
} else {
pr_err("Unknown eswitch inline mode \"%s\"\n", typestr);
return -EINVAL;
}
return 0;
}
static int dl_argv_parse(struct dl *dl, uint32_t o_required,
uint32_t o_optional)
{
@ -803,6 +830,19 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required,
if (err)
return err;
o_found |= DL_OPT_ESWITCH_MODE;
} else if (dl_argv_match(dl, "inline-mode") &&
(o_all & DL_OPT_ESWITCH_INLINE_MODE)) {
const char *typestr;
dl_arg_inc(dl);
err = dl_argv_str(dl, &typestr);
if (err)
return err;
err = eswitch_inline_mode_get(
typestr, &opts->eswitch_inline_mode);
if (err)
return err;
o_found |= DL_OPT_ESWITCH_INLINE_MODE;
} else {
pr_err("Unknown option \"%s\"\n", dl_argv(dl));
return -EINVAL;
@ -863,6 +903,12 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required,
return -EINVAL;
}
if ((o_required & DL_OPT_ESWITCH_INLINE_MODE) &&
!(o_found & DL_OPT_ESWITCH_INLINE_MODE)) {
pr_err("E-Switch inline-mode option expected.\n");
return -EINVAL;
}
return 0;
}
@ -909,6 +955,9 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
if (opts->present & DL_OPT_ESWITCH_MODE)
mnl_attr_put_u16(nlh, DEVLINK_ATTR_ESWITCH_MODE,
opts->eswitch_mode);
if (opts->present & DL_OPT_ESWITCH_INLINE_MODE)
mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
opts->eswitch_inline_mode);
}
static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl,
@ -963,6 +1012,9 @@ static bool dl_dump_filter(struct dl *dl, struct nlattr **tb)
static void cmd_dev_help(void)
{
pr_err("Usage: devlink dev show [ DEV ]\n");
pr_err(" devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n");
pr_err(" [ inline-mode { none | link | network | transport } ]\n");
pr_err(" devlink dev eswitch show DEV\n");
}
static bool cmp_arr_last_handle(struct dl *dl, const char *bus_name,
@ -1201,6 +1253,22 @@ static const char *eswitch_mode_name(uint32_t mode)
}
}
static const char *eswitch_inline_mode_name(uint32_t mode)
{
switch (mode) {
case DEVLINK_ESWITCH_INLINE_MODE_NONE:
return ESWITCH_INLINE_MODE_NONE;
case DEVLINK_ESWITCH_INLINE_MODE_LINK:
return ESWITCH_INLINE_MODE_LINK;
case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
return ESWITCH_INLINE_MODE_NETWORK;
case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
return ESWITCH_INLINE_MODE_TRANSPORT;
default:
return "<unknown mode>";
}
}
static void pr_out_eswitch(struct dl *dl, struct nlattr **tb)
{
__pr_out_handle_start(dl, tb, true, false);
@ -1208,6 +1276,12 @@ static void pr_out_eswitch(struct dl *dl, struct nlattr **tb)
if (tb[DEVLINK_ATTR_ESWITCH_MODE])
pr_out_str(dl, "mode",
eswitch_mode_name(mnl_attr_get_u16(tb[DEVLINK_ATTR_ESWITCH_MODE])));
if (tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE])
pr_out_str(dl, "inline-mode",
eswitch_inline_mode_name(mnl_attr_get_u8(
tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE])));
pr_out_handle_end(dl);
}
@ -1250,16 +1324,27 @@ static int cmd_dev_eswitch_set(struct dl *dl)
nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_MODE_SET,
NLM_F_REQUEST | NLM_F_ACK);
err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_ESWITCH_MODE, 0);
err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE,
DL_OPT_ESWITCH_MODE |
DL_OPT_ESWITCH_INLINE_MODE);
if (err)
return err;
if (dl->opts.present == 1) {
pr_err("Need to set at least one option\n");
return -ENOENT;
}
return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
}
static int cmd_dev_eswitch(struct dl *dl)
{
if (dl_argv_match(dl, "set")) {
if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
cmd_dev_help();
return 0;
} else if (dl_argv_match(dl, "set")) {
dl_arg_inc(dl);
return cmd_dev_eswitch_set(dl);
} else if (dl_argv_match(dl, "show")) {

1005
include/linux/sctp.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -148,11 +148,11 @@ static void print_operstate(FILE *f, __u8 state)
fprintf(f, "state %#x ", state);
} else if (brief) {
color_fprintf(f, oper_state_color(state),
"%-14s ", oper_states[state]);
"%-14s ", oper_states[state]);
} else {
fprintf(f, "state ");
color_fprintf(f, oper_state_color(state),
"%s ", oper_states[state]);
"%s ", oper_states[state]);
}
}
@ -322,10 +322,7 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
{
struct ifla_vf_mac *vf_mac;
struct ifla_vf_tx_rate *vf_tx_rate;
struct ifla_vf_spoofchk *vf_spoofchk;
struct ifla_vf_link_state *vf_linkstate;
struct rtattr *vf[IFLA_VF_MAX + 1] = {};
struct rtattr *tmp;
SPRINT_BUF(b1);
@ -339,31 +336,6 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
vf_mac = RTA_DATA(vf[IFLA_VF_MAC]);
vf_tx_rate = RTA_DATA(vf[IFLA_VF_TX_RATE]);
/* Check if the spoof checking vf info type is supported by
* this kernel.
*/
tmp = (struct rtattr *)((char *)vf[IFLA_VF_TX_RATE] +
vf[IFLA_VF_TX_RATE]->rta_len);
if (tmp->rta_type != IFLA_VF_SPOOFCHK)
vf_spoofchk = NULL;
else
vf_spoofchk = RTA_DATA(vf[IFLA_VF_SPOOFCHK]);
if (vf_spoofchk) {
/* Check if the link state vf info type is supported by
* this kernel.
*/
tmp = (struct rtattr *)((char *)vf[IFLA_VF_SPOOFCHK] +
vf[IFLA_VF_SPOOFCHK]->rta_len);
if (tmp->rta_type != IFLA_VF_LINK_STATE)
vf_linkstate = NULL;
else
vf_linkstate = RTA_DATA(vf[IFLA_VF_LINK_STATE]);
} else
vf_linkstate = NULL;
fprintf(fp, "%s vf %d MAC %s", _SL_, vf_mac->vf,
ll_addr_n2a((unsigned char *)&vf_mac->mac,
ETH_ALEN, 0, b1, sizeof(b1)));
@ -407,14 +379,18 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
if (vf_rate->min_tx_rate)
fprintf(fp, ", min_tx_rate %dMbps", vf_rate->min_tx_rate);
}
if (vf[IFLA_VF_SPOOFCHK]) {
struct ifla_vf_spoofchk *vf_spoofchk =
RTA_DATA(vf[IFLA_VF_SPOOFCHK]);
if (vf_spoofchk && vf_spoofchk->setting != -1) {
if (vf_spoofchk->setting)
fprintf(fp, ", spoof checking on");
else
fprintf(fp, ", spoof checking off");
if (vf_spoofchk->setting != -1)
fprintf(fp, ", spoof checking %s",
vf_spoofchk->setting ? "on" : "off");
}
if (vf_linkstate) {
if (vf[IFLA_VF_LINK_STATE]) {
struct ifla_vf_link_state *vf_linkstate =
RTA_DATA(vf[IFLA_VF_LINK_STATE]);
if (vf_linkstate->link_state == IFLA_VF_LINK_STATE_AUTO)
fprintf(fp, ", link-state auto");
else if (vf_linkstate->link_state == IFLA_VF_LINK_STATE_ENABLE)
@ -427,7 +403,23 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
if (vf_trust->setting != -1)
fprintf(fp, ", trust %s",
vf_trust->setting ? "on" : "off");
vf_trust->setting ? "on" : "off");
}
if (vf[IFLA_VF_RSS_QUERY_EN]) {
struct ifla_vf_rss_query_en *rss_query =
RTA_DATA(vf[IFLA_VF_RSS_QUERY_EN]);
if (rss_query->setting != -1)
fprintf(fp, ", query_rss %s",
rss_query->setting ? "on" : "off");
}
if (vf[IFLA_VF_RSS_QUERY_EN]) {
struct ifla_vf_rss_query_en *rss_query =
RTA_DATA(vf[IFLA_VF_RSS_QUERY_EN]);
if (rss_query->setting != -1)
fprintf(fp, ", query_rss %s",
rss_query->setting ? "on" : "off");
}
if (vf[IFLA_VF_STATS] && show_stats)
print_vf_stats64(fp, vf[IFLA_VF_STATS]);
@ -448,7 +440,8 @@ static void print_num(FILE *fp, unsigned int width, uint64_t count)
}
/* increase value by a factor of 1000/1024 and print
* if result is something a human can read */
* if result is something a human can read
*/
for (;;) {
powi *= base;
if (count / base < powi)
@ -691,9 +684,9 @@ int print_linkinfo_brief(const struct sockaddr_nl *who,
return -1;
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
if (tb[IFLA_IFNAME] == NULL) {
if (tb[IFLA_IFNAME] == NULL)
fprintf(stderr, "BUG: device with ifindex %d has nil ifname\n", ifi->ifi_index);
}
if (filter.label &&
(!filter.family || filter.family == AF_PACKET) &&
fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0))
@ -787,9 +780,9 @@ int print_linkinfo(const struct sockaddr_nl *who,
return 0;
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
if (tb[IFLA_IFNAME] == NULL) {
if (tb[IFLA_IFNAME] == NULL)
fprintf(stderr, "BUG: device with ifindex %d has nil ifname\n", ifi->ifi_index);
}
if (filter.label &&
(!filter.family || filter.family == AF_PACKET) &&
fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0))
@ -1118,16 +1111,16 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
if (rta_tb[IFA_LOCAL]) {
color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s",
format_host_rta(ifa->ifa_family,
rta_tb[IFA_LOCAL]));
format_host_rta(ifa->ifa_family,
rta_tb[IFA_LOCAL]));
if (rta_tb[IFA_ADDRESS] &&
memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]),
RTA_DATA(rta_tb[IFA_LOCAL]),
ifa->ifa_family == AF_INET ? 4 : 16)) {
RTA_DATA(rta_tb[IFA_LOCAL]),
ifa->ifa_family == AF_INET ? 4 : 16)) {
fprintf(fp, " peer ");
color_fprintf(fp, ifa_family_color(ifa->ifa_family),
"%s", format_host_rta(ifa->ifa_family,
rta_tb[IFA_ADDRESS]));
"%s", format_host_rta(ifa->ifa_family,
rta_tb[IFA_ADDRESS]));
}
fprintf(fp, "/%d ", ifa->ifa_prefixlen);
}
@ -1138,14 +1131,14 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
if (rta_tb[IFA_BROADCAST]) {
fprintf(fp, "brd ");
color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s ",
format_host_rta(ifa->ifa_family,
rta_tb[IFA_BROADCAST]));
format_host_rta(ifa->ifa_family,
rta_tb[IFA_BROADCAST]));
}
if (rta_tb[IFA_ANYCAST]) {
fprintf(fp, "any ");
color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s ",
format_host_rta(ifa->ifa_family,
rta_tb[IFA_ANYCAST]));
format_host_rta(ifa->ifa_family,
rta_tb[IFA_ANYCAST]));
}
fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1)));
if (ifa_flags & IFA_F_SECONDARY) {
@ -1184,9 +1177,9 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
ifa_flags &= ~IFA_F_MCAUTOJOIN;
fprintf(fp, "autojoin ");
}
if (!(ifa_flags & IFA_F_PERMANENT)) {
if (!(ifa_flags & IFA_F_PERMANENT))
fprintf(fp, "dynamic ");
} else
else
ifa_flags &= ~IFA_F_PERMANENT;
if (ifa_flags & IFA_F_DADFAILED) {
ifa_flags &= ~IFA_F_DADFAILED;
@ -1672,9 +1665,9 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
filter.kind = *argv;
}
} else {
if (strcmp(*argv, "dev") == 0) {
if (strcmp(*argv, "dev") == 0)
NEXT_ARG();
} else if (matches(*argv, "help") == 0)
else if (matches(*argv, "help") == 0)
usage();
if (filter_dev)
duparg2("dev", *argv);
@ -1979,9 +1972,8 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
} else if (strcmp(*argv, "autojoin") == 0) {
ifa_flags |= IFA_F_MCAUTOJOIN;
} else {
if (strcmp(*argv, "local") == 0) {
if (strcmp(*argv, "local") == 0)
NEXT_ARG();
}
if (matches(*argv, "help") == 0)
usage();
if (local_len)
@ -2012,9 +2004,9 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
if (peer_len == 0 && local_len) {
if (cmd == RTM_DELADDR && lcl.family == AF_INET && !(lcl.flags & PREFIXLEN_SPECIFIED)) {
fprintf(stderr,
"Warning: Executing wildcard deletion to stay compatible with old scripts.\n" \
" Explicitly specify the prefix length (%s/%d) to avoid this warning.\n" \
" This special behaviour is likely to disappear in further releases,\n" \
"Warning: Executing wildcard deletion to stay compatible with old scripts.\n"
" Explicitly specify the prefix length (%s/%d) to avoid this warning.\n"
" This special behaviour is likely to disappear in further releases,\n"
" fix your scripts!\n", lcl_arg, local_len*8);
} else {
peer = lcl;

View File

@ -56,15 +56,15 @@ struct l2tp_parm {
uint16_t pw_type;
uint16_t mtu;
int udp6_csum_tx:1;
int udp6_csum_rx:1;
int udp_csum:1;
int recv_seq:1;
int send_seq:1;
int lns_mode:1;
int data_seq:2;
int tunnel:1;
int session:1;
unsigned int udp6_csum_tx:1;
unsigned int udp6_csum_rx:1;
unsigned int udp_csum:1;
unsigned int recv_seq:1;
unsigned int send_seq:1;
unsigned int lns_mode:1;
unsigned int data_seq:2;
unsigned int tunnel:1;
unsigned int session:1;
int reorder_timeout;
const char *ifname;
uint8_t l2spec_type;
@ -110,17 +110,19 @@ static int create_tunnel(struct l2tp_parm *p)
if (p->local_ip.family == AF_INET6)
local_attr = L2TP_ATTR_IP6_SADDR;
addattr_l(&req.n, 1024, local_attr, &p->local_ip.data, p->local_ip.bytelen);
addattr_l(&req.n, 1024, local_attr, &p->local_ip.data,
p->local_ip.bytelen);
if (p->peer_ip.family == AF_INET6)
peer_attr = L2TP_ATTR_IP6_DADDR;
addattr_l(&req.n, 1024, peer_attr, &p->peer_ip.data, p->peer_ip.bytelen);
addattr_l(&req.n, 1024, peer_attr, &p->peer_ip.data,
p->peer_ip.bytelen);
if (p->encap == L2TP_ENCAPTYPE_UDP) {
addattr16(&req.n, 1024, L2TP_ATTR_UDP_SPORT, p->local_udp_port);
addattr16(&req.n, 1024, L2TP_ATTR_UDP_DPORT, p->peer_udp_port);
if (p->udp_csum)
addattr(&req.n, 1024, L2TP_ATTR_UDP_CSUM);
addattr8(&req.n, 1024, L2TP_ATTR_UDP_CSUM, 1);
if (!p->udp6_csum_tx)
addattr(&req.n, 1024, L2TP_ATTR_UDP_ZERO_CSUM6_TX);
if (!p->udp6_csum_rx)
@ -159,18 +161,27 @@ static int create_session(struct l2tp_parm *p)
addattr8(&req.n, 1024, L2TP_ATTR_L2SPEC_TYPE, p->l2spec_type);
addattr8(&req.n, 1024, L2TP_ATTR_L2SPEC_LEN, p->l2spec_len);
if (p->mtu) addattr16(&req.n, 1024, L2TP_ATTR_MTU, p->mtu);
if (p->recv_seq) addattr(&req.n, 1024, L2TP_ATTR_RECV_SEQ);
if (p->send_seq) addattr(&req.n, 1024, L2TP_ATTR_SEND_SEQ);
if (p->lns_mode) addattr(&req.n, 1024, L2TP_ATTR_LNS_MODE);
if (p->data_seq) addattr8(&req.n, 1024, L2TP_ATTR_DATA_SEQ, p->data_seq);
if (p->reorder_timeout) addattr64(&req.n, 1024, L2TP_ATTR_RECV_TIMEOUT,
if (p->mtu)
addattr16(&req.n, 1024, L2TP_ATTR_MTU, p->mtu);
if (p->recv_seq)
addattr8(&req.n, 1024, L2TP_ATTR_RECV_SEQ, 1);
if (p->send_seq)
addattr8(&req.n, 1024, L2TP_ATTR_SEND_SEQ, 1);
if (p->lns_mode)
addattr(&req.n, 1024, L2TP_ATTR_LNS_MODE);
if (p->data_seq)
addattr8(&req.n, 1024, L2TP_ATTR_DATA_SEQ, p->data_seq);
if (p->reorder_timeout)
addattr64(&req.n, 1024, L2TP_ATTR_RECV_TIMEOUT,
p->reorder_timeout);
if (p->offset) addattr16(&req.n, 1024, L2TP_ATTR_OFFSET, p->offset);
if (p->cookie_len) addattr_l(&req.n, 1024, L2TP_ATTR_COOKIE,
p->cookie, p->cookie_len);
if (p->peer_cookie_len) addattr_l(&req.n, 1024, L2TP_ATTR_PEER_COOKIE,
p->peer_cookie, p->peer_cookie_len);
if (p->offset)
addattr16(&req.n, 1024, L2TP_ATTR_OFFSET, p->offset);
if (p->cookie_len)
addattr_l(&req.n, 1024, L2TP_ATTR_COOKIE,
p->cookie, p->cookie_len);
if (p->peer_cookie_len)
addattr_l(&req.n, 1024, L2TP_ATTR_PEER_COOKIE,
p->peer_cookie, p->peer_cookie_len);
if (p->ifname && p->ifname[0])
addattrstrz(&req.n, 1024, L2TP_ATTR_IFNAME, p->ifname);
@ -213,14 +224,37 @@ static void print_tunnel(const struct l2tp_data *data)
p->tunnel_id,
p->encap == L2TP_ENCAPTYPE_UDP ? "UDP" :
p->encap == L2TP_ENCAPTYPE_IP ? "IP" : "??");
printf(" From %s ", inet_ntop(p->local_ip.family, p->local_ip.data, buf, sizeof(buf)));
printf("to %s\n", inet_ntop(p->peer_ip.family, p->peer_ip.data, buf, sizeof(buf)));
printf(" From %s ",
inet_ntop(p->local_ip.family, p->local_ip.data,
buf, sizeof(buf)));
printf("to %s\n",
inet_ntop(p->peer_ip.family, p->peer_ip.data,
buf, sizeof(buf)));
printf(" Peer tunnel %u\n",
p->peer_tunnel_id);
if (p->encap == L2TP_ENCAPTYPE_UDP)
if (p->encap == L2TP_ENCAPTYPE_UDP) {
printf(" UDP source / dest ports: %hu/%hu\n",
p->local_udp_port, p->peer_udp_port);
switch (p->local_ip.family) {
case AF_INET:
printf(" UDP checksum: %s\n",
p->udp_csum ? "enabled" : "disabled");
break;
case AF_INET6:
printf(" UDP checksum: %s%s%s%s\n",
p->udp6_csum_tx && p->udp6_csum_rx
? "enabled" : "",
p->udp6_csum_tx && !p->udp6_csum_rx
? "tx" : "",
!p->udp6_csum_tx && p->udp6_csum_rx
? "rx" : "",
!p->udp6_csum_tx && !p->udp6_csum_rx
? "disabled" : "");
break;
}
}
}
static void print_session(struct l2tp_data *data)
@ -232,9 +266,9 @@ static void print_session(struct l2tp_data *data)
printf(" Peer session %u, tunnel %u\n",
p->peer_session_id, p->peer_tunnel_id);
if (p->ifname != NULL) {
if (p->ifname != NULL)
printf(" interface name: %s\n", p->ifname);
}
printf(" offset %u, peer offset %u\n",
p->offset, p->peer_offset);
if (p->cookie_len > 0)
@ -246,6 +280,14 @@ static void print_session(struct l2tp_data *data)
printf(" reorder timeout: %u\n", p->reorder_timeout);
else
printf("\n");
if (p->send_seq || p->recv_seq) {
printf(" sequence numbering:");
if (p->send_seq)
printf(" send");
if (p->recv_seq)
printf(" recv");
printf("\n");
}
}
static int get_response(struct nlmsghdr *n, void *arg)
@ -289,13 +331,12 @@ static int get_response(struct nlmsghdr *n, void *arg)
if (attrs[L2TP_ATTR_L2SPEC_LEN])
p->l2spec_len = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_LEN]);
p->udp_csum = !!attrs[L2TP_ATTR_UDP_CSUM];
/*
* Not fetching from L2TP_ATTR_UDP_ZERO_CSUM6_{T,R}X because the
* kernel doesn't send it so just leave it as default value.
*/
p->udp6_csum_tx = 1;
p->udp6_csum_rx = 1;
if (attrs[L2TP_ATTR_UDP_CSUM])
p->udp_csum = !!rta_getattr_u8(attrs[L2TP_ATTR_UDP_CSUM]);
p->udp6_csum_tx = !attrs[L2TP_ATTR_UDP_ZERO_CSUM6_TX];
p->udp6_csum_rx = !attrs[L2TP_ATTR_UDP_ZERO_CSUM6_RX];
if (attrs[L2TP_ATTR_COOKIE])
memcpy(p->cookie, RTA_DATA(attrs[L2TP_ATTR_COOKIE]),
p->cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_COOKIE]));
@ -304,8 +345,10 @@ static int get_response(struct nlmsghdr *n, void *arg)
memcpy(p->peer_cookie, RTA_DATA(attrs[L2TP_ATTR_PEER_COOKIE]),
p->peer_cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_PEER_COOKIE]));
p->recv_seq = !!attrs[L2TP_ATTR_RECV_SEQ];
p->send_seq = !!attrs[L2TP_ATTR_SEND_SEQ];
if (attrs[L2TP_ATTR_RECV_SEQ])
p->recv_seq = !!rta_getattr_u8(attrs[L2TP_ATTR_RECV_SEQ]);
if (attrs[L2TP_ATTR_SEND_SEQ])
p->send_seq = !!rta_getattr_u8(attrs[L2TP_ATTR_SEND_SEQ]);
if (attrs[L2TP_ATTR_RECV_TIMEOUT])
p->reorder_timeout = rta_getattr_u64(attrs[L2TP_ATTR_RECV_TIMEOUT]);
@ -369,7 +412,8 @@ static int get_response(struct nlmsghdr *n, void *arg)
return 0;
}
static int session_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
static int session_nlmsg(const struct sockaddr_nl *who,
struct nlmsghdr *n, void *arg)
{
int ret = get_response(n, arg);
@ -389,7 +433,8 @@ static int get_session(struct l2tp_data *p)
if (p->config.tunnel_id && p->config.session_id) {
addattr32(&req.n, 128, L2TP_ATTR_CONN_ID, p->config.tunnel_id);
addattr32(&req.n, 128, L2TP_ATTR_SESSION_ID, p->config.session_id);
addattr32(&req.n, 128, L2TP_ATTR_SESSION_ID,
p->config.session_id);
}
if (rtnl_send(&genl_rth, &req, req.n.nlmsg_len) < 0)
@ -403,7 +448,8 @@ static int get_session(struct l2tp_data *p)
return 0;
}
static int tunnel_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
static int tunnel_nlmsg(const struct sockaddr_nl *who,
struct nlmsghdr *n, void *arg)
{
int ret = get_response(n, arg);
@ -468,31 +514,33 @@ static void usage(void) __attribute__((noreturn));
static void usage(void)
{
fprintf(stderr, "Usage: ip l2tp add tunnel\n");
fprintf(stderr, " remote ADDR local ADDR\n");
fprintf(stderr, " tunnel_id ID peer_tunnel_id ID\n");
fprintf(stderr, " [ encap { ip | udp } ]\n");
fprintf(stderr, " [ udp_sport PORT ] [ udp_dport PORT ]\n");
fprintf(stderr, " [ udp_csum { on | off } ]\n");
fprintf(stderr, " [ udp6_csum_tx { on | off } ]\n");
fprintf(stderr, " [ udp6_csum_rx { on | off } ]\n");
fprintf(stderr, "Usage: ip l2tp add session [ name NAME ]\n");
fprintf(stderr, " tunnel_id ID\n");
fprintf(stderr, " session_id ID peer_session_id ID\n");
fprintf(stderr, " [ cookie HEXSTR ] [ peer_cookie HEXSTR ]\n");
fprintf(stderr, " [ offset OFFSET ] [ peer_offset OFFSET ]\n");
fprintf(stderr, " [ l2spec_type L2SPEC ]\n");
fprintf(stderr, " ip l2tp del tunnel tunnel_id ID\n");
fprintf(stderr, " ip l2tp del session tunnel_id ID session_id ID\n");
fprintf(stderr, " ip l2tp show tunnel [ tunnel_id ID ]\n");
fprintf(stderr, " ip l2tp show session [ tunnel_id ID ] [ session_id ID ]\n");
fprintf(stderr, "\n");
fprintf(stderr, "Where: NAME := STRING\n");
fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n");
fprintf(stderr, " PORT := { 0..65535 }\n");
fprintf(stderr, " ID := { 1..4294967295 }\n");
fprintf(stderr, " HEXSTR := { 8 or 16 hex digits (4 / 8 bytes) }\n");
fprintf(stderr, " L2SPEC := { none | default }\n");
fprintf(stderr, "Usage: ip l2tp add tunnel\n"
" remote ADDR local ADDR\n"
" tunnel_id ID peer_tunnel_id ID\n"
" [ encap { ip | udp } ]\n"
" [ udp_sport PORT ] [ udp_dport PORT ]\n"
" [ udp_csum { on | off } ]\n"
" [ udp6_csum_tx { on | off } ]\n"
" [ udp6_csum_rx { on | off } ]\n"
"Usage: ip l2tp add session [ name NAME ]\n"
" tunnel_id ID\n"
" session_id ID peer_session_id ID\n"
" [ cookie HEXSTR ] [ peer_cookie HEXSTR ]\n"
" [ offset OFFSET ] [ peer_offset OFFSET ]\n"
" [ seq { none | send | recv | both } ]\n"
" [ l2spec_type L2SPEC ]\n"
" ip l2tp del tunnel tunnel_id ID\n"
" ip l2tp del session tunnel_id ID session_id ID\n"
" ip l2tp show tunnel [ tunnel_id ID ]\n"
" ip l2tp show session [ tunnel_id ID ] [ session_id ID ]\n"
"\n"
"Where: NAME := STRING\n"
" ADDR := { IP_ADDRESS | any }\n"
" PORT := { 0..65535 }\n"
" ID := { 1..4294967295 }\n"
" HEXSTR := { 8 or 16 hex digits (4 / 8 bytes) }\n"
" L2SPEC := { none | default }\n");
exit(-1);
}
@ -648,7 +696,26 @@ static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p)
p->l2spec_type = L2TP_L2SPECTYPE_NONE;
p->l2spec_len = 0;
} else {
fprintf(stderr, "Unknown layer2specific header type \"%s\"\n", *argv);
fprintf(stderr,
"Unknown layer2specific header type \"%s\"\n",
*argv);
exit(-1);
}
} else if (strcmp(*argv, "seq") == 0) {
NEXT_ARG();
if (strcasecmp(*argv, "both") == 0) {
p->recv_seq = 1;
p->send_seq = 1;
} else if (strcasecmp(*argv, "recv") == 0) {
p->recv_seq = 1;
} else if (strcasecmp(*argv, "send") == 0) {
p->send_seq = 1;
} else if (strcasecmp(*argv, "none") == 0) {
p->recv_seq = 0;
p->send_seq = 0;
} else {
fprintf(stderr,
"Unknown seq value \"%s\"\n", *argv);
exit(-1);
}
} else if (strcmp(*argv, "tunnel") == 0) {
@ -779,6 +846,7 @@ int do_ipl2tp(int argc, char **argv)
matches(*argv, "list") == 0)
return do_show(argc-1, argv+1);
fprintf(stderr, "Command \"%s\" is unknown, try \"ip l2tp help\".\n", *argv);
fprintf(stderr,
"Command \"%s\" is unknown, try \"ip l2tp help\".\n", *argv);
exit(-1);
}

View File

@ -98,8 +98,8 @@ void iplink_usage(void)
fprintf(stderr,
" ip link help [ TYPE ]\n\n"
"TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n"
" bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |\n"
" gre | gretap | ip6gre | ip6gretap | vti | nlmon |\n"
" bridge | bond | team | ipoib | ip6tnl | ipip | sit | vxlan |\n"
" gre | gretap | ip6gre | ip6gretap | vti | nlmon | team_slave |\n"
" bond_slave | ipvlan | geneve | bridge_slave | vrf | macsec }\n");
}
exit(-1);

View File

@ -15,6 +15,7 @@
#include <string.h>
#include <sys/socket.h>
#include <linux/if_link.h>
#include <linux/if_ether.h>
#include "rt_names.h"
#include "utils.h"
@ -29,7 +30,11 @@
static void print_explain(struct link_util *lu, FILE *f)
{
fprintf(f,
"Usage: ... %s mode { private | vepa | bridge | passthru [nopromisc] }\n",
"Usage: ... %s mode MODE [flag MODE_FLAG] MODE_OPTS\n"
"MODE: private | vepa | bridge | passthru | source\n"
"MODE_FLAG: null | nopromisc\n"
"MODE_OPTS: for mode \"source\":\n"
"\tmacaddr { { add | del } <macaddr> | set [ <macaddr> [ <macaddr> ... ] ] | flush }\n",
lu->id
);
}
@ -43,7 +48,15 @@ static void explain(struct link_util *lu)
static int mode_arg(const char *arg)
{
fprintf(stderr,
"Error: argument of \"mode\" must be \"private\", \"vepa\", \"bridge\" or \"passthru\", not \"%s\"\n",
"Error: argument of \"mode\" must be \"private\", \"vepa\", \"bridge\", \"passthru\" or \"source\", not \"%s\"\n",
arg);
return -1;
}
static int flag_arg(const char *arg)
{
fprintf(stderr,
"Error: argument of \"flag\" must be \"nopromisc\" or \"null\", not \"%s\"\n",
arg);
return -1;
}
@ -53,6 +66,10 @@ static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv,
{
__u32 mode = 0;
__u16 flags = 0;
__u32 mac_mode = 0;
int has_flags = 0;
char mac[ETH_ALEN];
struct rtattr *nmac;
while (argc > 0) {
if (matches(*argv, "mode") == 0) {
@ -66,10 +83,72 @@ static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv,
mode = MACVLAN_MODE_BRIDGE;
else if (strcmp(*argv, "passthru") == 0)
mode = MACVLAN_MODE_PASSTHRU;
else if (strcmp(*argv, "source") == 0)
mode = MACVLAN_MODE_SOURCE;
else
return mode_arg(*argv);
} else if (matches(*argv, "flag") == 0) {
NEXT_ARG();
if (strcmp(*argv, "nopromisc") == 0)
flags |= MACVLAN_FLAG_NOPROMISC;
else if (strcmp(*argv, "null") == 0)
flags |= 0;
else
return flag_arg(*argv);
has_flags = 1;
} else if (matches(*argv, "macaddr") == 0) {
NEXT_ARG();
if (strcmp(*argv, "add") == 0) {
mac_mode = MACVLAN_MACADDR_ADD;
} else if (strcmp(*argv, "del") == 0) {
mac_mode = MACVLAN_MACADDR_DEL;
} else if (strcmp(*argv, "set") == 0) {
mac_mode = MACVLAN_MACADDR_SET;
} else if (strcmp(*argv, "flush") == 0) {
mac_mode = MACVLAN_MACADDR_FLUSH;
} else {
explain(lu);
return -1;
}
addattr32(n, 1024, IFLA_MACVLAN_MACADDR_MODE, mac_mode);
if (mac_mode == MACVLAN_MACADDR_ADD ||
mac_mode == MACVLAN_MACADDR_DEL) {
NEXT_ARG();
if (ll_addr_a2n(mac, sizeof(mac),
*argv) != ETH_ALEN)
return -1;
addattr_l(n, 1024, IFLA_MACVLAN_MACADDR, &mac,
ETH_ALEN);
}
if (mac_mode == MACVLAN_MACADDR_SET) {
nmac = addattr_nest(n, 1024,
IFLA_MACVLAN_MACADDR_DATA);
while (NEXT_ARG_OK()) {
NEXT_ARG_FWD();
if (ll_addr_a2n(mac, sizeof(mac),
*argv) != ETH_ALEN) {
PREV_ARG();
break;
}
addattr_l(n, 1024, IFLA_MACVLAN_MACADDR,
&mac, ETH_ALEN);
}
addattr_nest_end(n, nmac);
}
} else if (matches(*argv, "nopromisc") == 0) {
flags |= MACVLAN_FLAG_NOPROMISC;
has_flags = 1;
} else if (matches(*argv, "help") == 0) {
explain(lu);
return -1;
@ -84,7 +163,7 @@ static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv,
if (mode)
addattr32(n, 1024, IFLA_MACVLAN_MODE, mode);
if (flags) {
if (has_flags) {
if (flags & MACVLAN_FLAG_NOPROMISC &&
mode != MACVLAN_MODE_PASSTHRU) {
pfx_err(lu, "nopromisc flag only valid in passthru mode");
@ -100,6 +179,10 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]
{
__u32 mode;
__u16 flags;
__u32 count;
unsigned char *addr;
int len;
struct rtattr *rta;
if (!tb)
return;
@ -109,20 +192,49 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]
return;
mode = rta_getattr_u32(tb[IFLA_MACVLAN_MODE]);
fprintf(f, " mode %s ",
fprintf(f, "mode %s ",
mode == MACVLAN_MODE_PRIVATE ? "private"
: mode == MACVLAN_MODE_VEPA ? "vepa"
: mode == MACVLAN_MODE_BRIDGE ? "bridge"
: mode == MACVLAN_MODE_PASSTHRU ? "passthru"
: mode == MACVLAN_MODE_SOURCE ? "source"
: "unknown");
if (!tb[IFLA_MACVLAN_FLAGS] ||
RTA_PAYLOAD(tb[IFLA_MACVLAN_FLAGS]) < sizeof(__u16))
return;
flags = 0;
else
flags = rta_getattr_u16(tb[IFLA_MACVLAN_FLAGS]);
flags = rta_getattr_u16(tb[IFLA_MACVLAN_FLAGS]);
if (flags & MACVLAN_FLAG_NOPROMISC)
fprintf(f, "nopromisc ");
/* in source mode, there are more options to print */
if (mode != MACVLAN_MODE_SOURCE)
return;
if (!tb[IFLA_MACVLAN_MACADDR_COUNT] ||
RTA_PAYLOAD(tb[IFLA_MACVLAN_MACADDR_COUNT]) < sizeof(__u32))
return;
count = rta_getattr_u32(tb[IFLA_MACVLAN_MACADDR_COUNT]);
fprintf(f, "remotes (%d) ", count);
if (!tb[IFLA_MACVLAN_MACADDR_DATA])
return;
rta = RTA_DATA(tb[IFLA_MACVLAN_MACADDR_DATA]);
len = RTA_PAYLOAD(tb[IFLA_MACVLAN_MACADDR_DATA]);
for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
if (rta->rta_type != IFLA_MACVLAN_MACADDR ||
RTA_PAYLOAD(rta) < 6)
continue;
addr = RTA_DATA(rta);
fprintf(f, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x ", addr[0],
addr[1], addr[2], addr[3], addr[4], addr[5]);
}
}
static void macvlan_print_help(struct link_util *lu, int argc, char **argv,

View File

@ -634,10 +634,10 @@ static void print_one_stat(const char **names, struct rtattr **attr, int idx,
}
static const char *txsc_stats_names[NUM_MACSEC_TXSC_STATS_ATTR] = {
[MACSEC_TXSC_STATS_ATTR_OUT_PKTS_PROTECTED] = "OutOctetsProtected",
[MACSEC_TXSC_STATS_ATTR_OUT_PKTS_ENCRYPTED] = "OutOctetsEncrypted",
[MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_PROTECTED] = "OutPktsProtected",
[MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_ENCRYPTED] = "OutPktsEncrypted",
[MACSEC_TXSC_STATS_ATTR_OUT_PKTS_PROTECTED] = "OutPktsProtected",
[MACSEC_TXSC_STATS_ATTR_OUT_PKTS_ENCRYPTED] = "OutPktsEncrypted",
[MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_PROTECTED] = "OutOctetsProtected",
[MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_ENCRYPTED] = "OutOctetsEncrypted",
};
static void print_txsc_stats(const char *prefix, struct rtattr *attr)

View File

@ -321,7 +321,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
fprintf(stderr, "Not a route: %08x %08x %08x\n",
n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
return 0;
return -1;
}
if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
return 0;
@ -1755,7 +1755,7 @@ static int iproute_get(int argc, char **argv)
if (print_route(NULL, &req.n, (void *)stdout) < 0) {
fprintf(stderr, "An error :-)\n");
exit(1);
return -1;
}
if (req.n.nlmsg_type != RTM_NEWROUTE) {

View File

@ -43,7 +43,7 @@ void rtnl_close(struct rtnl_handle *rth)
}
}
int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
int rtnl_open_byproto(struct rtnl_handle *rth, unsigned int subscriptions,
int protocol)
{
socklen_t addr_len;
@ -58,12 +58,14 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
return -1;
}
if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) {
if (setsockopt(rth->fd, SOL_SOCKET, SO_SNDBUF,
&sndbuf, sizeof(sndbuf)) < 0) {
perror("SO_SNDBUF");
return -1;
}
if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf)) < 0) {
if (setsockopt(rth->fd, SOL_SOCKET, SO_RCVBUF,
&rcvbuf, sizeof(rcvbuf)) < 0) {
perror("SO_RCVBUF");
return -1;
}
@ -72,12 +74,14 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
rth->local.nl_family = AF_NETLINK;
rth->local.nl_groups = subscriptions;
if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
if (bind(rth->fd, (struct sockaddr *)&rth->local,
sizeof(rth->local)) < 0) {
perror("Cannot bind netlink socket");
return -1;
}
addr_len = sizeof(rth->local);
if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
if (getsockname(rth->fd, (struct sockaddr *)&rth->local,
&addr_len) < 0) {
perror("Cannot getsockname");
return -1;
}
@ -86,14 +90,15 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
return -1;
}
if (rth->local.nl_family != AF_NETLINK) {
fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
fprintf(stderr, "Wrong address family %d\n",
rth->local.nl_family);
return -1;
}
rth->seq = time(NULL);
return 0;
}
int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
int rtnl_open(struct rtnl_handle *rth, unsigned int subscriptions)
{
return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
}
@ -123,7 +128,7 @@ int rtnl_wilddump_req_filter(struct rtnl_handle *rth, int family, int type,
.ext_filter_mask = filt_mask,
};
return send(rth->fd, (void*)&req, sizeof(req), 0);
return send(rth->fd, &req, sizeof(req), 0);
}
int rtnl_wilddump_req_filter_fn(struct rtnl_handle *rth, int family, int type,
@ -149,7 +154,7 @@ int rtnl_wilddump_req_filter_fn(struct rtnl_handle *rth, int family, int type,
if (err)
return err;
return send(rth->fd, (void*)&req, sizeof(req), 0);
return send(rth->fd, &req, req.nlh.nlmsg_len, 0);
}
int rtnl_wilddump_stats_req_filter(struct rtnl_handle *rth, int fam, int type,
@ -169,7 +174,7 @@ int rtnl_wilddump_stats_req_filter(struct rtnl_handle *rth, int fam, int type,
req.ifsm.family = fam;
req.ifsm.filter_mask = filt_mask;
return send(rth->fd, (void *)&req, sizeof(req), 0);
return send(rth->fd, &req, sizeof(req), 0);
}
int rtnl_send(struct rtnl_handle *rth, const void *buf, int len)
@ -198,7 +203,8 @@ int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len)
for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status);
h = NLMSG_NEXT(h, status)) {
if (h->nlmsg_type == NLMSG_ERROR) {
struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
fprintf(stderr, "ERROR truncated\n");
else
@ -237,7 +243,7 @@ int rtnl_dump_request_n(struct rtnl_handle *rth, struct nlmsghdr *n)
{
struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
struct iovec iov = {
.iov_base = (void*) n,
.iov_base = n,
.iov_len = n->nlmsg_len
};
struct msghdr msg = {
@ -295,7 +301,8 @@ int rtnl_dump_filter_l(struct rtnl_handle *rth,
fwrite(buf, 1, NLMSG_ALIGN(status), rth->dump_fp);
for (a = arg; a->filter; a++) {
struct nlmsghdr *h = (struct nlmsghdr*)buf;
struct nlmsghdr *h = (struct nlmsghdr *)buf;
msglen = status;
while (NLMSG_OK(h, msglen)) {
@ -316,7 +323,8 @@ int rtnl_dump_filter_l(struct rtnl_handle *rth,
break; /* process next filter */
}
if (h->nlmsg_type == NLMSG_ERROR) {
struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
fprintf(stderr,
"ERROR truncated\n");
@ -377,11 +385,11 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
struct nlmsghdr *answer, size_t maxlen)
{
int status;
unsigned seq;
unsigned int seq;
struct nlmsghdr *h;
struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
struct iovec iov = {
.iov_base = (void*) n,
.iov_base = n,
.iov_len = n->nlmsg_len
};
struct msghdr msg = {
@ -420,19 +428,23 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
return -1;
}
if (msg.msg_namelen != sizeof(nladdr)) {
fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
fprintf(stderr,
"sender address length == %d\n",
msg.msg_namelen);
exit(1);
}
for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
int len = h->nlmsg_len;
int l = len - sizeof(*h);
if (l < 0 || len>status) {
if (l < 0 || len > status) {
if (msg.msg_flags & MSG_TRUNC) {
fprintf(stderr, "Truncated message\n");
return -1;
}
fprintf(stderr, "!!!malformed message: len=%d\n", len);
fprintf(stderr,
"!!!malformed message: len=%d\n",
len);
exit(1);
}
@ -441,12 +453,13 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
h->nlmsg_seq != seq) {
/* Don't forget to skip that message. */
status -= NLMSG_ALIGN(len);
h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
continue;
}
if (h->nlmsg_type == NLMSG_ERROR) {
struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
if (l < sizeof(struct nlmsgerr)) {
fprintf(stderr, "ERROR truncated\n");
} else if (!err->error) {
@ -473,7 +486,7 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
fprintf(stderr, "Unexpected reply!!!\n");
status -= NLMSG_ALIGN(len);
h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
}
if (msg.msg_flags & MSG_TRUNC) {
@ -545,7 +558,9 @@ int rtnl_listen(struct rtnl_handle *rtnl,
return -1;
}
if (msg.msg_namelen != sizeof(nladdr)) {
fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
fprintf(stderr,
"Sender address length == %d\n",
msg.msg_namelen);
exit(1);
}
@ -563,17 +578,19 @@ int rtnl_listen(struct rtnl_handle *rtnl,
}
}
for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
int err;
int len = h->nlmsg_len;
int l = len - sizeof(*h);
if (l<0 || len>status) {
if (l < 0 || len > status) {
if (msg.msg_flags & MSG_TRUNC) {
fprintf(stderr, "Truncated message\n");
return -1;
}
fprintf(stderr, "!!!malformed message: len=%d\n", len);
fprintf(stderr,
"!!!malformed message: len=%d\n",
len);
exit(1);
}
@ -582,7 +599,7 @@ int rtnl_listen(struct rtnl_handle *rtnl,
return err;
status -= NLMSG_ALIGN(len);
h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
}
if (msg.msg_flags & MSG_TRUNC) {
fprintf(stderr, "Message truncated\n");
@ -600,8 +617,8 @@ int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler,
{
int status;
struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
char buf[16384];
struct nlmsghdr *h = (void*)buf;
char buf[16384];
struct nlmsghdr *h = (struct nlmsghdr *)buf;
while (1) {
int err, len;
@ -621,7 +638,7 @@ int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler,
len = h->nlmsg_len;
l = len - sizeof(*h);
if (l<0 || len>sizeof(buf)) {
if (l < 0 || len > sizeof(buf)) {
fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
len, ftell(rtnl));
return -1;
@ -681,7 +698,9 @@ int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
struct rtattr *rta;
if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen);
fprintf(stderr,
"addattr_l ERROR: message exceeded bound of %d\n",
maxlen);
return -1;
}
rta = NLMSG_TAIL(n);
@ -695,7 +714,9 @@ int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
{
if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen);
fprintf(stderr,
"addraw_l ERROR: message exceeded bound of %d\n",
maxlen);
return -1;
}
@ -744,10 +765,12 @@ int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
struct rtattr *subrta;
if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen);
fprintf(stderr,
"rta_addattr32: Error! max allowed bound %d exceeded\n",
maxlen);
return -1;
}
subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
subrta = (struct rtattr *)(((char *)rta) + RTA_ALIGN(rta->rta_len));
subrta->rta_type = type;
subrta->rta_len = len;
memcpy(RTA_DATA(subrta), &data, 4);
@ -762,10 +785,12 @@ int rta_addattr_l(struct rtattr *rta, int maxlen, int type,
int len = RTA_LENGTH(alen);
if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) {
fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen);
fprintf(stderr,
"rta_addattr_l: Error! max allowed bound %d exceeded\n",
maxlen);
return -1;
}
subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
subrta = (struct rtattr *)(((char *)rta) + RTA_ALIGN(rta->rta_len));
subrta->rta_type = type;
subrta->rta_len = len;
memcpy(RTA_DATA(subrta), data, alen);
@ -819,14 +844,16 @@ int parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta,
type = rta->rta_type & ~flags;
if ((type <= max) && (!tb[type]))
tb[type] = rta;
rta = RTA_NEXT(rta,len);
rta = RTA_NEXT(rta, len);
}
if (len)
fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
fprintf(stderr, "!!!Deficit %d, rta_len=%d\n",
len, rta->rta_len);
return 0;
}
int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len)
int parse_rtattr_byindex(struct rtattr *tb[], int max,
struct rtattr *rta, int len)
{
int i = 0;
@ -834,10 +861,11 @@ int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int l
while (RTA_OK(rta, len)) {
if (rta->rta_type <= max && i < max)
tb[i++] = rta;
rta = RTA_NEXT(rta,len);
rta = RTA_NEXT(rta, len);
}
if (len)
fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
fprintf(stderr, "!!!Deficit %d, rta_len=%d\n",
len, rta->rta_len);
return i;
}
@ -848,13 +876,16 @@ struct rtattr *parse_rtattr_one(int type, struct rtattr *rta, int len)
return rta;
rta = RTA_NEXT(rta, len);
}
if (len)
fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
fprintf(stderr, "!!!Deficit %d, rta_len=%d\n",
len, rta->rta_len);
return NULL;
}
int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta,
int len)
int __parse_rtattr_nested_compat(struct rtattr *tb[], int max,
struct rtattr *rta,
int len)
{
if (RTA_PAYLOAD(rta) < len)
return -1;

View File

@ -100,11 +100,13 @@ __PF(IEEE80211,ieee802.11)
__PF(IEEE80211_PRISM,ieee802.11/prism)
__PF(IEEE80211_RADIOTAP,ieee802.11/radiotap)
__PF(IEEE802154, ieee802.15.4)
__PF(IEEE802154_MONITOR, ieee802.15.4/monitor)
__PF(PHONET, phonet)
__PF(PHONET_PIPE, phonet_pipe)
__PF(CAIF, caif)
__PF(IP6GRE, gre6)
__PF(NETLINK, netlink)
__PF(6LOWPAN, 6lowpan)
__PF(NONE, none)
__PF(VOID,void)

View File

@ -559,8 +559,12 @@ const char *rtnl_group_n2a(int id, char *buf, int len)
for (i = 0; i < 256; i++) {
entry = rtnl_group_hash[i];
if (entry && entry->id == id)
return entry->name;
while (entry) {
if (entry->id == id)
return entry->name;
entry = entry->next;
}
}
snprintf(buf, len, "%d", id);

View File

@ -31,6 +31,9 @@ devlink-dev \- devlink device configuration
.RI "[ "
.BR mode " { " legacy " | " switchdev " } "
.RI "]"
.RI "[ "
.BR inline-mode " { " none " | " link " | " network " | " transport " } "
.RI "]"
.ti -8
.BR "devlink dev eswitch show"
@ -54,7 +57,7 @@ BUS_NAME/BUS_ADDRESS
.TP
.BR mode " { " legacy " | " switchdev " } "
set eswitch mode
Set eswitch mode
.I legacy
- Legacy SRIOV
@ -62,6 +65,22 @@ set eswitch mode
.I switchdev
- SRIOV switchdev offloads
.TP
.BR inline-mode " { " none " | " link " | " network " | " transport " } "
Some HWs need the VF driver to put part of the packet headers on the TX descriptor so the e-switch can do proper matching and steering.
.I none
- None
.I link
- L2 mode
.I network
- L3 mode
.I transport
- L4 mode
.SH "EXAMPLES"
.PP
devlink dev show

View File

@ -30,6 +30,12 @@ ip-l2tp - L2TPv3 static unmanaged tunnel configuration
.IR PORT
.RB " ]"
.br
.RB "[ " udp_csum " { " on " | " off " } ]"
.br
.RB "[ " udp6_csum_tx " { " on " | " off " } ]"
.br
.RB "[ " udp6_csum_rx " { " on " | " off " } ]"
.br
.ti -8
.BR "ip l2tp add session"
.RB "[ " name
@ -51,6 +57,8 @@ ip-l2tp - L2TPv3 static unmanaged tunnel configuration
.br
.RB "[ " l2spec_type " { " none " | " default " } ]"
.br
.RB "[ " seq " { " none " | " send " | " recv " | " both " } ]"
.br
.RB "[ " offset
.IR OFFSET
.RB " ] [ " peer_offset
@ -154,9 +162,6 @@ tunnels and sessions to be established and provides for detecting and
acting upon network failures.
.SS ip l2tp add tunnel - add a new tunnel
.TP
.BI name " NAME "
sets the session network interface name. Default is l2tpethN.
.TP
.BI tunnel_id " ID"
set the tunnel id, which is a 32-bit integer value. Uniquely
identifies the tunnel. The value used must match the peer_tunnel_id
@ -191,6 +196,33 @@ selected.
set the UDP destination port to be used for the tunnel. Must be
present when udp encapsulation is selected. Ignored when ip
encapsulation is selected.
.TP
.BI udp_csum " STATE"
(IPv4 only) control if IPv4 UDP checksums should be calculated and checked for the
encapsulating UDP packets, when UDP encapsulating is selected.
Default is
.BR off "."
.br
Valid values are:
.BR on ", " off "."
.TP
.BI udp6_csum_tx " STATE"
(IPv6 only) control if IPv6 UDP checksums should be calculated for encapsulating
UDP packets, when UDP encapsulating is selected.
Default is
.BR on "."
.br
Valid values are:
.BR on ", " off "."
.TP
.BI udp6_csum_rx " STATE"
(IPv6 only) control if IPv6 UDP checksums should be checked for the encapsulating
UDP packets, when UDP encapsulating is selected.
Default is
.BR on "."
.br
Valid values are:
.BR on ", " off "."
.SS ip l2tp del tunnel - destroy a tunnel
.TP
.BI tunnel_id " ID"
@ -239,7 +271,20 @@ find in received L2TP packets. Default is to use no cookie.
set the layer2specific header type of the session.
.br
Valid values are:
.BR none ", " udp "."
.BR none ", " default "."
.TP
.BI seq " SEQ"
controls sequence numbering to prevent or detect out of order packets.
.B send
puts a sequence number in the default layer2specific header of each
outgoing packet.
.B recv
reorder packets if they are received out of order.
Default is
.BR none "."
.br
Valid values are:
.BR none ", " send ", " recv ", " both "."
.TP
.BI offset " OFFSET"
sets the byte offset from the L2TP header where user data starts in

View File

@ -135,7 +135,12 @@ ip-link \- network device configuration
.IR NAME " ]"
.br
.RB "[ " addrgenmode " { " eui64 " | " none " | " stable_secret " | " random " } ]"
.br
.RB "[ " macaddr " { " flush " | { " add " | " del " } "
.IR MACADDR " | set [ "
.IR MACADDR " [ "
.IR MACADDR " [ ... ] ] ] } ]"
.br
.ti -8
.B ip link show
@ -882,7 +887,7 @@ the following additional arguments are supported:
.BI "ip link add link " DEVICE " name " NAME
.BR type " { " macvlan " | " macvtap " } "
.BR mode " { " private " | " vepa " | " bridge " | " passthru
.RB " [ " nopromisc " ] } "
.RB " [ " nopromisc " ] | " source " } "
.in +8
.sp
@ -919,6 +924,13 @@ the interface or create vlan interfaces on top of it. By default, this mode
forces the underlying interface into promiscuous mode. Passing the
.BR nopromisc " flag prevents this, so the promisc flag may be controlled "
using standard tools.
.B mode source
- allows one to set a list of allowed mac address, which is used to match
against source mac address from received frames on underlying interface. This
allows creating mac based VLAN associations, instead of standard port or tag
based. The feature is useful to deploy 802.1x mac based behavior,
where drivers of underlying interfaces doesn't allows that.
.in -8
.TP
@ -1468,6 +1480,32 @@ the following additional arguments are supported:
.in -8
.TP
MACVLAN and MACVTAP Support
Modify list of allowed macaddr for link in source mode.
.B "ip link set type { macvlan | macvap } "
[
.BI macaddr " " "" COMMAND " " MACADDR " ..."
]
Commands:
.in +8
.B add
- add MACADDR to allowed list
.sp
.B set
- replace allowed list
.sp
.B del
- remove MACADDR from allowed list
.sp
.B flush
- flush whole allowed list
.sp
.in -8
.SS ip link show - display device attributes
.TP

View File

@ -122,6 +122,9 @@ Display RAW sockets.
.B \-x, \-\-unix
Display Unix domain sockets (alias for -f unix).
.TP
.B \-S, \-\-sctp
Display SCTP sockets.
.TP
.B \-f FAMILY, \-\-family=FAMILY
Display sockets of type FAMILY.
Currently the following families are supported: unix, inet, inet6, link, netlink.

View File

@ -23,8 +23,6 @@ flower \- flow based traffic control filter
.R " | { "
.BR dst_mac " | " src_mac " } "
.IR mac_address " | "
.BR eth_type " { " ipv4 " | " ipv6 " | " 802.1Q " | "
.IR ETH_TYPE " } | "
.B vlan_id
.IR VID " | "
.B vlan_prio
@ -75,13 +73,6 @@ Do not process filter by hardware.
.BI src_mac " mac_address"
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

View File

@ -28,7 +28,7 @@ class-id ] qdisc
.B tc
.RI "[ " OPTIONS " ]"
.B filter [ add | change | replace | delete ] dev
.B filter [ add | change | replace | delete | get ] dev
DEV
.B [ parent
qdisc-id
@ -575,6 +575,14 @@ replace
Performs a nearly atomic remove/add on an existing node id. If the node does not exist yet
it is created.
.TP
get
Displays a single filter given the interface, parent ID, priority, protocol and handle ID.
.TP
show
Displays all filters attached to the given interface. A valid parent ID must be passed.
.TP
link
Only available for qdiscs and performs a replace where the node

View File

@ -662,18 +662,18 @@ static void usage(void)
{
fprintf(stderr,
"Usage: ifstat [OPTION] [ PATTERN [ PATTERN ] ]\n"
" -h, --help this message\n"
" -a, --ignore ignore history\n"
" -d, --scan=SECS sample every statistics every SECS\n"
" -e, --errors show errors\n"
" -j, --json format output in JSON\n"
" -n, --nooutput do history only\n"
" -p, --pretty pretty print\n"
" -r, --reset reset history\n"
" -s, --noupdate don\'t update history\n"
" -t, --interval=SECS report average over the last SECS\n"
" -V, --version output version information\n"
" -z, --zeros show entries with zero activity\n");
" -h, --help this message\n"
" -a, --ignore ignore history\n"
" -d, --scan=SECS sample every statistics every SECS\n"
" -e, --errors show errors\n"
" -j, --json format output in JSON\n"
" -n, --nooutput do history only\n"
" -p, --pretty pretty print\n"
" -r, --reset reset history\n"
" -s, --noupdate don't update history\n"
" -t, --interval=SECS report average over the last SECS\n"
" -V, --version output version information\n"
" -z, --zeros show entries with zero activity\n");
exit(-1);
}

View File

@ -526,17 +526,17 @@ static void usage(void)
{
fprintf(stderr,
"Usage: nstat [OPTION] [ PATTERN [ PATTERN ] ]\n"
" -h, --help this message\n"
" -a, --ignore ignore history\n"
" -d, --scan=SECS sample every statistics every SECS\n"
" -j, --json format output in JSON\n"
" -n, --nooutput do history only\n"
" -p, --pretty pretty print\n"
" -r, --reset reset history\n"
" -s, --noupdate don\'t update history\n"
" -t, --interval=SECS report average over the last SECS\n"
" -V, --version output version information\n"
" -z, --zeros show entries with zero activity\n");
" -h, --help this message\n"
" -a, --ignore ignore history\n"
" -d, --scan=SECS sample every statistics every SECS\n"
" -j, --json format output in JSON\n"
" -n, --nooutput do history only\n"
" -p, --pretty pretty print\n"
" -r, --reset reset history\n"
" -s, --noupdate don't update history\n"
" -t, --interval=SECS report average over the last SECS\n"
" -V, --version output version information\n"
" -z, --zeros show entries with zero activity\n");
exit(-1);
}

219
misc/ss.c
View File

@ -43,6 +43,7 @@
#include <linux/filter.h>
#include <linux/packet_diag.h>
#include <linux/netlink_diag.h>
#include <linux/sctp.h>
#define MAGIC_SEQ 123456
@ -102,6 +103,7 @@ int show_header = 1;
/* If show_users & show_proc_ctx only do user_ent_hash_build() once */
int user_ent_hash_build_init;
int follow_events;
int sctp_ino;
int netid_width;
int state_width;
@ -111,6 +113,7 @@ int serv_width;
int screen_width;
static const char *TCP_PROTO = "tcp";
static const char *SCTP_PROTO = "sctp";
static const char *UDP_PROTO = "udp";
static const char *RAW_PROTO = "raw";
static const char *dg_proto;
@ -126,13 +129,15 @@ enum {
PACKET_DG_DB,
PACKET_R_DB,
NETLINK_DB,
SCTP_DB,
MAX_DB
};
#define PACKET_DBM ((1<<PACKET_DG_DB)|(1<<PACKET_R_DB))
#define UNIX_DBM ((1<<UNIX_DG_DB)|(1<<UNIX_ST_DB)|(1<<UNIX_SQ_DB))
#define ALL_DB ((1<<MAX_DB)-1)
#define INET_DBM ((1<<TCP_DB)|(1<<UDP_DB)|(1<<DCCP_DB)|(1<<RAW_DB))
#define INET_L4_DBM ((1<<TCP_DB)|(1<<UDP_DB)|(1<<DCCP_DB)|(1<<SCTP_DB))
#define INET_DBM (INET_L4_DBM | (1<<RAW_DB))
enum {
SS_UNKNOWN,
@ -150,6 +155,17 @@ enum {
SS_MAX
};
enum {
SCTP_STATE_CLOSED = 0,
SCTP_STATE_COOKIE_WAIT = 1,
SCTP_STATE_COOKIE_ECHOED = 2,
SCTP_STATE_ESTABLISHED = 3,
SCTP_STATE_SHUTDOWN_PENDING = 4,
SCTP_STATE_SHUTDOWN_SENT = 5,
SCTP_STATE_SHUTDOWN_RECEIVED = 6,
SCTP_STATE_SHUTDOWN_ACK_SENT = 7,
};
#define SS_ALL ((1 << SS_MAX) - 1)
#define SS_CONN (SS_ALL & ~((1<<SS_LISTEN)|(1<<SS_CLOSE)|(1<<SS_TIME_WAIT)|(1<<SS_SYN_RECV)))
@ -204,6 +220,10 @@ static const struct filter default_dbs[MAX_DB] = {
.states = (1 << SS_CLOSE),
.families = (1 << AF_NETLINK),
},
[SCTP_DB] = {
.states = SS_CONN,
.families = (1 << AF_INET) | (1 << AF_INET6),
},
};
static const struct filter default_afs[AF_MAX] = {
@ -264,6 +284,7 @@ static void filter_default_dbs(struct filter *f)
filter_db_set(f, PACKET_R_DB);
filter_db_set(f, PACKET_DG_DB);
filter_db_set(f, NETLINK_DB);
filter_db_set(f, SCTP_DB);
}
static void filter_states_set(struct filter *f, int states)
@ -705,6 +726,17 @@ static const char *sstate_name[] = {
[SS_CLOSING] = "CLOSING",
};
static const char *sctp_sstate_name[] = {
[SCTP_STATE_CLOSED] = "CLOSED",
[SCTP_STATE_COOKIE_WAIT] = "COOKIE_WAIT",
[SCTP_STATE_COOKIE_ECHOED] = "COOKIE_ECHOED",
[SCTP_STATE_ESTABLISHED] = "ESTAB",
[SCTP_STATE_SHUTDOWN_PENDING] = "SHUTDOWN_PENDING",
[SCTP_STATE_SHUTDOWN_SENT] = "SHUTDOWN_SENT",
[SCTP_STATE_SHUTDOWN_RECEIVED] = "SHUTDOWN_RECEIVED",
[SCTP_STATE_SHUTDOWN_ACK_SENT] = "ACK_SENT",
};
static const char *sstate_namel[] = {
"UNKNOWN",
[SS_ESTABLISHED] = "established",
@ -793,12 +825,30 @@ struct tcpstat {
struct tcp_bbr_info *bbr_info;
};
/* SCTP assocs share the same inode number with their parent endpoint. So if we
* have seen the inode number before, it must be an assoc instead of the next
* endpoint. */
static bool is_sctp_assoc(struct sockstat *s, const char *sock_name)
{
if (strcmp(sock_name, "sctp"))
return false;
if (!sctp_ino || sctp_ino != s->ino)
return false;
return true;
}
static void sock_state_print(struct sockstat *s, const char *sock_name)
{
if (netid_width)
printf("%-*s ", netid_width, sock_name);
if (state_width)
printf("%-*s ", state_width, sstate_name[s->state]);
printf("%-*s ", netid_width,
is_sctp_assoc(s, sock_name) ? "" : sock_name);
if (state_width) {
if (is_sctp_assoc(s, sock_name))
printf("`- %-*s ", state_width - 3,
sctp_sstate_name[s->state]);
else
printf("%-*s ", state_width, sstate_name[s->state]);
}
printf("%-6d %-6d ", s->rq, s->wq);
}
@ -908,6 +958,8 @@ static void init_service_resolver(void)
c->proto = TCP_PROTO;
else if (strcmp(proto, UDP_PROTO) == 0)
c->proto = UDP_PROTO;
else if (strcmp(proto, SCTP_PROTO) == 0)
c->proto = SCTP_PROTO;
else
c->proto = NULL;
c->next = rlist;
@ -1679,6 +1731,8 @@ static char *proto_name(int protocol)
return "udp";
case IPPROTO_TCP:
return "tcp";
case IPPROTO_SCTP:
return "sctp";
case IPPROTO_DCCP:
return "dccp";
}
@ -1771,6 +1825,56 @@ static char *sprint_bw(char *buf, double bw)
return buf;
}
static void sctp_stats_print(struct sctp_info *s)
{
if (s->sctpi_tag)
printf(" tag:%x", s->sctpi_tag);
if (s->sctpi_state)
printf(" state:%s", sctp_sstate_name[s->sctpi_state]);
if (s->sctpi_rwnd)
printf(" rwnd:%d", s->sctpi_rwnd);
if (s->sctpi_unackdata)
printf(" unackdata:%d", s->sctpi_unackdata);
if (s->sctpi_penddata)
printf(" penddata:%d", s->sctpi_penddata);
if (s->sctpi_instrms)
printf(" instrms:%d", s->sctpi_instrms);
if (s->sctpi_outstrms)
printf(" outstrms:%d", s->sctpi_outstrms);
if (s->sctpi_inqueue)
printf(" inqueue:%d", s->sctpi_inqueue);
if (s->sctpi_outqueue)
printf(" outqueue:%d", s->sctpi_outqueue);
if (s->sctpi_overall_error)
printf(" overerr:%d", s->sctpi_overall_error);
if (s->sctpi_max_burst)
printf(" maxburst:%d", s->sctpi_max_burst);
if (s->sctpi_maxseg)
printf(" maxseg:%d", s->sctpi_maxseg);
if (s->sctpi_peer_rwnd)
printf(" prwnd:%d", s->sctpi_peer_rwnd);
if (s->sctpi_peer_tag)
printf(" ptag:%x", s->sctpi_peer_tag);
if (s->sctpi_peer_capable)
printf(" pcapable:%d", s->sctpi_peer_capable);
if (s->sctpi_peer_sack)
printf(" psack:%d", s->sctpi_peer_sack);
if (s->sctpi_s_autoclose)
printf(" autoclose:%d", s->sctpi_s_autoclose);
if (s->sctpi_s_adaptation_ind)
printf(" adapind:%d", s->sctpi_s_adaptation_ind);
if (s->sctpi_s_pd_point)
printf(" pdpoint:%d", s->sctpi_s_pd_point);
if (s->sctpi_s_nodelay)
printf(" nodealy:%d", s->sctpi_s_nodelay);
if (s->sctpi_s_disable_fragments)
printf(" nofrag:%d", s->sctpi_s_disable_fragments);
if (s->sctpi_s_v4mapped)
printf(" v4mapped:%d", s->sctpi_s_v4mapped);
if (s->sctpi_s_frag_interleave)
printf(" fraginl:%d", s->sctpi_s_frag_interleave);
}
static void tcp_stats_print(struct tcpstat *s)
{
char b1[64];
@ -1902,6 +2006,13 @@ static void tcp_timer_print(struct tcpstat *s)
}
}
static void sctp_timer_print(struct tcpstat *s)
{
if (s->timer)
printf(" timer:(T3_RTX,%s,%d)",
print_ms_timer(s->timeout), s->retrans);
}
static int tcp_show_line(char *line, const struct filter *f, int family)
{
int rto = 0, ato = 0;
@ -2168,6 +2279,64 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
}
}
static const char *format_host_sa(struct sockaddr_storage *sa)
{
union {
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
} *saddr = (void *)sa;
switch (sa->ss_family) {
case AF_INET:
return format_host(AF_INET, 4, &saddr->sin.sin_addr);
case AF_INET6:
return format_host(AF_INET6, 16, &saddr->sin6.sin6_addr);
default:
return "";
}
}
static void sctp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
struct rtattr *tb[])
{
struct sockaddr_storage *sa;
int len;
print_skmeminfo(tb, INET_DIAG_SKMEMINFO);
if (tb[INET_DIAG_LOCALS]) {
len = RTA_PAYLOAD(tb[INET_DIAG_LOCALS]);
sa = RTA_DATA(tb[INET_DIAG_LOCALS]);
printf("locals:%s", format_host_sa(sa));
for (sa++, len -= sizeof(*sa); len > 0; sa++, len -= sizeof(*sa))
printf(",%s", format_host_sa(sa));
}
if (tb[INET_DIAG_PEERS]) {
len = RTA_PAYLOAD(tb[INET_DIAG_PEERS]);
sa = RTA_DATA(tb[INET_DIAG_PEERS]);
printf(" peers:%s", format_host_sa(sa));
for (sa++, len -= sizeof(*sa); len > 0; sa++, len -= sizeof(*sa))
printf(",%s", format_host_sa(sa));
}
if (tb[INET_DIAG_INFO]) {
struct sctp_info *info;
len = RTA_PAYLOAD(tb[INET_DIAG_INFO]);
/* workaround for older kernels with less fields */
if (len < sizeof(*info)) {
info = alloca(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]);
sctp_stats_print(info);
}
}
static void parse_diag_msg(struct nlmsghdr *nlh, struct sockstat *s)
{
struct rtattr *tb[INET_DIAG_MAX+1];
@ -2221,7 +2390,10 @@ static int inet_show_sock(struct nlmsghdr *nlh,
t.timer = r->idiag_timer;
t.timeout = r->idiag_expires;
t.retrans = r->idiag_retrans;
tcp_timer_print(&t);
if (protocol == IPPROTO_SCTP)
sctp_timer_print(&t);
else
tcp_timer_print(&t);
}
if (show_details) {
@ -2242,8 +2414,12 @@ static int inet_show_sock(struct nlmsghdr *nlh,
if (show_mem || show_tcpinfo) {
printf("\n\t");
tcp_show_info(nlh, r, tb);
if (protocol == IPPROTO_SCTP)
sctp_show_info(nlh, r, tb);
else
tcp_show_info(nlh, r, tb);
}
sctp_ino = s->ino;
printf("\n");
return 0;
@ -2627,6 +2803,17 @@ outerr:
} while (0);
}
static int sctp_show(struct filter *f)
{
if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
return 0;
if (!getenv("PROC_NET_SCTP") && !getenv("PROC_ROOT")
&& inet_show_netlink(f, NULL, IPPROTO_SCTP) == 0)
return 0;
return 0;
}
static int dgram_show_line(char *line, const struct filter *f, int family)
{
@ -2895,7 +3082,9 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
memcpy(name, RTA_DATA(tb[UNIX_DIAG_NAME]), len);
name[len] = '\0';
if (name[0] == '\0')
name[0] = '@';
for (int i = 0; i < len; i++)
if (name[i] == '\0')
name[i] = '@';
stat.name = &name[0];
memcpy(stat.local.data, &stat.name, sizeof(stat.name));
}
@ -3738,6 +3927,7 @@ static void _usage(FILE *dest)
" -6, --ipv6 display only IP version 6 sockets\n"
" -0, --packet display PACKET sockets\n"
" -t, --tcp display only TCP sockets\n"
" -S, --sctp display only SCTP sockets\n"
" -u, --udp display only UDP sockets\n"
" -d, --dccp display only DCCP sockets\n"
" -w, --raw display only RAW sockets\n"
@ -3820,6 +4010,7 @@ static const struct option long_opts[] = {
{ "events", 0, 0, 'E' },
{ "dccp", 0, 0, 'd' },
{ "tcp", 0, 0, 't' },
{ "sctp", 0, 0, 'S' },
{ "udp", 0, 0, 'u' },
{ "raw", 0, 0, 'w' },
{ "unix", 0, 0, 'x' },
@ -3855,7 +4046,8 @@ int main(int argc, char *argv[])
int ch;
int state_filter = 0;
while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbEf:miA:D:F:vVzZN:KH",
while ((ch = getopt_long(argc, argv,
"dhaletuwxnro460spbEf:miA:D:F:vVzZN:KHS",
long_opts, NULL)) != EOF) {
switch (ch) {
case 'n':
@ -3894,6 +4086,9 @@ int main(int argc, char *argv[])
case 't':
filter_db_set(&current_filter, TCP_DB);
break;
case 'S':
filter_db_set(&current_filter, SCTP_DB);
break;
case 'u':
filter_db_set(&current_filter, UDP_DB);
break;
@ -3958,6 +4153,7 @@ int main(int argc, char *argv[])
filter_db_set(&current_filter, UDP_DB);
filter_db_set(&current_filter, DCCP_DB);
filter_db_set(&current_filter, TCP_DB);
filter_db_set(&current_filter, SCTP_DB);
filter_db_set(&current_filter, RAW_DB);
} else if (strcmp(p, "udp") == 0) {
filter_db_set(&current_filter, UDP_DB);
@ -3965,6 +4161,8 @@ int main(int argc, char *argv[])
filter_db_set(&current_filter, DCCP_DB);
} else if (strcmp(p, "tcp") == 0) {
filter_db_set(&current_filter, TCP_DB);
} else if (strcmp(p, "sctp") == 0) {
filter_db_set(&current_filter, SCTP_DB);
} else if (strcmp(p, "raw") == 0) {
filter_db_set(&current_filter, RAW_DB);
} else if (strcmp(p, "unix") == 0) {
@ -4089,10 +4287,9 @@ int main(int argc, char *argv[])
filter_merge_defaults(&current_filter);
if (resolve_services && resolve_hosts &&
(current_filter.dbs&(UNIX_DBM|(1<<TCP_DB)|(1<<UDP_DB)|(1<<DCCP_DB))))
(current_filter.dbs & (UNIX_DBM|INET_L4_DBM)))
init_service_resolver();
if (current_filter.dbs == 0) {
fprintf(stderr, "ss: no socket tables to show with such filter.\n");
exit(0);
@ -4205,6 +4402,8 @@ int main(int argc, char *argv[])
tcp_show(&current_filter, IPPROTO_TCP);
if (current_filter.dbs & (1<<DCCP_DB))
tcp_show(&current_filter, IPPROTO_DCCP);
if (current_filter.dbs & (1<<SCTP_DB))
sctp_show(&current_filter);
if (show_users || show_proc_ctx || show_sock_ctx)
user_ent_destroy();

View File

@ -37,7 +37,6 @@ static void explain(void)
" vlan_ethtype [ ipv4 | ipv6 | ETH-TYPE ] |\n"
" dst_mac MAC-ADDR |\n"
" src_mac MAC-ADDR |\n"
" [ipv4 | ipv6 ] |\n"
" ip_proto [tcp | udp | IP-PROTO ] |\n"
" dst_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
" src_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
@ -46,7 +45,7 @@ static void explain(void)
" FILTERID := X:Y:Z\n"
" ACTION-SPEC := ... look at individual actions\n"
"\n"
"NOTE: CLASSID, ETH-TYPE, IP-PROTO are parsed as hexadecimal input.\n"
"NOTE: CLASSID, IP-PROTO are parsed as hexadecimal input.\n"
"NOTE: There can be only used one mask per one prio. If user needs\n"
" to specify different mask, he has to use different prio.\n");
}

View File

@ -25,10 +25,19 @@
static void explain(void)
{
fprintf(stderr, "Usage: ... fw [ classid CLASSID ] [ action ACTION_SPEC ]\n");
fprintf(stderr, " ACTION_SPEC := ... look at individual actions\n");
fprintf(stderr, " CLASSID := X:Y\n");
fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
fprintf(stderr,
"Usage: ... fw [ classid CLASSID ] [ indev DEV ] [ action ACTION_SPEC ]\n");
fprintf(stderr,
" CLASSID := Push matching packets to the class identified by CLASSID with format X:Y\n");
fprintf(stderr,
" CLASSID is parsed as hexadecimal input.\n");
fprintf(stderr,
" DEV := specify device for incoming device classification.\n");
fprintf(stderr,
" ACTION_SPEC := Apply an action on matching packets.\n");
fprintf(stderr,
" NOTE: handle is represented as HANDLE[/FWMASK].\n");
fprintf(stderr, " FWMASK is 0xffffffff by default.\n");
}
static int fw_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n)

View File

@ -226,6 +226,16 @@ int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
if (n->nlmsg_type == RTM_DELTFILTER)
fprintf(fp, "deleted ");
if (n->nlmsg_type == RTM_NEWTFILTER &&
(n->nlmsg_flags & NLM_F_CREATE) &&
!(n->nlmsg_flags & NLM_F_EXCL))
fprintf(fp, "replaced ");
if (n->nlmsg_type == RTM_NEWTFILTER &&
(n->nlmsg_flags & NLM_F_CREATE) &&
(n->nlmsg_flags & NLM_F_EXCL))
fprintf(fp, "added ");
fprintf(fp, "filter ");
if (!filter_ifindex || filter_ifindex != t->tcm_ifindex)
fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex));

View File

@ -182,7 +182,8 @@ static int tc_qdisc_modify(int cmd, unsigned int flags, int argc, char **argv)
ll_init_map(&rth);
if ((idx = ll_name_to_index(d)) == 0) {
idx = ll_name_to_index(d);
if (idx == 0) {
fprintf(stderr, "Cannot find device \"%s\"\n", d);
return 1;
}
@ -198,8 +199,7 @@ static int tc_qdisc_modify(int cmd, unsigned int flags, int argc, char **argv)
static int filter_ifindex;
int print_qdisc(const struct sockaddr_nl *who,
struct nlmsghdr *n,
void *arg)
struct nlmsghdr *n, void *arg)
{
FILE *fp = (FILE *)arg;
struct tcmsg *t = NLMSG_DATA(n);
@ -231,21 +231,29 @@ int print_qdisc(const struct sockaddr_nl *who,
if (n->nlmsg_type == RTM_DELQDISC)
fprintf(fp, "deleted ");
fprintf(fp, "qdisc %s %x: ", rta_getattr_str(tb[TCA_KIND]), t->tcm_handle>>16);
if (show_raw)
fprintf(fp, "qdisc %s %x:[%08x] ",
rta_getattr_str(tb[TCA_KIND]),
t->tcm_handle >> 16, t->tcm_handle);
else
fprintf(fp, "qdisc %s %x: ", rta_getattr_str(tb[TCA_KIND]),
t->tcm_handle >> 16);
if (filter_ifindex == 0)
fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex));
if (t->tcm_parent == TC_H_ROOT)
fprintf(fp, "root ");
else if (t->tcm_parent) {
print_tc_classid(abuf, sizeof(abuf), t->tcm_parent);
fprintf(fp, "parent %s ", abuf);
}
if (t->tcm_info != 1) {
fprintf(fp, "refcnt %d ", t->tcm_info);
}
/* pfifo_fast is generic enough to warrant the hardcoding --JHS */
if (0 == strcmp("pfifo_fast", RTA_DATA(tb[TCA_KIND])))
if (t->tcm_info != 1)
fprintf(fp, "refcnt %d ", t->tcm_info);
/* pfifo_fast is generic enough to warrant the hardcoding --JHS */
if (strcmp("pfifo_fast", RTA_DATA(tb[TCA_KIND])) == 0)
q = get_qdisc_kind("prio");
else
q = get_qdisc_kind(RTA_DATA(tb[TCA_KIND]));
@ -257,10 +265,12 @@ int print_qdisc(const struct sockaddr_nl *who,
fprintf(fp, "[cannot parse qdisc parameters]");
}
fprintf(fp, "\n");
if (show_details && tb[TCA_STAB]) {
print_size_table(fp, " ", tb[TCA_STAB]);
fprintf(fp, "\n");
}
if (show_stats) {
struct rtattr *xstats = NULL;
@ -289,11 +299,11 @@ static int tc_qdisc_list(int argc, char **argv)
strncpy(d, *argv, sizeof(d)-1);
} else if (strcmp(*argv, "ingress") == 0 ||
strcmp(*argv, "clsact") == 0) {
if (t.tcm_parent) {
fprintf(stderr, "Duplicate parent ID\n");
usage();
}
t.tcm_parent = TC_H_INGRESS;
if (t.tcm_parent) {
fprintf(stderr, "Duplicate parent ID\n");
usage();
}
t.tcm_parent = TC_H_INGRESS;
} else if (matches(*argv, "help") == 0) {
usage();
} else {
@ -307,7 +317,8 @@ static int tc_qdisc_list(int argc, char **argv)
ll_init_map(&rth);
if (d[0]) {
if ((t.tcm_ifindex = ll_name_to_index(d)) == 0) {
t.tcm_ifindex = ll_name_to_index(d);
if (t.tcm_ifindex == 0) {
fprintf(stderr, "Cannot find device \"%s\"\n", d);
return 1;
}