Merge branch 'master' into net-next
This commit is contained in:
commit
328374dcfe
|
|
@ -28,6 +28,10 @@
|
||||||
|
|
||||||
#define ESWITCH_MODE_LEGACY "legacy"
|
#define ESWITCH_MODE_LEGACY "legacy"
|
||||||
#define ESWITCH_MODE_SWITCHDEV "switchdev"
|
#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_err(args...) fprintf(stderr, ##args)
|
||||||
#define pr_out(args...) fprintf(stdout, ##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_TH BIT(9)
|
||||||
#define DL_OPT_SB_TC BIT(10)
|
#define DL_OPT_SB_TC BIT(10)
|
||||||
#define DL_OPT_ESWITCH_MODE BIT(11)
|
#define DL_OPT_ESWITCH_MODE BIT(11)
|
||||||
|
#define DL_OPT_ESWITCH_INLINE_MODE BIT(12)
|
||||||
|
|
||||||
struct dl_opts {
|
struct dl_opts {
|
||||||
uint32_t present; /* flags of present items */
|
uint32_t present; /* flags of present items */
|
||||||
|
|
@ -148,6 +153,7 @@ struct dl_opts {
|
||||||
uint32_t sb_threshold;
|
uint32_t sb_threshold;
|
||||||
uint16_t sb_tc_index;
|
uint16_t sb_tc_index;
|
||||||
enum devlink_eswitch_mode eswitch_mode;
|
enum devlink_eswitch_mode eswitch_mode;
|
||||||
|
enum devlink_eswitch_inline_mode eswitch_inline_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dl {
|
struct dl {
|
||||||
|
|
@ -305,6 +311,9 @@ static int attr_cb(const struct nlattr *attr, void *data)
|
||||||
if (type == DEVLINK_ATTR_ESWITCH_MODE &&
|
if (type == DEVLINK_ATTR_ESWITCH_MODE &&
|
||||||
mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
|
mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
|
||||||
return MNL_CB_ERROR;
|
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;
|
tb[type] = attr;
|
||||||
return MNL_CB_OK;
|
return MNL_CB_OK;
|
||||||
}
|
}
|
||||||
|
|
@ -682,6 +691,24 @@ static int eswitch_mode_get(const char *typestr,
|
||||||
return 0;
|
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,
|
static int dl_argv_parse(struct dl *dl, uint32_t o_required,
|
||||||
uint32_t o_optional)
|
uint32_t o_optional)
|
||||||
{
|
{
|
||||||
|
|
@ -803,6 +830,19 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required,
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
o_found |= DL_OPT_ESWITCH_MODE;
|
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 {
|
} else {
|
||||||
pr_err("Unknown option \"%s\"\n", dl_argv(dl));
|
pr_err("Unknown option \"%s\"\n", dl_argv(dl));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
@ -863,6 +903,12 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required,
|
||||||
return -EINVAL;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -909,6 +955,9 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
|
||||||
if (opts->present & DL_OPT_ESWITCH_MODE)
|
if (opts->present & DL_OPT_ESWITCH_MODE)
|
||||||
mnl_attr_put_u16(nlh, DEVLINK_ATTR_ESWITCH_MODE,
|
mnl_attr_put_u16(nlh, DEVLINK_ATTR_ESWITCH_MODE,
|
||||||
opts->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,
|
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)
|
static void cmd_dev_help(void)
|
||||||
{
|
{
|
||||||
pr_err("Usage: devlink dev show [ DEV ]\n");
|
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,
|
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)
|
static void pr_out_eswitch(struct dl *dl, struct nlattr **tb)
|
||||||
{
|
{
|
||||||
__pr_out_handle_start(dl, tb, true, false);
|
__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])
|
if (tb[DEVLINK_ATTR_ESWITCH_MODE])
|
||||||
pr_out_str(dl, "mode",
|
pr_out_str(dl, "mode",
|
||||||
eswitch_mode_name(mnl_attr_get_u16(tb[DEVLINK_ATTR_ESWITCH_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);
|
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,
|
nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_MODE_SET,
|
||||||
NLM_F_REQUEST | NLM_F_ACK);
|
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)
|
if (err)
|
||||||
return 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);
|
return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_dev_eswitch(struct dl *dl)
|
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);
|
dl_arg_inc(dl);
|
||||||
return cmd_dev_eswitch_set(dl);
|
return cmd_dev_eswitch_set(dl);
|
||||||
} else if (dl_argv_match(dl, "show")) {
|
} else if (dl_argv_match(dl, "show")) {
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
114
ip/ipaddress.c
114
ip/ipaddress.c
|
|
@ -148,11 +148,11 @@ static void print_operstate(FILE *f, __u8 state)
|
||||||
fprintf(f, "state %#x ", state);
|
fprintf(f, "state %#x ", state);
|
||||||
} else if (brief) {
|
} else if (brief) {
|
||||||
color_fprintf(f, oper_state_color(state),
|
color_fprintf(f, oper_state_color(state),
|
||||||
"%-14s ", oper_states[state]);
|
"%-14s ", oper_states[state]);
|
||||||
} else {
|
} else {
|
||||||
fprintf(f, "state ");
|
fprintf(f, "state ");
|
||||||
color_fprintf(f, oper_state_color(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_mac *vf_mac;
|
||||||
struct ifla_vf_tx_rate *vf_tx_rate;
|
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 *vf[IFLA_VF_MAX + 1] = {};
|
||||||
struct rtattr *tmp;
|
|
||||||
|
|
||||||
SPRINT_BUF(b1);
|
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_mac = RTA_DATA(vf[IFLA_VF_MAC]);
|
||||||
vf_tx_rate = RTA_DATA(vf[IFLA_VF_TX_RATE]);
|
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,
|
fprintf(fp, "%s vf %d MAC %s", _SL_, vf_mac->vf,
|
||||||
ll_addr_n2a((unsigned char *)&vf_mac->mac,
|
ll_addr_n2a((unsigned char *)&vf_mac->mac,
|
||||||
ETH_ALEN, 0, b1, sizeof(b1)));
|
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)
|
if (vf_rate->min_tx_rate)
|
||||||
fprintf(fp, ", min_tx_rate %dMbps", 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 != -1)
|
||||||
if (vf_spoofchk->setting)
|
fprintf(fp, ", spoof checking %s",
|
||||||
fprintf(fp, ", spoof checking on");
|
vf_spoofchk->setting ? "on" : "off");
|
||||||
else
|
|
||||||
fprintf(fp, ", spoof checking 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)
|
if (vf_linkstate->link_state == IFLA_VF_LINK_STATE_AUTO)
|
||||||
fprintf(fp, ", link-state auto");
|
fprintf(fp, ", link-state auto");
|
||||||
else if (vf_linkstate->link_state == IFLA_VF_LINK_STATE_ENABLE)
|
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)
|
if (vf_trust->setting != -1)
|
||||||
fprintf(fp, ", trust %s",
|
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)
|
if (vf[IFLA_VF_STATS] && show_stats)
|
||||||
print_vf_stats64(fp, vf[IFLA_VF_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
|
/* 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 (;;) {
|
for (;;) {
|
||||||
powi *= base;
|
powi *= base;
|
||||||
if (count / base < powi)
|
if (count / base < powi)
|
||||||
|
|
@ -691,9 +684,9 @@ int print_linkinfo_brief(const struct sockaddr_nl *who,
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
|
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);
|
fprintf(stderr, "BUG: device with ifindex %d has nil ifname\n", ifi->ifi_index);
|
||||||
}
|
|
||||||
if (filter.label &&
|
if (filter.label &&
|
||||||
(!filter.family || filter.family == AF_PACKET) &&
|
(!filter.family || filter.family == AF_PACKET) &&
|
||||||
fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0))
|
fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0))
|
||||||
|
|
@ -787,9 +780,9 @@ int print_linkinfo(const struct sockaddr_nl *who,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
|
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);
|
fprintf(stderr, "BUG: device with ifindex %d has nil ifname\n", ifi->ifi_index);
|
||||||
}
|
|
||||||
if (filter.label &&
|
if (filter.label &&
|
||||||
(!filter.family || filter.family == AF_PACKET) &&
|
(!filter.family || filter.family == AF_PACKET) &&
|
||||||
fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0))
|
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]) {
|
if (rta_tb[IFA_LOCAL]) {
|
||||||
color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s",
|
color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s",
|
||||||
format_host_rta(ifa->ifa_family,
|
format_host_rta(ifa->ifa_family,
|
||||||
rta_tb[IFA_LOCAL]));
|
rta_tb[IFA_LOCAL]));
|
||||||
if (rta_tb[IFA_ADDRESS] &&
|
if (rta_tb[IFA_ADDRESS] &&
|
||||||
memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]),
|
memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]),
|
||||||
RTA_DATA(rta_tb[IFA_LOCAL]),
|
RTA_DATA(rta_tb[IFA_LOCAL]),
|
||||||
ifa->ifa_family == AF_INET ? 4 : 16)) {
|
ifa->ifa_family == AF_INET ? 4 : 16)) {
|
||||||
fprintf(fp, " peer ");
|
fprintf(fp, " peer ");
|
||||||
color_fprintf(fp, ifa_family_color(ifa->ifa_family),
|
color_fprintf(fp, ifa_family_color(ifa->ifa_family),
|
||||||
"%s", format_host_rta(ifa->ifa_family,
|
"%s", format_host_rta(ifa->ifa_family,
|
||||||
rta_tb[IFA_ADDRESS]));
|
rta_tb[IFA_ADDRESS]));
|
||||||
}
|
}
|
||||||
fprintf(fp, "/%d ", ifa->ifa_prefixlen);
|
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]) {
|
if (rta_tb[IFA_BROADCAST]) {
|
||||||
fprintf(fp, "brd ");
|
fprintf(fp, "brd ");
|
||||||
color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s ",
|
color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s ",
|
||||||
format_host_rta(ifa->ifa_family,
|
format_host_rta(ifa->ifa_family,
|
||||||
rta_tb[IFA_BROADCAST]));
|
rta_tb[IFA_BROADCAST]));
|
||||||
}
|
}
|
||||||
if (rta_tb[IFA_ANYCAST]) {
|
if (rta_tb[IFA_ANYCAST]) {
|
||||||
fprintf(fp, "any ");
|
fprintf(fp, "any ");
|
||||||
color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s ",
|
color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s ",
|
||||||
format_host_rta(ifa->ifa_family,
|
format_host_rta(ifa->ifa_family,
|
||||||
rta_tb[IFA_ANYCAST]));
|
rta_tb[IFA_ANYCAST]));
|
||||||
}
|
}
|
||||||
fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1)));
|
fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1)));
|
||||||
if (ifa_flags & IFA_F_SECONDARY) {
|
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;
|
ifa_flags &= ~IFA_F_MCAUTOJOIN;
|
||||||
fprintf(fp, "autojoin ");
|
fprintf(fp, "autojoin ");
|
||||||
}
|
}
|
||||||
if (!(ifa_flags & IFA_F_PERMANENT)) {
|
if (!(ifa_flags & IFA_F_PERMANENT))
|
||||||
fprintf(fp, "dynamic ");
|
fprintf(fp, "dynamic ");
|
||||||
} else
|
else
|
||||||
ifa_flags &= ~IFA_F_PERMANENT;
|
ifa_flags &= ~IFA_F_PERMANENT;
|
||||||
if (ifa_flags & IFA_F_DADFAILED) {
|
if (ifa_flags & IFA_F_DADFAILED) {
|
||||||
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;
|
filter.kind = *argv;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (strcmp(*argv, "dev") == 0) {
|
if (strcmp(*argv, "dev") == 0)
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
} else if (matches(*argv, "help") == 0)
|
else if (matches(*argv, "help") == 0)
|
||||||
usage();
|
usage();
|
||||||
if (filter_dev)
|
if (filter_dev)
|
||||||
duparg2("dev", *argv);
|
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) {
|
} else if (strcmp(*argv, "autojoin") == 0) {
|
||||||
ifa_flags |= IFA_F_MCAUTOJOIN;
|
ifa_flags |= IFA_F_MCAUTOJOIN;
|
||||||
} else {
|
} else {
|
||||||
if (strcmp(*argv, "local") == 0) {
|
if (strcmp(*argv, "local") == 0)
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
}
|
|
||||||
if (matches(*argv, "help") == 0)
|
if (matches(*argv, "help") == 0)
|
||||||
usage();
|
usage();
|
||||||
if (local_len)
|
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 (peer_len == 0 && local_len) {
|
||||||
if (cmd == RTM_DELADDR && lcl.family == AF_INET && !(lcl.flags & PREFIXLEN_SPECIFIED)) {
|
if (cmd == RTM_DELADDR && lcl.family == AF_INET && !(lcl.flags & PREFIXLEN_SPECIFIED)) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Warning: Executing wildcard deletion to stay compatible with old scripts.\n" \
|
"Warning: Executing wildcard deletion to stay compatible with old scripts.\n"
|
||||||
" Explicitly specify the prefix length (%s/%d) to avoid this warning.\n" \
|
" Explicitly specify the prefix length (%s/%d) to avoid this warning.\n"
|
||||||
" This special behaviour is likely to disappear in further releases,\n" \
|
" This special behaviour is likely to disappear in further releases,\n"
|
||||||
" fix your scripts!\n", lcl_arg, local_len*8);
|
" fix your scripts!\n", lcl_arg, local_len*8);
|
||||||
} else {
|
} else {
|
||||||
peer = lcl;
|
peer = lcl;
|
||||||
|
|
|
||||||
202
ip/ipl2tp.c
202
ip/ipl2tp.c
|
|
@ -56,15 +56,15 @@ struct l2tp_parm {
|
||||||
|
|
||||||
uint16_t pw_type;
|
uint16_t pw_type;
|
||||||
uint16_t mtu;
|
uint16_t mtu;
|
||||||
int udp6_csum_tx:1;
|
unsigned int udp6_csum_tx:1;
|
||||||
int udp6_csum_rx:1;
|
unsigned int udp6_csum_rx:1;
|
||||||
int udp_csum:1;
|
unsigned int udp_csum:1;
|
||||||
int recv_seq:1;
|
unsigned int recv_seq:1;
|
||||||
int send_seq:1;
|
unsigned int send_seq:1;
|
||||||
int lns_mode:1;
|
unsigned int lns_mode:1;
|
||||||
int data_seq:2;
|
unsigned int data_seq:2;
|
||||||
int tunnel:1;
|
unsigned int tunnel:1;
|
||||||
int session:1;
|
unsigned int session:1;
|
||||||
int reorder_timeout;
|
int reorder_timeout;
|
||||||
const char *ifname;
|
const char *ifname;
|
||||||
uint8_t l2spec_type;
|
uint8_t l2spec_type;
|
||||||
|
|
@ -110,17 +110,19 @@ static int create_tunnel(struct l2tp_parm *p)
|
||||||
|
|
||||||
if (p->local_ip.family == AF_INET6)
|
if (p->local_ip.family == AF_INET6)
|
||||||
local_attr = L2TP_ATTR_IP6_SADDR;
|
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)
|
if (p->peer_ip.family == AF_INET6)
|
||||||
peer_attr = L2TP_ATTR_IP6_DADDR;
|
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) {
|
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_SPORT, p->local_udp_port);
|
||||||
addattr16(&req.n, 1024, L2TP_ATTR_UDP_DPORT, p->peer_udp_port);
|
addattr16(&req.n, 1024, L2TP_ATTR_UDP_DPORT, p->peer_udp_port);
|
||||||
if (p->udp_csum)
|
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)
|
if (!p->udp6_csum_tx)
|
||||||
addattr(&req.n, 1024, L2TP_ATTR_UDP_ZERO_CSUM6_TX);
|
addattr(&req.n, 1024, L2TP_ATTR_UDP_ZERO_CSUM6_TX);
|
||||||
if (!p->udp6_csum_rx)
|
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_TYPE, p->l2spec_type);
|
||||||
addattr8(&req.n, 1024, L2TP_ATTR_L2SPEC_LEN, p->l2spec_len);
|
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->mtu)
|
||||||
if (p->recv_seq) addattr(&req.n, 1024, L2TP_ATTR_RECV_SEQ);
|
addattr16(&req.n, 1024, L2TP_ATTR_MTU, p->mtu);
|
||||||
if (p->send_seq) addattr(&req.n, 1024, L2TP_ATTR_SEND_SEQ);
|
if (p->recv_seq)
|
||||||
if (p->lns_mode) addattr(&req.n, 1024, L2TP_ATTR_LNS_MODE);
|
addattr8(&req.n, 1024, L2TP_ATTR_RECV_SEQ, 1);
|
||||||
if (p->data_seq) addattr8(&req.n, 1024, L2TP_ATTR_DATA_SEQ, p->data_seq);
|
if (p->send_seq)
|
||||||
if (p->reorder_timeout) addattr64(&req.n, 1024, L2TP_ATTR_RECV_TIMEOUT,
|
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);
|
p->reorder_timeout);
|
||||||
if (p->offset) addattr16(&req.n, 1024, L2TP_ATTR_OFFSET, p->offset);
|
if (p->offset)
|
||||||
if (p->cookie_len) addattr_l(&req.n, 1024, L2TP_ATTR_COOKIE,
|
addattr16(&req.n, 1024, L2TP_ATTR_OFFSET, p->offset);
|
||||||
p->cookie, p->cookie_len);
|
if (p->cookie_len)
|
||||||
if (p->peer_cookie_len) addattr_l(&req.n, 1024, L2TP_ATTR_PEER_COOKIE,
|
addattr_l(&req.n, 1024, L2TP_ATTR_COOKIE,
|
||||||
p->peer_cookie, p->peer_cookie_len);
|
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])
|
if (p->ifname && p->ifname[0])
|
||||||
addattrstrz(&req.n, 1024, L2TP_ATTR_IFNAME, p->ifname);
|
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->tunnel_id,
|
||||||
p->encap == L2TP_ENCAPTYPE_UDP ? "UDP" :
|
p->encap == L2TP_ENCAPTYPE_UDP ? "UDP" :
|
||||||
p->encap == L2TP_ENCAPTYPE_IP ? "IP" : "??");
|
p->encap == L2TP_ENCAPTYPE_IP ? "IP" : "??");
|
||||||
printf(" From %s ", inet_ntop(p->local_ip.family, p->local_ip.data, buf, sizeof(buf)));
|
printf(" From %s ",
|
||||||
printf("to %s\n", inet_ntop(p->peer_ip.family, p->peer_ip.data, buf, sizeof(buf)));
|
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",
|
printf(" Peer tunnel %u\n",
|
||||||
p->peer_tunnel_id);
|
p->peer_tunnel_id);
|
||||||
|
|
||||||
if (p->encap == L2TP_ENCAPTYPE_UDP)
|
if (p->encap == L2TP_ENCAPTYPE_UDP) {
|
||||||
printf(" UDP source / dest ports: %hu/%hu\n",
|
printf(" UDP source / dest ports: %hu/%hu\n",
|
||||||
p->local_udp_port, p->peer_udp_port);
|
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)
|
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",
|
printf(" Peer session %u, tunnel %u\n",
|
||||||
p->peer_session_id, p->peer_tunnel_id);
|
p->peer_session_id, p->peer_tunnel_id);
|
||||||
|
|
||||||
if (p->ifname != NULL) {
|
if (p->ifname != NULL)
|
||||||
printf(" interface name: %s\n", p->ifname);
|
printf(" interface name: %s\n", p->ifname);
|
||||||
}
|
|
||||||
printf(" offset %u, peer offset %u\n",
|
printf(" offset %u, peer offset %u\n",
|
||||||
p->offset, p->peer_offset);
|
p->offset, p->peer_offset);
|
||||||
if (p->cookie_len > 0)
|
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);
|
printf(" reorder timeout: %u\n", p->reorder_timeout);
|
||||||
else
|
else
|
||||||
printf("\n");
|
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)
|
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])
|
if (attrs[L2TP_ATTR_L2SPEC_LEN])
|
||||||
p->l2spec_len = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_LEN]);
|
p->l2spec_len = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_LEN]);
|
||||||
|
|
||||||
p->udp_csum = !!attrs[L2TP_ATTR_UDP_CSUM];
|
if (attrs[L2TP_ATTR_UDP_CSUM])
|
||||||
/*
|
p->udp_csum = !!rta_getattr_u8(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 = !attrs[L2TP_ATTR_UDP_ZERO_CSUM6_TX];
|
||||||
*/
|
p->udp6_csum_rx = !attrs[L2TP_ATTR_UDP_ZERO_CSUM6_RX];
|
||||||
p->udp6_csum_tx = 1;
|
|
||||||
p->udp6_csum_rx = 1;
|
|
||||||
if (attrs[L2TP_ATTR_COOKIE])
|
if (attrs[L2TP_ATTR_COOKIE])
|
||||||
memcpy(p->cookie, RTA_DATA(attrs[L2TP_ATTR_COOKIE]),
|
memcpy(p->cookie, RTA_DATA(attrs[L2TP_ATTR_COOKIE]),
|
||||||
p->cookie_len = RTA_PAYLOAD(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]),
|
memcpy(p->peer_cookie, RTA_DATA(attrs[L2TP_ATTR_PEER_COOKIE]),
|
||||||
p->peer_cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_PEER_COOKIE]));
|
p->peer_cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_PEER_COOKIE]));
|
||||||
|
|
||||||
p->recv_seq = !!attrs[L2TP_ATTR_RECV_SEQ];
|
if (attrs[L2TP_ATTR_RECV_SEQ])
|
||||||
p->send_seq = !!attrs[L2TP_ATTR_SEND_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])
|
if (attrs[L2TP_ATTR_RECV_TIMEOUT])
|
||||||
p->reorder_timeout = rta_getattr_u64(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;
|
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);
|
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) {
|
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_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)
|
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;
|
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);
|
int ret = get_response(n, arg);
|
||||||
|
|
||||||
|
|
@ -468,31 +514,33 @@ static void usage(void) __attribute__((noreturn));
|
||||||
|
|
||||||
static void usage(void)
|
static void usage(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: ip l2tp add tunnel\n");
|
fprintf(stderr, "Usage: ip l2tp add tunnel\n"
|
||||||
fprintf(stderr, " remote ADDR local ADDR\n");
|
" remote ADDR local ADDR\n"
|
||||||
fprintf(stderr, " tunnel_id ID peer_tunnel_id ID\n");
|
" tunnel_id ID peer_tunnel_id ID\n"
|
||||||
fprintf(stderr, " [ encap { ip | udp } ]\n");
|
" [ encap { ip | udp } ]\n"
|
||||||
fprintf(stderr, " [ udp_sport PORT ] [ udp_dport PORT ]\n");
|
" [ udp_sport PORT ] [ udp_dport PORT ]\n"
|
||||||
fprintf(stderr, " [ udp_csum { on | off } ]\n");
|
" [ udp_csum { on | off } ]\n"
|
||||||
fprintf(stderr, " [ udp6_csum_tx { on | off } ]\n");
|
" [ udp6_csum_tx { on | off } ]\n"
|
||||||
fprintf(stderr, " [ udp6_csum_rx { on | off } ]\n");
|
" [ udp6_csum_rx { on | off } ]\n"
|
||||||
fprintf(stderr, "Usage: ip l2tp add session [ name NAME ]\n");
|
"Usage: ip l2tp add session [ name NAME ]\n"
|
||||||
fprintf(stderr, " tunnel_id ID\n");
|
" tunnel_id ID\n"
|
||||||
fprintf(stderr, " session_id ID peer_session_id ID\n");
|
" session_id ID peer_session_id ID\n"
|
||||||
fprintf(stderr, " [ cookie HEXSTR ] [ peer_cookie HEXSTR ]\n");
|
" [ cookie HEXSTR ] [ peer_cookie HEXSTR ]\n"
|
||||||
fprintf(stderr, " [ offset OFFSET ] [ peer_offset OFFSET ]\n");
|
" [ offset OFFSET ] [ peer_offset OFFSET ]\n"
|
||||||
fprintf(stderr, " [ l2spec_type L2SPEC ]\n");
|
" [ seq { none | send | recv | both } ]\n"
|
||||||
fprintf(stderr, " ip l2tp del tunnel tunnel_id ID\n");
|
" [ l2spec_type L2SPEC ]\n"
|
||||||
fprintf(stderr, " ip l2tp del session tunnel_id ID session_id ID\n");
|
" ip l2tp del tunnel tunnel_id ID\n"
|
||||||
fprintf(stderr, " ip l2tp show tunnel [ tunnel_id ID ]\n");
|
" ip l2tp del session tunnel_id ID session_id ID\n"
|
||||||
fprintf(stderr, " ip l2tp show session [ tunnel_id ID ] [ session_id ID ]\n");
|
" ip l2tp show tunnel [ tunnel_id ID ]\n"
|
||||||
fprintf(stderr, "\n");
|
" ip l2tp show session [ tunnel_id ID ] [ session_id ID ]\n"
|
||||||
fprintf(stderr, "Where: NAME := STRING\n");
|
"\n"
|
||||||
fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n");
|
"Where: NAME := STRING\n"
|
||||||
fprintf(stderr, " PORT := { 0..65535 }\n");
|
" ADDR := { IP_ADDRESS | any }\n"
|
||||||
fprintf(stderr, " ID := { 1..4294967295 }\n");
|
" PORT := { 0..65535 }\n"
|
||||||
fprintf(stderr, " HEXSTR := { 8 or 16 hex digits (4 / 8 bytes) }\n");
|
" ID := { 1..4294967295 }\n"
|
||||||
fprintf(stderr, " L2SPEC := { none | default }\n");
|
" HEXSTR := { 8 or 16 hex digits (4 / 8 bytes) }\n"
|
||||||
|
" L2SPEC := { none | default }\n");
|
||||||
|
|
||||||
exit(-1);
|
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_type = L2TP_L2SPECTYPE_NONE;
|
||||||
p->l2spec_len = 0;
|
p->l2spec_len = 0;
|
||||||
} else {
|
} 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);
|
exit(-1);
|
||||||
}
|
}
|
||||||
} else if (strcmp(*argv, "tunnel") == 0) {
|
} else if (strcmp(*argv, "tunnel") == 0) {
|
||||||
|
|
@ -779,6 +846,7 @@ int do_ipl2tp(int argc, char **argv)
|
||||||
matches(*argv, "list") == 0)
|
matches(*argv, "list") == 0)
|
||||||
return do_show(argc-1, argv+1);
|
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);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,8 +98,8 @@ void iplink_usage(void)
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" ip link help [ TYPE ]\n\n"
|
" ip link help [ TYPE ]\n\n"
|
||||||
"TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n"
|
"TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n"
|
||||||
" bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |\n"
|
" bridge | bond | team | ipoib | ip6tnl | ipip | sit | vxlan |\n"
|
||||||
" gre | gretap | ip6gre | ip6gretap | vti | nlmon |\n"
|
" gre | gretap | ip6gre | ip6gretap | vti | nlmon | team_slave |\n"
|
||||||
" bond_slave | ipvlan | geneve | bridge_slave | vrf | macsec }\n");
|
" bond_slave | ipvlan | geneve | bridge_slave | vrf | macsec }\n");
|
||||||
}
|
}
|
||||||
exit(-1);
|
exit(-1);
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <linux/if_link.h>
|
#include <linux/if_link.h>
|
||||||
|
#include <linux/if_ether.h>
|
||||||
|
|
||||||
#include "rt_names.h"
|
#include "rt_names.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
@ -29,7 +30,11 @@
|
||||||
static void print_explain(struct link_util *lu, FILE *f)
|
static void print_explain(struct link_util *lu, FILE *f)
|
||||||
{
|
{
|
||||||
fprintf(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
|
lu->id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -43,7 +48,15 @@ static void explain(struct link_util *lu)
|
||||||
static int mode_arg(const char *arg)
|
static int mode_arg(const char *arg)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
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);
|
arg);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -53,6 +66,10 @@ static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv,
|
||||||
{
|
{
|
||||||
__u32 mode = 0;
|
__u32 mode = 0;
|
||||||
__u16 flags = 0;
|
__u16 flags = 0;
|
||||||
|
__u32 mac_mode = 0;
|
||||||
|
int has_flags = 0;
|
||||||
|
char mac[ETH_ALEN];
|
||||||
|
struct rtattr *nmac;
|
||||||
|
|
||||||
while (argc > 0) {
|
while (argc > 0) {
|
||||||
if (matches(*argv, "mode") == 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;
|
mode = MACVLAN_MODE_BRIDGE;
|
||||||
else if (strcmp(*argv, "passthru") == 0)
|
else if (strcmp(*argv, "passthru") == 0)
|
||||||
mode = MACVLAN_MODE_PASSTHRU;
|
mode = MACVLAN_MODE_PASSTHRU;
|
||||||
|
else if (strcmp(*argv, "source") == 0)
|
||||||
|
mode = MACVLAN_MODE_SOURCE;
|
||||||
else
|
else
|
||||||
return mode_arg(*argv);
|
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) {
|
} else if (matches(*argv, "nopromisc") == 0) {
|
||||||
flags |= MACVLAN_FLAG_NOPROMISC;
|
flags |= MACVLAN_FLAG_NOPROMISC;
|
||||||
|
has_flags = 1;
|
||||||
} else if (matches(*argv, "help") == 0) {
|
} else if (matches(*argv, "help") == 0) {
|
||||||
explain(lu);
|
explain(lu);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -84,7 +163,7 @@ static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv,
|
||||||
if (mode)
|
if (mode)
|
||||||
addattr32(n, 1024, IFLA_MACVLAN_MODE, mode);
|
addattr32(n, 1024, IFLA_MACVLAN_MODE, mode);
|
||||||
|
|
||||||
if (flags) {
|
if (has_flags) {
|
||||||
if (flags & MACVLAN_FLAG_NOPROMISC &&
|
if (flags & MACVLAN_FLAG_NOPROMISC &&
|
||||||
mode != MACVLAN_MODE_PASSTHRU) {
|
mode != MACVLAN_MODE_PASSTHRU) {
|
||||||
pfx_err(lu, "nopromisc flag only valid in passthru mode");
|
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;
|
__u32 mode;
|
||||||
__u16 flags;
|
__u16 flags;
|
||||||
|
__u32 count;
|
||||||
|
unsigned char *addr;
|
||||||
|
int len;
|
||||||
|
struct rtattr *rta;
|
||||||
|
|
||||||
if (!tb)
|
if (!tb)
|
||||||
return;
|
return;
|
||||||
|
|
@ -109,20 +192,49 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mode = rta_getattr_u32(tb[IFLA_MACVLAN_MODE]);
|
mode = rta_getattr_u32(tb[IFLA_MACVLAN_MODE]);
|
||||||
fprintf(f, " mode %s ",
|
fprintf(f, "mode %s ",
|
||||||
mode == MACVLAN_MODE_PRIVATE ? "private"
|
mode == MACVLAN_MODE_PRIVATE ? "private"
|
||||||
: mode == MACVLAN_MODE_VEPA ? "vepa"
|
: mode == MACVLAN_MODE_VEPA ? "vepa"
|
||||||
: mode == MACVLAN_MODE_BRIDGE ? "bridge"
|
: mode == MACVLAN_MODE_BRIDGE ? "bridge"
|
||||||
: mode == MACVLAN_MODE_PASSTHRU ? "passthru"
|
: mode == MACVLAN_MODE_PASSTHRU ? "passthru"
|
||||||
|
: mode == MACVLAN_MODE_SOURCE ? "source"
|
||||||
: "unknown");
|
: "unknown");
|
||||||
|
|
||||||
if (!tb[IFLA_MACVLAN_FLAGS] ||
|
if (!tb[IFLA_MACVLAN_FLAGS] ||
|
||||||
RTA_PAYLOAD(tb[IFLA_MACVLAN_FLAGS]) < sizeof(__u16))
|
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)
|
if (flags & MACVLAN_FLAG_NOPROMISC)
|
||||||
fprintf(f, "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,
|
static void macvlan_print_help(struct link_util *lu, int argc, char **argv,
|
||||||
|
|
|
||||||
|
|
@ -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] = {
|
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_PROTECTED] = "OutPktsProtected",
|
||||||
[MACSEC_TXSC_STATS_ATTR_OUT_PKTS_ENCRYPTED] = "OutOctetsEncrypted",
|
[MACSEC_TXSC_STATS_ATTR_OUT_PKTS_ENCRYPTED] = "OutPktsEncrypted",
|
||||||
[MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_PROTECTED] = "OutPktsProtected",
|
[MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_PROTECTED] = "OutOctetsProtected",
|
||||||
[MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_ENCRYPTED] = "OutPktsEncrypted",
|
[MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_ENCRYPTED] = "OutOctetsEncrypted",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void print_txsc_stats(const char *prefix, struct rtattr *attr)
|
static void print_txsc_stats(const char *prefix, struct rtattr *attr)
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
|
||||||
fprintf(stderr, "Not a route: %08x %08x %08x\n",
|
fprintf(stderr, "Not a route: %08x %08x %08x\n",
|
||||||
n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
|
n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
|
if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -1755,7 +1755,7 @@ static int iproute_get(int argc, char **argv)
|
||||||
|
|
||||||
if (print_route(NULL, &req.n, (void *)stdout) < 0) {
|
if (print_route(NULL, &req.n, (void *)stdout) < 0) {
|
||||||
fprintf(stderr, "An error :-)\n");
|
fprintf(stderr, "An error :-)\n");
|
||||||
exit(1);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.n.nlmsg_type != RTM_NEWROUTE) {
|
if (req.n.nlmsg_type != RTM_NEWROUTE) {
|
||||||
|
|
|
||||||
121
lib/libnetlink.c
121
lib/libnetlink.c
|
|
@ -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)
|
int protocol)
|
||||||
{
|
{
|
||||||
socklen_t addr_len;
|
socklen_t addr_len;
|
||||||
|
|
@ -58,12 +58,14 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
|
||||||
return -1;
|
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");
|
perror("SO_SNDBUF");
|
||||||
return -1;
|
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");
|
perror("SO_RCVBUF");
|
||||||
return -1;
|
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_family = AF_NETLINK;
|
||||||
rth->local.nl_groups = subscriptions;
|
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");
|
perror("Cannot bind netlink socket");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
addr_len = sizeof(rth->local);
|
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");
|
perror("Cannot getsockname");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -86,14 +90,15 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (rth->local.nl_family != AF_NETLINK) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
rth->seq = time(NULL);
|
rth->seq = time(NULL);
|
||||||
return 0;
|
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);
|
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,
|
.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,
|
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)
|
if (err)
|
||||||
return 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,
|
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.family = fam;
|
||||||
req.ifsm.filter_mask = filt_mask;
|
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)
|
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);
|
for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status);
|
||||||
h = NLMSG_NEXT(h, status)) {
|
h = NLMSG_NEXT(h, status)) {
|
||||||
if (h->nlmsg_type == NLMSG_ERROR) {
|
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)))
|
if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
|
||||||
fprintf(stderr, "ERROR truncated\n");
|
fprintf(stderr, "ERROR truncated\n");
|
||||||
else
|
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 sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
|
||||||
struct iovec iov = {
|
struct iovec iov = {
|
||||||
.iov_base = (void*) n,
|
.iov_base = n,
|
||||||
.iov_len = n->nlmsg_len
|
.iov_len = n->nlmsg_len
|
||||||
};
|
};
|
||||||
struct msghdr msg = {
|
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);
|
fwrite(buf, 1, NLMSG_ALIGN(status), rth->dump_fp);
|
||||||
|
|
||||||
for (a = arg; a->filter; a++) {
|
for (a = arg; a->filter; a++) {
|
||||||
struct nlmsghdr *h = (struct nlmsghdr*)buf;
|
struct nlmsghdr *h = (struct nlmsghdr *)buf;
|
||||||
|
|
||||||
msglen = status;
|
msglen = status;
|
||||||
|
|
||||||
while (NLMSG_OK(h, msglen)) {
|
while (NLMSG_OK(h, msglen)) {
|
||||||
|
|
@ -316,7 +323,8 @@ int rtnl_dump_filter_l(struct rtnl_handle *rth,
|
||||||
break; /* process next filter */
|
break; /* process next filter */
|
||||||
}
|
}
|
||||||
if (h->nlmsg_type == NLMSG_ERROR) {
|
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))) {
|
if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"ERROR truncated\n");
|
"ERROR truncated\n");
|
||||||
|
|
@ -377,11 +385,11 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
|
||||||
struct nlmsghdr *answer, size_t maxlen)
|
struct nlmsghdr *answer, size_t maxlen)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
unsigned seq;
|
unsigned int seq;
|
||||||
struct nlmsghdr *h;
|
struct nlmsghdr *h;
|
||||||
struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
|
struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
|
||||||
struct iovec iov = {
|
struct iovec iov = {
|
||||||
.iov_base = (void*) n,
|
.iov_base = n,
|
||||||
.iov_len = n->nlmsg_len
|
.iov_len = n->nlmsg_len
|
||||||
};
|
};
|
||||||
struct msghdr msg = {
|
struct msghdr msg = {
|
||||||
|
|
@ -420,19 +428,23 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (msg.msg_namelen != sizeof(nladdr)) {
|
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);
|
exit(1);
|
||||||
}
|
}
|
||||||
for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
|
for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
|
||||||
int len = h->nlmsg_len;
|
int len = h->nlmsg_len;
|
||||||
int l = len - sizeof(*h);
|
int l = len - sizeof(*h);
|
||||||
|
|
||||||
if (l < 0 || len>status) {
|
if (l < 0 || len > status) {
|
||||||
if (msg.msg_flags & MSG_TRUNC) {
|
if (msg.msg_flags & MSG_TRUNC) {
|
||||||
fprintf(stderr, "Truncated message\n");
|
fprintf(stderr, "Truncated message\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
fprintf(stderr, "!!!malformed message: len=%d\n", len);
|
fprintf(stderr,
|
||||||
|
"!!!malformed message: len=%d\n",
|
||||||
|
len);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -441,12 +453,13 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
|
||||||
h->nlmsg_seq != seq) {
|
h->nlmsg_seq != seq) {
|
||||||
/* Don't forget to skip that message. */
|
/* Don't forget to skip that message. */
|
||||||
status -= NLMSG_ALIGN(len);
|
status -= NLMSG_ALIGN(len);
|
||||||
h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
|
h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h->nlmsg_type == NLMSG_ERROR) {
|
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)) {
|
if (l < sizeof(struct nlmsgerr)) {
|
||||||
fprintf(stderr, "ERROR truncated\n");
|
fprintf(stderr, "ERROR truncated\n");
|
||||||
} else if (!err->error) {
|
} else if (!err->error) {
|
||||||
|
|
@ -473,7 +486,7 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
|
||||||
fprintf(stderr, "Unexpected reply!!!\n");
|
fprintf(stderr, "Unexpected reply!!!\n");
|
||||||
|
|
||||||
status -= NLMSG_ALIGN(len);
|
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) {
|
if (msg.msg_flags & MSG_TRUNC) {
|
||||||
|
|
@ -545,7 +558,9 @@ int rtnl_listen(struct rtnl_handle *rtnl,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (msg.msg_namelen != sizeof(nladdr)) {
|
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);
|
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 err;
|
||||||
int len = h->nlmsg_len;
|
int len = h->nlmsg_len;
|
||||||
int l = len - sizeof(*h);
|
int l = len - sizeof(*h);
|
||||||
|
|
||||||
if (l<0 || len>status) {
|
if (l < 0 || len > status) {
|
||||||
if (msg.msg_flags & MSG_TRUNC) {
|
if (msg.msg_flags & MSG_TRUNC) {
|
||||||
fprintf(stderr, "Truncated message\n");
|
fprintf(stderr, "Truncated message\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
fprintf(stderr, "!!!malformed message: len=%d\n", len);
|
fprintf(stderr,
|
||||||
|
"!!!malformed message: len=%d\n",
|
||||||
|
len);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -582,7 +599,7 @@ int rtnl_listen(struct rtnl_handle *rtnl,
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
status -= NLMSG_ALIGN(len);
|
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) {
|
if (msg.msg_flags & MSG_TRUNC) {
|
||||||
fprintf(stderr, "Message truncated\n");
|
fprintf(stderr, "Message truncated\n");
|
||||||
|
|
@ -600,8 +617,8 @@ int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler,
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
|
struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
|
||||||
char buf[16384];
|
char buf[16384];
|
||||||
struct nlmsghdr *h = (void*)buf;
|
struct nlmsghdr *h = (struct nlmsghdr *)buf;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int err, len;
|
int err, len;
|
||||||
|
|
@ -621,7 +638,7 @@ int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler,
|
||||||
len = h->nlmsg_len;
|
len = h->nlmsg_len;
|
||||||
l = len - sizeof(*h);
|
l = len - sizeof(*h);
|
||||||
|
|
||||||
if (l<0 || len>sizeof(buf)) {
|
if (l < 0 || len > sizeof(buf)) {
|
||||||
fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
|
fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
|
||||||
len, ftell(rtnl));
|
len, ftell(rtnl));
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -681,7 +698,9 @@ int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
|
||||||
struct rtattr *rta;
|
struct rtattr *rta;
|
||||||
|
|
||||||
if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
rta = NLMSG_TAIL(n);
|
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)
|
int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
|
||||||
{
|
{
|
||||||
if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -744,10 +765,12 @@ int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
|
||||||
struct rtattr *subrta;
|
struct rtattr *subrta;
|
||||||
|
|
||||||
if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
|
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;
|
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_type = type;
|
||||||
subrta->rta_len = len;
|
subrta->rta_len = len;
|
||||||
memcpy(RTA_DATA(subrta), &data, 4);
|
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);
|
int len = RTA_LENGTH(alen);
|
||||||
|
|
||||||
if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) {
|
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;
|
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_type = type;
|
||||||
subrta->rta_len = len;
|
subrta->rta_len = len;
|
||||||
memcpy(RTA_DATA(subrta), data, alen);
|
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;
|
type = rta->rta_type & ~flags;
|
||||||
if ((type <= max) && (!tb[type]))
|
if ((type <= max) && (!tb[type]))
|
||||||
tb[type] = rta;
|
tb[type] = rta;
|
||||||
rta = RTA_NEXT(rta,len);
|
rta = RTA_NEXT(rta, len);
|
||||||
}
|
}
|
||||||
if (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;
|
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;
|
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)) {
|
while (RTA_OK(rta, len)) {
|
||||||
if (rta->rta_type <= max && i < max)
|
if (rta->rta_type <= max && i < max)
|
||||||
tb[i++] = rta;
|
tb[i++] = rta;
|
||||||
rta = RTA_NEXT(rta,len);
|
rta = RTA_NEXT(rta, len);
|
||||||
}
|
}
|
||||||
if (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;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -848,13 +876,16 @@ struct rtattr *parse_rtattr_one(int type, struct rtattr *rta, int len)
|
||||||
return rta;
|
return rta;
|
||||||
rta = RTA_NEXT(rta, len);
|
rta = RTA_NEXT(rta, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta,
|
int __parse_rtattr_nested_compat(struct rtattr *tb[], int max,
|
||||||
int len)
|
struct rtattr *rta,
|
||||||
|
int len)
|
||||||
{
|
{
|
||||||
if (RTA_PAYLOAD(rta) < len)
|
if (RTA_PAYLOAD(rta) < len)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
||||||
|
|
@ -100,11 +100,13 @@ __PF(IEEE80211,ieee802.11)
|
||||||
__PF(IEEE80211_PRISM,ieee802.11/prism)
|
__PF(IEEE80211_PRISM,ieee802.11/prism)
|
||||||
__PF(IEEE80211_RADIOTAP,ieee802.11/radiotap)
|
__PF(IEEE80211_RADIOTAP,ieee802.11/radiotap)
|
||||||
__PF(IEEE802154, ieee802.15.4)
|
__PF(IEEE802154, ieee802.15.4)
|
||||||
|
__PF(IEEE802154_MONITOR, ieee802.15.4/monitor)
|
||||||
__PF(PHONET, phonet)
|
__PF(PHONET, phonet)
|
||||||
__PF(PHONET_PIPE, phonet_pipe)
|
__PF(PHONET_PIPE, phonet_pipe)
|
||||||
__PF(CAIF, caif)
|
__PF(CAIF, caif)
|
||||||
__PF(IP6GRE, gre6)
|
__PF(IP6GRE, gre6)
|
||||||
__PF(NETLINK, netlink)
|
__PF(NETLINK, netlink)
|
||||||
|
__PF(6LOWPAN, 6lowpan)
|
||||||
|
|
||||||
__PF(NONE, none)
|
__PF(NONE, none)
|
||||||
__PF(VOID,void)
|
__PF(VOID,void)
|
||||||
|
|
|
||||||
|
|
@ -559,8 +559,12 @@ const char *rtnl_group_n2a(int id, char *buf, int len)
|
||||||
|
|
||||||
for (i = 0; i < 256; i++) {
|
for (i = 0; i < 256; i++) {
|
||||||
entry = rtnl_group_hash[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);
|
snprintf(buf, len, "%d", id);
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,9 @@ devlink-dev \- devlink device configuration
|
||||||
.RI "[ "
|
.RI "[ "
|
||||||
.BR mode " { " legacy " | " switchdev " } "
|
.BR mode " { " legacy " | " switchdev " } "
|
||||||
.RI "]"
|
.RI "]"
|
||||||
|
.RI "[ "
|
||||||
|
.BR inline-mode " { " none " | " link " | " network " | " transport " } "
|
||||||
|
.RI "]"
|
||||||
|
|
||||||
.ti -8
|
.ti -8
|
||||||
.BR "devlink dev eswitch show"
|
.BR "devlink dev eswitch show"
|
||||||
|
|
@ -54,7 +57,7 @@ BUS_NAME/BUS_ADDRESS
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR mode " { " legacy " | " switchdev " } "
|
.BR mode " { " legacy " | " switchdev " } "
|
||||||
set eswitch mode
|
Set eswitch mode
|
||||||
|
|
||||||
.I legacy
|
.I legacy
|
||||||
- Legacy SRIOV
|
- Legacy SRIOV
|
||||||
|
|
@ -62,6 +65,22 @@ set eswitch mode
|
||||||
.I switchdev
|
.I switchdev
|
||||||
- SRIOV switchdev offloads
|
- 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"
|
.SH "EXAMPLES"
|
||||||
.PP
|
.PP
|
||||||
devlink dev show
|
devlink dev show
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,12 @@ ip-l2tp - L2TPv3 static unmanaged tunnel configuration
|
||||||
.IR PORT
|
.IR PORT
|
||||||
.RB " ]"
|
.RB " ]"
|
||||||
.br
|
.br
|
||||||
|
.RB "[ " udp_csum " { " on " | " off " } ]"
|
||||||
|
.br
|
||||||
|
.RB "[ " udp6_csum_tx " { " on " | " off " } ]"
|
||||||
|
.br
|
||||||
|
.RB "[ " udp6_csum_rx " { " on " | " off " } ]"
|
||||||
|
.br
|
||||||
.ti -8
|
.ti -8
|
||||||
.BR "ip l2tp add session"
|
.BR "ip l2tp add session"
|
||||||
.RB "[ " name
|
.RB "[ " name
|
||||||
|
|
@ -51,6 +57,8 @@ ip-l2tp - L2TPv3 static unmanaged tunnel configuration
|
||||||
.br
|
.br
|
||||||
.RB "[ " l2spec_type " { " none " | " default " } ]"
|
.RB "[ " l2spec_type " { " none " | " default " } ]"
|
||||||
.br
|
.br
|
||||||
|
.RB "[ " seq " { " none " | " send " | " recv " | " both " } ]"
|
||||||
|
.br
|
||||||
.RB "[ " offset
|
.RB "[ " offset
|
||||||
.IR OFFSET
|
.IR OFFSET
|
||||||
.RB " ] [ " peer_offset
|
.RB " ] [ " peer_offset
|
||||||
|
|
@ -154,9 +162,6 @@ tunnels and sessions to be established and provides for detecting and
|
||||||
acting upon network failures.
|
acting upon network failures.
|
||||||
.SS ip l2tp add tunnel - add a new tunnel
|
.SS ip l2tp add tunnel - add a new tunnel
|
||||||
.TP
|
.TP
|
||||||
.BI name " NAME "
|
|
||||||
sets the session network interface name. Default is l2tpethN.
|
|
||||||
.TP
|
|
||||||
.BI tunnel_id " ID"
|
.BI tunnel_id " ID"
|
||||||
set the tunnel id, which is a 32-bit integer value. Uniquely
|
set the tunnel id, which is a 32-bit integer value. Uniquely
|
||||||
identifies the tunnel. The value used must match the peer_tunnel_id
|
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
|
set the UDP destination port to be used for the tunnel. Must be
|
||||||
present when udp encapsulation is selected. Ignored when ip
|
present when udp encapsulation is selected. Ignored when ip
|
||||||
encapsulation is selected.
|
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
|
.SS ip l2tp del tunnel - destroy a tunnel
|
||||||
.TP
|
.TP
|
||||||
.BI tunnel_id " ID"
|
.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.
|
set the layer2specific header type of the session.
|
||||||
.br
|
.br
|
||||||
Valid values are:
|
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
|
.TP
|
||||||
.BI offset " OFFSET"
|
.BI offset " OFFSET"
|
||||||
sets the byte offset from the L2TP header where user data starts in
|
sets the byte offset from the L2TP header where user data starts in
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,12 @@ ip-link \- network device configuration
|
||||||
.IR NAME " ]"
|
.IR NAME " ]"
|
||||||
.br
|
.br
|
||||||
.RB "[ " addrgenmode " { " eui64 " | " none " | " stable_secret " | " random " } ]"
|
.RB "[ " addrgenmode " { " eui64 " | " none " | " stable_secret " | " random " } ]"
|
||||||
|
.br
|
||||||
|
.RB "[ " macaddr " { " flush " | { " add " | " del " } "
|
||||||
|
.IR MACADDR " | set [ "
|
||||||
|
.IR MACADDR " [ "
|
||||||
|
.IR MACADDR " [ ... ] ] ] } ]"
|
||||||
|
.br
|
||||||
|
|
||||||
.ti -8
|
.ti -8
|
||||||
.B ip link show
|
.B ip link show
|
||||||
|
|
@ -882,7 +887,7 @@ the following additional arguments are supported:
|
||||||
.BI "ip link add link " DEVICE " name " NAME
|
.BI "ip link add link " DEVICE " name " NAME
|
||||||
.BR type " { " macvlan " | " macvtap " } "
|
.BR type " { " macvlan " | " macvtap " } "
|
||||||
.BR mode " { " private " | " vepa " | " bridge " | " passthru
|
.BR mode " { " private " | " vepa " | " bridge " | " passthru
|
||||||
.RB " [ " nopromisc " ] } "
|
.RB " [ " nopromisc " ] | " source " } "
|
||||||
|
|
||||||
.in +8
|
.in +8
|
||||||
.sp
|
.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
|
forces the underlying interface into promiscuous mode. Passing the
|
||||||
.BR nopromisc " flag prevents this, so the promisc flag may be controlled "
|
.BR nopromisc " flag prevents this, so the promisc flag may be controlled "
|
||||||
using standard tools.
|
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
|
.in -8
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
|
|
@ -1468,6 +1480,32 @@ the following additional arguments are supported:
|
||||||
|
|
||||||
.in -8
|
.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
|
.SS ip link show - display device attributes
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,9 @@ Display RAW sockets.
|
||||||
.B \-x, \-\-unix
|
.B \-x, \-\-unix
|
||||||
Display Unix domain sockets (alias for -f unix).
|
Display Unix domain sockets (alias for -f unix).
|
||||||
.TP
|
.TP
|
||||||
|
.B \-S, \-\-sctp
|
||||||
|
Display SCTP sockets.
|
||||||
|
.TP
|
||||||
.B \-f FAMILY, \-\-family=FAMILY
|
.B \-f FAMILY, \-\-family=FAMILY
|
||||||
Display sockets of type FAMILY.
|
Display sockets of type FAMILY.
|
||||||
Currently the following families are supported: unix, inet, inet6, link, netlink.
|
Currently the following families are supported: unix, inet, inet6, link, netlink.
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@ flower \- flow based traffic control filter
|
||||||
.R " | { "
|
.R " | { "
|
||||||
.BR dst_mac " | " src_mac " } "
|
.BR dst_mac " | " src_mac " } "
|
||||||
.IR mac_address " | "
|
.IR mac_address " | "
|
||||||
.BR eth_type " { " ipv4 " | " ipv6 " | " 802.1Q " | "
|
|
||||||
.IR ETH_TYPE " } | "
|
|
||||||
.B vlan_id
|
.B vlan_id
|
||||||
.IR VID " | "
|
.IR VID " | "
|
||||||
.B vlan_prio
|
.B vlan_prio
|
||||||
|
|
@ -75,13 +73,6 @@ Do not process filter by hardware.
|
||||||
.BI src_mac " mac_address"
|
.BI src_mac " mac_address"
|
||||||
Match on source or destination MAC address.
|
Match on source or destination MAC address.
|
||||||
.TP
|
.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"
|
.BI vlan_id " VID"
|
||||||
Match on vlan tag id.
|
Match on vlan tag id.
|
||||||
.I VID
|
.I VID
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ class-id ] qdisc
|
||||||
|
|
||||||
.B tc
|
.B tc
|
||||||
.RI "[ " OPTIONS " ]"
|
.RI "[ " OPTIONS " ]"
|
||||||
.B filter [ add | change | replace | delete ] dev
|
.B filter [ add | change | replace | delete | get ] dev
|
||||||
DEV
|
DEV
|
||||||
.B [ parent
|
.B [ parent
|
||||||
qdisc-id
|
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
|
Performs a nearly atomic remove/add on an existing node id. If the node does not exist yet
|
||||||
it is created.
|
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
|
.TP
|
||||||
link
|
link
|
||||||
Only available for qdiscs and performs a replace where the node
|
Only available for qdiscs and performs a replace where the node
|
||||||
|
|
|
||||||
|
|
@ -662,18 +662,18 @@ static void usage(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Usage: ifstat [OPTION] [ PATTERN [ PATTERN ] ]\n"
|
"Usage: ifstat [OPTION] [ PATTERN [ PATTERN ] ]\n"
|
||||||
" -h, --help this message\n"
|
" -h, --help this message\n"
|
||||||
" -a, --ignore ignore history\n"
|
" -a, --ignore ignore history\n"
|
||||||
" -d, --scan=SECS sample every statistics every SECS\n"
|
" -d, --scan=SECS sample every statistics every SECS\n"
|
||||||
" -e, --errors show errors\n"
|
" -e, --errors show errors\n"
|
||||||
" -j, --json format output in JSON\n"
|
" -j, --json format output in JSON\n"
|
||||||
" -n, --nooutput do history only\n"
|
" -n, --nooutput do history only\n"
|
||||||
" -p, --pretty pretty print\n"
|
" -p, --pretty pretty print\n"
|
||||||
" -r, --reset reset history\n"
|
" -r, --reset reset history\n"
|
||||||
" -s, --noupdate don\'t update history\n"
|
" -s, --noupdate don't update history\n"
|
||||||
" -t, --interval=SECS report average over the last SECS\n"
|
" -t, --interval=SECS report average over the last SECS\n"
|
||||||
" -V, --version output version information\n"
|
" -V, --version output version information\n"
|
||||||
" -z, --zeros show entries with zero activity\n");
|
" -z, --zeros show entries with zero activity\n");
|
||||||
|
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
22
misc/nstat.c
22
misc/nstat.c
|
|
@ -526,17 +526,17 @@ static void usage(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Usage: nstat [OPTION] [ PATTERN [ PATTERN ] ]\n"
|
"Usage: nstat [OPTION] [ PATTERN [ PATTERN ] ]\n"
|
||||||
" -h, --help this message\n"
|
" -h, --help this message\n"
|
||||||
" -a, --ignore ignore history\n"
|
" -a, --ignore ignore history\n"
|
||||||
" -d, --scan=SECS sample every statistics every SECS\n"
|
" -d, --scan=SECS sample every statistics every SECS\n"
|
||||||
" -j, --json format output in JSON\n"
|
" -j, --json format output in JSON\n"
|
||||||
" -n, --nooutput do history only\n"
|
" -n, --nooutput do history only\n"
|
||||||
" -p, --pretty pretty print\n"
|
" -p, --pretty pretty print\n"
|
||||||
" -r, --reset reset history\n"
|
" -r, --reset reset history\n"
|
||||||
" -s, --noupdate don\'t update history\n"
|
" -s, --noupdate don't update history\n"
|
||||||
" -t, --interval=SECS report average over the last SECS\n"
|
" -t, --interval=SECS report average over the last SECS\n"
|
||||||
" -V, --version output version information\n"
|
" -V, --version output version information\n"
|
||||||
" -z, --zeros show entries with zero activity\n");
|
" -z, --zeros show entries with zero activity\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
219
misc/ss.c
219
misc/ss.c
|
|
@ -43,6 +43,7 @@
|
||||||
#include <linux/filter.h>
|
#include <linux/filter.h>
|
||||||
#include <linux/packet_diag.h>
|
#include <linux/packet_diag.h>
|
||||||
#include <linux/netlink_diag.h>
|
#include <linux/netlink_diag.h>
|
||||||
|
#include <linux/sctp.h>
|
||||||
|
|
||||||
#define MAGIC_SEQ 123456
|
#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 */
|
/* If show_users & show_proc_ctx only do user_ent_hash_build() once */
|
||||||
int user_ent_hash_build_init;
|
int user_ent_hash_build_init;
|
||||||
int follow_events;
|
int follow_events;
|
||||||
|
int sctp_ino;
|
||||||
|
|
||||||
int netid_width;
|
int netid_width;
|
||||||
int state_width;
|
int state_width;
|
||||||
|
|
@ -111,6 +113,7 @@ int serv_width;
|
||||||
int screen_width;
|
int screen_width;
|
||||||
|
|
||||||
static const char *TCP_PROTO = "tcp";
|
static const char *TCP_PROTO = "tcp";
|
||||||
|
static const char *SCTP_PROTO = "sctp";
|
||||||
static const char *UDP_PROTO = "udp";
|
static const char *UDP_PROTO = "udp";
|
||||||
static const char *RAW_PROTO = "raw";
|
static const char *RAW_PROTO = "raw";
|
||||||
static const char *dg_proto;
|
static const char *dg_proto;
|
||||||
|
|
@ -126,13 +129,15 @@ enum {
|
||||||
PACKET_DG_DB,
|
PACKET_DG_DB,
|
||||||
PACKET_R_DB,
|
PACKET_R_DB,
|
||||||
NETLINK_DB,
|
NETLINK_DB,
|
||||||
|
SCTP_DB,
|
||||||
MAX_DB
|
MAX_DB
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PACKET_DBM ((1<<PACKET_DG_DB)|(1<<PACKET_R_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 UNIX_DBM ((1<<UNIX_DG_DB)|(1<<UNIX_ST_DB)|(1<<UNIX_SQ_DB))
|
||||||
#define ALL_DB ((1<<MAX_DB)-1)
|
#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 {
|
enum {
|
||||||
SS_UNKNOWN,
|
SS_UNKNOWN,
|
||||||
|
|
@ -150,6 +155,17 @@ enum {
|
||||||
SS_MAX
|
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_ALL ((1 << SS_MAX) - 1)
|
||||||
#define SS_CONN (SS_ALL & ~((1<<SS_LISTEN)|(1<<SS_CLOSE)|(1<<SS_TIME_WAIT)|(1<<SS_SYN_RECV)))
|
#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),
|
.states = (1 << SS_CLOSE),
|
||||||
.families = (1 << AF_NETLINK),
|
.families = (1 << AF_NETLINK),
|
||||||
},
|
},
|
||||||
|
[SCTP_DB] = {
|
||||||
|
.states = SS_CONN,
|
||||||
|
.families = (1 << AF_INET) | (1 << AF_INET6),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct filter default_afs[AF_MAX] = {
|
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_R_DB);
|
||||||
filter_db_set(f, PACKET_DG_DB);
|
filter_db_set(f, PACKET_DG_DB);
|
||||||
filter_db_set(f, NETLINK_DB);
|
filter_db_set(f, NETLINK_DB);
|
||||||
|
filter_db_set(f, SCTP_DB);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void filter_states_set(struct filter *f, int states)
|
static void filter_states_set(struct filter *f, int states)
|
||||||
|
|
@ -705,6 +726,17 @@ static const char *sstate_name[] = {
|
||||||
[SS_CLOSING] = "CLOSING",
|
[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[] = {
|
static const char *sstate_namel[] = {
|
||||||
"UNKNOWN",
|
"UNKNOWN",
|
||||||
[SS_ESTABLISHED] = "established",
|
[SS_ESTABLISHED] = "established",
|
||||||
|
|
@ -793,12 +825,30 @@ struct tcpstat {
|
||||||
struct tcp_bbr_info *bbr_info;
|
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)
|
static void sock_state_print(struct sockstat *s, const char *sock_name)
|
||||||
{
|
{
|
||||||
if (netid_width)
|
if (netid_width)
|
||||||
printf("%-*s ", netid_width, sock_name);
|
printf("%-*s ", netid_width,
|
||||||
if (state_width)
|
is_sctp_assoc(s, sock_name) ? "" : sock_name);
|
||||||
printf("%-*s ", state_width, sstate_name[s->state]);
|
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);
|
printf("%-6d %-6d ", s->rq, s->wq);
|
||||||
}
|
}
|
||||||
|
|
@ -908,6 +958,8 @@ static void init_service_resolver(void)
|
||||||
c->proto = TCP_PROTO;
|
c->proto = TCP_PROTO;
|
||||||
else if (strcmp(proto, UDP_PROTO) == 0)
|
else if (strcmp(proto, UDP_PROTO) == 0)
|
||||||
c->proto = UDP_PROTO;
|
c->proto = UDP_PROTO;
|
||||||
|
else if (strcmp(proto, SCTP_PROTO) == 0)
|
||||||
|
c->proto = SCTP_PROTO;
|
||||||
else
|
else
|
||||||
c->proto = NULL;
|
c->proto = NULL;
|
||||||
c->next = rlist;
|
c->next = rlist;
|
||||||
|
|
@ -1679,6 +1731,8 @@ static char *proto_name(int protocol)
|
||||||
return "udp";
|
return "udp";
|
||||||
case IPPROTO_TCP:
|
case IPPROTO_TCP:
|
||||||
return "tcp";
|
return "tcp";
|
||||||
|
case IPPROTO_SCTP:
|
||||||
|
return "sctp";
|
||||||
case IPPROTO_DCCP:
|
case IPPROTO_DCCP:
|
||||||
return "dccp";
|
return "dccp";
|
||||||
}
|
}
|
||||||
|
|
@ -1771,6 +1825,56 @@ static char *sprint_bw(char *buf, double bw)
|
||||||
return buf;
|
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)
|
static void tcp_stats_print(struct tcpstat *s)
|
||||||
{
|
{
|
||||||
char b1[64];
|
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)
|
static int tcp_show_line(char *line, const struct filter *f, int family)
|
||||||
{
|
{
|
||||||
int rto = 0, ato = 0;
|
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)
|
static void parse_diag_msg(struct nlmsghdr *nlh, struct sockstat *s)
|
||||||
{
|
{
|
||||||
struct rtattr *tb[INET_DIAG_MAX+1];
|
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.timer = r->idiag_timer;
|
||||||
t.timeout = r->idiag_expires;
|
t.timeout = r->idiag_expires;
|
||||||
t.retrans = r->idiag_retrans;
|
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) {
|
if (show_details) {
|
||||||
|
|
@ -2242,8 +2414,12 @@ static int inet_show_sock(struct nlmsghdr *nlh,
|
||||||
|
|
||||||
if (show_mem || show_tcpinfo) {
|
if (show_mem || show_tcpinfo) {
|
||||||
printf("\n\t");
|
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");
|
printf("\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -2627,6 +2803,17 @@ outerr:
|
||||||
} while (0);
|
} 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)
|
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);
|
memcpy(name, RTA_DATA(tb[UNIX_DIAG_NAME]), len);
|
||||||
name[len] = '\0';
|
name[len] = '\0';
|
||||||
if (name[0] == '\0')
|
if (name[0] == '\0')
|
||||||
name[0] = '@';
|
for (int i = 0; i < len; i++)
|
||||||
|
if (name[i] == '\0')
|
||||||
|
name[i] = '@';
|
||||||
stat.name = &name[0];
|
stat.name = &name[0];
|
||||||
memcpy(stat.local.data, &stat.name, sizeof(stat.name));
|
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"
|
" -6, --ipv6 display only IP version 6 sockets\n"
|
||||||
" -0, --packet display PACKET sockets\n"
|
" -0, --packet display PACKET sockets\n"
|
||||||
" -t, --tcp display only TCP sockets\n"
|
" -t, --tcp display only TCP sockets\n"
|
||||||
|
" -S, --sctp display only SCTP sockets\n"
|
||||||
" -u, --udp display only UDP sockets\n"
|
" -u, --udp display only UDP sockets\n"
|
||||||
" -d, --dccp display only DCCP sockets\n"
|
" -d, --dccp display only DCCP sockets\n"
|
||||||
" -w, --raw display only RAW sockets\n"
|
" -w, --raw display only RAW sockets\n"
|
||||||
|
|
@ -3820,6 +4010,7 @@ static const struct option long_opts[] = {
|
||||||
{ "events", 0, 0, 'E' },
|
{ "events", 0, 0, 'E' },
|
||||||
{ "dccp", 0, 0, 'd' },
|
{ "dccp", 0, 0, 'd' },
|
||||||
{ "tcp", 0, 0, 't' },
|
{ "tcp", 0, 0, 't' },
|
||||||
|
{ "sctp", 0, 0, 'S' },
|
||||||
{ "udp", 0, 0, 'u' },
|
{ "udp", 0, 0, 'u' },
|
||||||
{ "raw", 0, 0, 'w' },
|
{ "raw", 0, 0, 'w' },
|
||||||
{ "unix", 0, 0, 'x' },
|
{ "unix", 0, 0, 'x' },
|
||||||
|
|
@ -3855,7 +4046,8 @@ int main(int argc, char *argv[])
|
||||||
int ch;
|
int ch;
|
||||||
int state_filter = 0;
|
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) {
|
long_opts, NULL)) != EOF) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'n':
|
case 'n':
|
||||||
|
|
@ -3894,6 +4086,9 @@ int main(int argc, char *argv[])
|
||||||
case 't':
|
case 't':
|
||||||
filter_db_set(¤t_filter, TCP_DB);
|
filter_db_set(¤t_filter, TCP_DB);
|
||||||
break;
|
break;
|
||||||
|
case 'S':
|
||||||
|
filter_db_set(¤t_filter, SCTP_DB);
|
||||||
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
filter_db_set(¤t_filter, UDP_DB);
|
filter_db_set(¤t_filter, UDP_DB);
|
||||||
break;
|
break;
|
||||||
|
|
@ -3958,6 +4153,7 @@ int main(int argc, char *argv[])
|
||||||
filter_db_set(¤t_filter, UDP_DB);
|
filter_db_set(¤t_filter, UDP_DB);
|
||||||
filter_db_set(¤t_filter, DCCP_DB);
|
filter_db_set(¤t_filter, DCCP_DB);
|
||||||
filter_db_set(¤t_filter, TCP_DB);
|
filter_db_set(¤t_filter, TCP_DB);
|
||||||
|
filter_db_set(¤t_filter, SCTP_DB);
|
||||||
filter_db_set(¤t_filter, RAW_DB);
|
filter_db_set(¤t_filter, RAW_DB);
|
||||||
} else if (strcmp(p, "udp") == 0) {
|
} else if (strcmp(p, "udp") == 0) {
|
||||||
filter_db_set(¤t_filter, UDP_DB);
|
filter_db_set(¤t_filter, UDP_DB);
|
||||||
|
|
@ -3965,6 +4161,8 @@ int main(int argc, char *argv[])
|
||||||
filter_db_set(¤t_filter, DCCP_DB);
|
filter_db_set(¤t_filter, DCCP_DB);
|
||||||
} else if (strcmp(p, "tcp") == 0) {
|
} else if (strcmp(p, "tcp") == 0) {
|
||||||
filter_db_set(¤t_filter, TCP_DB);
|
filter_db_set(¤t_filter, TCP_DB);
|
||||||
|
} else if (strcmp(p, "sctp") == 0) {
|
||||||
|
filter_db_set(¤t_filter, SCTP_DB);
|
||||||
} else if (strcmp(p, "raw") == 0) {
|
} else if (strcmp(p, "raw") == 0) {
|
||||||
filter_db_set(¤t_filter, RAW_DB);
|
filter_db_set(¤t_filter, RAW_DB);
|
||||||
} else if (strcmp(p, "unix") == 0) {
|
} else if (strcmp(p, "unix") == 0) {
|
||||||
|
|
@ -4089,10 +4287,9 @@ int main(int argc, char *argv[])
|
||||||
filter_merge_defaults(¤t_filter);
|
filter_merge_defaults(¤t_filter);
|
||||||
|
|
||||||
if (resolve_services && resolve_hosts &&
|
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();
|
init_service_resolver();
|
||||||
|
|
||||||
|
|
||||||
if (current_filter.dbs == 0) {
|
if (current_filter.dbs == 0) {
|
||||||
fprintf(stderr, "ss: no socket tables to show with such filter.\n");
|
fprintf(stderr, "ss: no socket tables to show with such filter.\n");
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
@ -4205,6 +4402,8 @@ int main(int argc, char *argv[])
|
||||||
tcp_show(¤t_filter, IPPROTO_TCP);
|
tcp_show(¤t_filter, IPPROTO_TCP);
|
||||||
if (current_filter.dbs & (1<<DCCP_DB))
|
if (current_filter.dbs & (1<<DCCP_DB))
|
||||||
tcp_show(¤t_filter, IPPROTO_DCCP);
|
tcp_show(¤t_filter, IPPROTO_DCCP);
|
||||||
|
if (current_filter.dbs & (1<<SCTP_DB))
|
||||||
|
sctp_show(¤t_filter);
|
||||||
|
|
||||||
if (show_users || show_proc_ctx || show_sock_ctx)
|
if (show_users || show_proc_ctx || show_sock_ctx)
|
||||||
user_ent_destroy();
|
user_ent_destroy();
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@ static void explain(void)
|
||||||
" vlan_ethtype [ ipv4 | ipv6 | ETH-TYPE ] |\n"
|
" vlan_ethtype [ ipv4 | ipv6 | ETH-TYPE ] |\n"
|
||||||
" dst_mac MAC-ADDR |\n"
|
" dst_mac MAC-ADDR |\n"
|
||||||
" src_mac MAC-ADDR |\n"
|
" src_mac MAC-ADDR |\n"
|
||||||
" [ipv4 | ipv6 ] |\n"
|
|
||||||
" ip_proto [tcp | udp | IP-PROTO ] |\n"
|
" ip_proto [tcp | udp | IP-PROTO ] |\n"
|
||||||
" dst_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
|
" dst_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
|
||||||
" src_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"
|
" FILTERID := X:Y:Z\n"
|
||||||
" ACTION-SPEC := ... look at individual actions\n"
|
" ACTION-SPEC := ... look at individual actions\n"
|
||||||
"\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"
|
"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");
|
" to specify different mask, he has to use different prio.\n");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
17
tc/f_fw.c
17
tc/f_fw.c
|
|
@ -25,10 +25,19 @@
|
||||||
|
|
||||||
static void explain(void)
|
static void explain(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: ... fw [ classid CLASSID ] [ action ACTION_SPEC ]\n");
|
fprintf(stderr,
|
||||||
fprintf(stderr, " ACTION_SPEC := ... look at individual actions\n");
|
"Usage: ... fw [ classid CLASSID ] [ indev DEV ] [ action ACTION_SPEC ]\n");
|
||||||
fprintf(stderr, " CLASSID := X:Y\n");
|
fprintf(stderr,
|
||||||
fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
|
" 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)
|
static int fw_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n)
|
||||||
|
|
|
||||||
|
|
@ -226,6 +226,16 @@ int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
|
||||||
if (n->nlmsg_type == RTM_DELTFILTER)
|
if (n->nlmsg_type == RTM_DELTFILTER)
|
||||||
fprintf(fp, "deleted ");
|
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 ");
|
fprintf(fp, "filter ");
|
||||||
if (!filter_ifindex || filter_ifindex != t->tcm_ifindex)
|
if (!filter_ifindex || filter_ifindex != t->tcm_ifindex)
|
||||||
fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex));
|
fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex));
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,8 @@ static int tc_qdisc_modify(int cmd, unsigned int flags, int argc, char **argv)
|
||||||
|
|
||||||
ll_init_map(&rth);
|
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);
|
fprintf(stderr, "Cannot find device \"%s\"\n", d);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -198,8 +199,7 @@ static int tc_qdisc_modify(int cmd, unsigned int flags, int argc, char **argv)
|
||||||
static int filter_ifindex;
|
static int filter_ifindex;
|
||||||
|
|
||||||
int print_qdisc(const struct sockaddr_nl *who,
|
int print_qdisc(const struct sockaddr_nl *who,
|
||||||
struct nlmsghdr *n,
|
struct nlmsghdr *n, void *arg)
|
||||||
void *arg)
|
|
||||||
{
|
{
|
||||||
FILE *fp = (FILE *)arg;
|
FILE *fp = (FILE *)arg;
|
||||||
struct tcmsg *t = NLMSG_DATA(n);
|
struct tcmsg *t = NLMSG_DATA(n);
|
||||||
|
|
@ -231,21 +231,29 @@ int print_qdisc(const struct sockaddr_nl *who,
|
||||||
if (n->nlmsg_type == RTM_DELQDISC)
|
if (n->nlmsg_type == RTM_DELQDISC)
|
||||||
fprintf(fp, "deleted ");
|
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)
|
if (filter_ifindex == 0)
|
||||||
fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex));
|
fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex));
|
||||||
|
|
||||||
if (t->tcm_parent == TC_H_ROOT)
|
if (t->tcm_parent == TC_H_ROOT)
|
||||||
fprintf(fp, "root ");
|
fprintf(fp, "root ");
|
||||||
else if (t->tcm_parent) {
|
else if (t->tcm_parent) {
|
||||||
print_tc_classid(abuf, sizeof(abuf), t->tcm_parent);
|
print_tc_classid(abuf, sizeof(abuf), t->tcm_parent);
|
||||||
fprintf(fp, "parent %s ", abuf);
|
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");
|
q = get_qdisc_kind("prio");
|
||||||
else
|
else
|
||||||
q = get_qdisc_kind(RTA_DATA(tb[TCA_KIND]));
|
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, "[cannot parse qdisc parameters]");
|
||||||
}
|
}
|
||||||
fprintf(fp, "\n");
|
fprintf(fp, "\n");
|
||||||
|
|
||||||
if (show_details && tb[TCA_STAB]) {
|
if (show_details && tb[TCA_STAB]) {
|
||||||
print_size_table(fp, " ", tb[TCA_STAB]);
|
print_size_table(fp, " ", tb[TCA_STAB]);
|
||||||
fprintf(fp, "\n");
|
fprintf(fp, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (show_stats) {
|
if (show_stats) {
|
||||||
struct rtattr *xstats = NULL;
|
struct rtattr *xstats = NULL;
|
||||||
|
|
||||||
|
|
@ -289,11 +299,11 @@ static int tc_qdisc_list(int argc, char **argv)
|
||||||
strncpy(d, *argv, sizeof(d)-1);
|
strncpy(d, *argv, sizeof(d)-1);
|
||||||
} else if (strcmp(*argv, "ingress") == 0 ||
|
} else if (strcmp(*argv, "ingress") == 0 ||
|
||||||
strcmp(*argv, "clsact") == 0) {
|
strcmp(*argv, "clsact") == 0) {
|
||||||
if (t.tcm_parent) {
|
if (t.tcm_parent) {
|
||||||
fprintf(stderr, "Duplicate parent ID\n");
|
fprintf(stderr, "Duplicate parent ID\n");
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
t.tcm_parent = TC_H_INGRESS;
|
t.tcm_parent = TC_H_INGRESS;
|
||||||
} else if (matches(*argv, "help") == 0) {
|
} else if (matches(*argv, "help") == 0) {
|
||||||
usage();
|
usage();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -307,7 +317,8 @@ static int tc_qdisc_list(int argc, char **argv)
|
||||||
ll_init_map(&rth);
|
ll_init_map(&rth);
|
||||||
|
|
||||||
if (d[0]) {
|
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);
|
fprintf(stderr, "Cannot find device \"%s\"\n", d);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue