Merge ../iproute2-next
This commit is contained in:
commit
724ec5aeb0
6
Makefile
6
Makefile
|
|
@ -40,12 +40,6 @@ DEFINES+=-DCONFDIR=\"$(CONFDIR)\" \
|
||||||
-DNETNS_RUN_DIR=\"$(NETNS_RUN_DIR)\" \
|
-DNETNS_RUN_DIR=\"$(NETNS_RUN_DIR)\" \
|
||||||
-DNETNS_ETC_DIR=\"$(NETNS_ETC_DIR)\"
|
-DNETNS_ETC_DIR=\"$(NETNS_ETC_DIR)\"
|
||||||
|
|
||||||
#options for decnet
|
|
||||||
ADDLIB+=dnet_ntop.o dnet_pton.o
|
|
||||||
|
|
||||||
#options for ipx
|
|
||||||
ADDLIB+=ipx_ntop.o ipx_pton.o
|
|
||||||
|
|
||||||
#options for mpls
|
#options for mpls
|
||||||
ADDLIB+=mpls_ntop.o mpls_pton.o
|
ADDLIB+=mpls_ntop.o mpls_pton.o
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
|
|
||||||
Here are a few quick points about DECnet support...
|
|
||||||
|
|
||||||
o iproute2 is the tool of choice for configuring the DECnet support for
|
|
||||||
Linux. For many features, it is the only tool which can be used to
|
|
||||||
configure them.
|
|
||||||
|
|
||||||
o No name resolution is available as yet, all addresses must be
|
|
||||||
entered numerically.
|
|
||||||
|
|
||||||
o Remember to set the hardware address of the interface using:
|
|
||||||
|
|
||||||
ip link set ethX address xx:xx:xx:xx:xx:xx
|
|
||||||
(where xx:xx:xx:xx:xx:xx is the MAC address for your DECnet node
|
|
||||||
address)
|
|
||||||
|
|
||||||
if your Ethernet card won't listen to more than one unicast
|
|
||||||
mac address at once. If the Linux DECnet stack doesn't talk to
|
|
||||||
any other DECnet nodes, then check this with tcpdump and if its
|
|
||||||
a problem, change the mac address (but do this _before_ starting
|
|
||||||
any other network protocol on the interface)
|
|
||||||
|
|
||||||
o Whilst you can use ip addr add to add more than one DECnet address to an
|
|
||||||
interface, don't expect addresses which are not the same as the
|
|
||||||
kernels node address to work properly with 2.4 kernels. This should
|
|
||||||
be fine with 2.6 kernels as the routing code has been extensively
|
|
||||||
modified and improved.
|
|
||||||
|
|
||||||
o The DECnet support is currently self contained. It does not depend on
|
|
||||||
the libdnet library.
|
|
||||||
|
|
||||||
Steve Whitehouse <steve@chygwyn.com>
|
|
||||||
|
|
||||||
|
|
@ -9,7 +9,7 @@ In addition to routing cache statistics, it supports any kind of statistics
|
||||||
the linux kernel exports via a file in /proc/net/stat. In a stock 2.6.9
|
the linux kernel exports via a file in /proc/net/stat. In a stock 2.6.9
|
||||||
kernel, this is
|
kernel, this is
|
||||||
per-protocol neighbour cache statistics
|
per-protocol neighbour cache statistics
|
||||||
(ipv4, ipv6, atm, decnet)
|
(ipv4, ipv6, atm)
|
||||||
routing cache statistics
|
routing cache statistics
|
||||||
(ipv4)
|
(ipv4)
|
||||||
connection tracking statistics
|
connection tracking statistics
|
||||||
|
|
@ -78,4 +78,3 @@ You can specify to print a header at start and every 20 lines:
|
||||||
You can specify the number of samples you want to take (e.g. 5):
|
You can specify the number of samples you want to take (e.g. 5):
|
||||||
|
|
||||||
lnstat -c 5
|
lnstat -c 5
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -302,7 +302,7 @@ _tc_qdisc_options()
|
||||||
;;
|
;;
|
||||||
gred)
|
gred)
|
||||||
_tc_once_attr 'setup vqs default grio vq prio limit min max avpkt \
|
_tc_once_attr 'setup vqs default grio vq prio limit min max avpkt \
|
||||||
burst probability bandwidth'
|
burst probability bandwidth ecn harddrop'
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
hhf)
|
hhf)
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,8 @@ static int batch(const char *name)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rtnl_set_strict_dump(&rth);
|
||||||
|
|
||||||
cmdlineno = 0;
|
cmdlineno = 0;
|
||||||
while (getcmdline(&line, &len, stdin) != -1) {
|
while (getcmdline(&line, &len, stdin) != -1) {
|
||||||
char *largv[100];
|
char *largv[100];
|
||||||
|
|
@ -205,6 +207,8 @@ main(int argc, char **argv)
|
||||||
if (rtnl_open(&rth, 0) < 0)
|
if (rtnl_open(&rth, 0) < 0)
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
|
rtnl_set_strict_dump(&rth);
|
||||||
|
|
||||||
if (argc > 1)
|
if (argc > 1)
|
||||||
return do_cmd(argv[1], argc-1, argv+1);
|
return do_cmd(argv[1], argc-1, argv+1);
|
||||||
|
|
||||||
|
|
|
||||||
62
bridge/fdb.c
62
bridge/fdb.c
|
|
@ -30,7 +30,7 @@
|
||||||
#include "rt_names.h"
|
#include "rt_names.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
static unsigned int filter_index, filter_vlan, filter_state;
|
static unsigned int filter_index, filter_vlan, filter_state, filter_master;
|
||||||
|
|
||||||
static void usage(void)
|
static void usage(void)
|
||||||
{
|
{
|
||||||
|
|
@ -256,20 +256,49 @@ int print_fdb(struct nlmsghdr *n, void *arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int fdb_linkdump_filter(struct nlmsghdr *nlh, int reqlen)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (filter_index) {
|
||||||
|
struct ifinfomsg *ifm = NLMSG_DATA(nlh);
|
||||||
|
|
||||||
|
ifm->ifi_index = filter_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter_master) {
|
||||||
|
err = addattr32(nlh, reqlen, IFLA_MASTER, filter_master);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fdb_dump_filter(struct nlmsghdr *nlh, int reqlen)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (filter_index) {
|
||||||
|
struct ndmsg *ndm = NLMSG_DATA(nlh);
|
||||||
|
|
||||||
|
ndm->ndm_ifindex = filter_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter_master) {
|
||||||
|
err = addattr32(nlh, reqlen, NDA_MASTER, filter_master);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int fdb_show(int argc, char **argv)
|
static int fdb_show(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct {
|
|
||||||
struct nlmsghdr n;
|
|
||||||
struct ifinfomsg ifm;
|
|
||||||
char buf[256];
|
|
||||||
} req = {
|
|
||||||
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
|
|
||||||
.ifm.ifi_family = PF_BRIDGE,
|
|
||||||
};
|
|
||||||
|
|
||||||
char *filter_dev = NULL;
|
char *filter_dev = NULL;
|
||||||
char *br = NULL;
|
char *br = NULL;
|
||||||
int msg_size = sizeof(struct ifinfomsg);
|
int rc;
|
||||||
|
|
||||||
while (argc > 0) {
|
while (argc > 0) {
|
||||||
if ((strcmp(*argv, "brport") == 0) || strcmp(*argv, "dev") == 0) {
|
if ((strcmp(*argv, "brport") == 0) || strcmp(*argv, "dev") == 0) {
|
||||||
|
|
@ -304,8 +333,7 @@ static int fdb_show(int argc, char **argv)
|
||||||
fprintf(stderr, "Cannot find bridge device \"%s\"\n", br);
|
fprintf(stderr, "Cannot find bridge device \"%s\"\n", br);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
addattr32(&req.n, sizeof(req), IFLA_MASTER, br_ifindex);
|
filter_master = br_ifindex;
|
||||||
msg_size += RTA_LENGTH(4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*we'll keep around filter_dev for older kernels */
|
/*we'll keep around filter_dev for older kernels */
|
||||||
|
|
@ -313,10 +341,14 @@ static int fdb_show(int argc, char **argv)
|
||||||
filter_index = ll_name_to_index(filter_dev);
|
filter_index = ll_name_to_index(filter_dev);
|
||||||
if (!filter_index)
|
if (!filter_index)
|
||||||
return nodev(filter_dev);
|
return nodev(filter_dev);
|
||||||
req.ifm.ifi_index = filter_index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rtnl_dump_request(&rth, RTM_GETNEIGH, &req.ifm, msg_size) < 0) {
|
if (rth.flags & RTNL_HANDLE_F_STRICT_CHK)
|
||||||
|
rc = rtnl_neighdump_req(&rth, PF_BRIDGE, fdb_dump_filter);
|
||||||
|
else
|
||||||
|
rc = rtnl_linkdump_req_filter_fn(&rth, PF_BRIDGE,
|
||||||
|
fdb_linkdump_filter);
|
||||||
|
if (rc < 0) {
|
||||||
perror("Cannot send dump request");
|
perror("Cannot send dump request");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1920,10 +1920,80 @@ static int cmd_dev_eswitch(struct dl *dl)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pr_out_param_value(struct dl *dl, int nla_type, struct nlattr *nl)
|
struct param_val_conv {
|
||||||
|
const char *name;
|
||||||
|
const char *vstr;
|
||||||
|
uint32_t vuint;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool param_val_conv_exists(const struct param_val_conv *param_val_conv,
|
||||||
|
uint32_t len, const char *name)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
if (!strcmp(param_val_conv[i].name, name))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
param_val_conv_uint_get(const struct param_val_conv *param_val_conv,
|
||||||
|
uint32_t len, const char *name, const char *vstr,
|
||||||
|
uint32_t *vuint)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
if (!strcmp(param_val_conv[i].name, name) &&
|
||||||
|
!strcmp(param_val_conv[i].vstr, vstr)) {
|
||||||
|
*vuint = param_val_conv[i].vuint;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
param_val_conv_str_get(const struct param_val_conv *param_val_conv,
|
||||||
|
uint32_t len, const char *name, uint32_t vuint,
|
||||||
|
const char **vstr)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
if (!strcmp(param_val_conv[i].name, name) &&
|
||||||
|
param_val_conv[i].vuint == vuint) {
|
||||||
|
*vstr = param_val_conv[i].vstr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct param_val_conv param_val_conv[] = {
|
||||||
|
{
|
||||||
|
.name = "fw_load_policy",
|
||||||
|
.vstr = "driver",
|
||||||
|
.vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "fw_load_policy",
|
||||||
|
.vstr = "flash",
|
||||||
|
.vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PARAM_VAL_CONV_LEN ARRAY_SIZE(param_val_conv)
|
||||||
|
|
||||||
|
static void pr_out_param_value(struct dl *dl, const char *nla_name,
|
||||||
|
int nla_type, struct nlattr *nl)
|
||||||
{
|
{
|
||||||
struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
|
struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
|
||||||
struct nlattr *val_attr;
|
struct nlattr *val_attr;
|
||||||
|
const char *vstr;
|
||||||
|
bool conv_exists;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = mnl_attr_parse_nested(nl, attr_cb, nla_value);
|
err = mnl_attr_parse_nested(nl, attr_cb, nla_value);
|
||||||
|
|
@ -1939,15 +2009,51 @@ static void pr_out_param_value(struct dl *dl, int nla_type, struct nlattr *nl)
|
||||||
param_cmode_name(mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE])));
|
param_cmode_name(mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE])));
|
||||||
val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
|
val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
|
||||||
|
|
||||||
|
conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN,
|
||||||
|
nla_name);
|
||||||
|
|
||||||
switch (nla_type) {
|
switch (nla_type) {
|
||||||
case MNL_TYPE_U8:
|
case MNL_TYPE_U8:
|
||||||
pr_out_uint(dl, "value", mnl_attr_get_u8(val_attr));
|
if (conv_exists) {
|
||||||
|
err = param_val_conv_str_get(param_val_conv,
|
||||||
|
PARAM_VAL_CONV_LEN,
|
||||||
|
nla_name,
|
||||||
|
mnl_attr_get_u8(val_attr),
|
||||||
|
&vstr);
|
||||||
|
if (err)
|
||||||
|
return;
|
||||||
|
pr_out_str(dl, "value", vstr);
|
||||||
|
} else {
|
||||||
|
pr_out_uint(dl, "value", mnl_attr_get_u8(val_attr));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case MNL_TYPE_U16:
|
case MNL_TYPE_U16:
|
||||||
pr_out_uint(dl, "value", mnl_attr_get_u16(val_attr));
|
if (conv_exists) {
|
||||||
|
err = param_val_conv_str_get(param_val_conv,
|
||||||
|
PARAM_VAL_CONV_LEN,
|
||||||
|
nla_name,
|
||||||
|
mnl_attr_get_u16(val_attr),
|
||||||
|
&vstr);
|
||||||
|
if (err)
|
||||||
|
return;
|
||||||
|
pr_out_str(dl, "value", vstr);
|
||||||
|
} else {
|
||||||
|
pr_out_uint(dl, "value", mnl_attr_get_u16(val_attr));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case MNL_TYPE_U32:
|
case MNL_TYPE_U32:
|
||||||
pr_out_uint(dl, "value", mnl_attr_get_u32(val_attr));
|
if (conv_exists) {
|
||||||
|
err = param_val_conv_str_get(param_val_conv,
|
||||||
|
PARAM_VAL_CONV_LEN,
|
||||||
|
nla_name,
|
||||||
|
mnl_attr_get_u32(val_attr),
|
||||||
|
&vstr);
|
||||||
|
if (err)
|
||||||
|
return;
|
||||||
|
pr_out_str(dl, "value", vstr);
|
||||||
|
} else {
|
||||||
|
pr_out_uint(dl, "value", mnl_attr_get_u32(val_attr));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case MNL_TYPE_STRING:
|
case MNL_TYPE_STRING:
|
||||||
pr_out_str(dl, "value", mnl_attr_get_str(val_attr));
|
pr_out_str(dl, "value", mnl_attr_get_str(val_attr));
|
||||||
|
|
@ -1962,6 +2068,7 @@ static void pr_out_param(struct dl *dl, struct nlattr **tb, bool array)
|
||||||
{
|
{
|
||||||
struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
|
struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
|
||||||
struct nlattr *param_value_attr;
|
struct nlattr *param_value_attr;
|
||||||
|
const char *nla_name;
|
||||||
int nla_type;
|
int nla_type;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
|
@ -1980,8 +2087,8 @@ static void pr_out_param(struct dl *dl, struct nlattr **tb, bool array)
|
||||||
|
|
||||||
nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
|
nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
|
||||||
|
|
||||||
pr_out_str(dl, "name",
|
nla_name = mnl_attr_get_str(nla_param[DEVLINK_ATTR_PARAM_NAME]);
|
||||||
mnl_attr_get_str(nla_param[DEVLINK_ATTR_PARAM_NAME]));
|
pr_out_str(dl, "name", nla_name);
|
||||||
|
|
||||||
if (!nla_param[DEVLINK_ATTR_PARAM_GENERIC])
|
if (!nla_param[DEVLINK_ATTR_PARAM_GENERIC])
|
||||||
pr_out_str(dl, "type", "driver-specific");
|
pr_out_str(dl, "type", "driver-specific");
|
||||||
|
|
@ -1992,7 +2099,7 @@ static void pr_out_param(struct dl *dl, struct nlattr **tb, bool array)
|
||||||
mnl_attr_for_each_nested(param_value_attr,
|
mnl_attr_for_each_nested(param_value_attr,
|
||||||
nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
|
nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
|
||||||
pr_out_entry_start(dl);
|
pr_out_entry_start(dl);
|
||||||
pr_out_param_value(dl, nla_type, param_value_attr);
|
pr_out_param_value(dl, nla_name, nla_type, param_value_attr);
|
||||||
pr_out_entry_end(dl);
|
pr_out_entry_end(dl);
|
||||||
}
|
}
|
||||||
pr_out_array_end(dl);
|
pr_out_array_end(dl);
|
||||||
|
|
@ -2097,6 +2204,7 @@ static int cmd_dev_param_set(struct dl *dl)
|
||||||
{
|
{
|
||||||
struct param_ctx ctx = {};
|
struct param_ctx ctx = {};
|
||||||
struct nlmsghdr *nlh;
|
struct nlmsghdr *nlh;
|
||||||
|
bool conv_exists;
|
||||||
uint32_t val_u32;
|
uint32_t val_u32;
|
||||||
uint16_t val_u16;
|
uint16_t val_u16;
|
||||||
uint8_t val_u8;
|
uint8_t val_u8;
|
||||||
|
|
@ -2124,10 +2232,22 @@ static int cmd_dev_param_set(struct dl *dl)
|
||||||
NLM_F_REQUEST | NLM_F_ACK);
|
NLM_F_REQUEST | NLM_F_ACK);
|
||||||
dl_opts_put(nlh, dl);
|
dl_opts_put(nlh, dl);
|
||||||
|
|
||||||
|
conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN,
|
||||||
|
dl->opts.param_name);
|
||||||
|
|
||||||
mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_TYPE, ctx.nla_type);
|
mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_TYPE, ctx.nla_type);
|
||||||
switch (ctx.nla_type) {
|
switch (ctx.nla_type) {
|
||||||
case MNL_TYPE_U8:
|
case MNL_TYPE_U8:
|
||||||
err = strtouint8_t(dl->opts.param_value, &val_u8);
|
if (conv_exists) {
|
||||||
|
err = param_val_conv_uint_get(param_val_conv,
|
||||||
|
PARAM_VAL_CONV_LEN,
|
||||||
|
dl->opts.param_name,
|
||||||
|
dl->opts.param_value,
|
||||||
|
&val_u32);
|
||||||
|
val_u8 = val_u32;
|
||||||
|
} else {
|
||||||
|
err = strtouint8_t(dl->opts.param_value, &val_u8);
|
||||||
|
}
|
||||||
if (err)
|
if (err)
|
||||||
goto err_param_value_parse;
|
goto err_param_value_parse;
|
||||||
if (val_u8 == ctx.value.vu8)
|
if (val_u8 == ctx.value.vu8)
|
||||||
|
|
@ -2135,7 +2255,16 @@ static int cmd_dev_param_set(struct dl *dl)
|
||||||
mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u8);
|
mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u8);
|
||||||
break;
|
break;
|
||||||
case MNL_TYPE_U16:
|
case MNL_TYPE_U16:
|
||||||
err = strtouint16_t(dl->opts.param_value, &val_u16);
|
if (conv_exists) {
|
||||||
|
err = param_val_conv_uint_get(param_val_conv,
|
||||||
|
PARAM_VAL_CONV_LEN,
|
||||||
|
dl->opts.param_name,
|
||||||
|
dl->opts.param_value,
|
||||||
|
&val_u32);
|
||||||
|
val_u16 = val_u32;
|
||||||
|
} else {
|
||||||
|
err = strtouint16_t(dl->opts.param_value, &val_u16);
|
||||||
|
}
|
||||||
if (err)
|
if (err)
|
||||||
goto err_param_value_parse;
|
goto err_param_value_parse;
|
||||||
if (val_u16 == ctx.value.vu16)
|
if (val_u16 == ctx.value.vu16)
|
||||||
|
|
@ -2143,7 +2272,14 @@ static int cmd_dev_param_set(struct dl *dl)
|
||||||
mnl_attr_put_u16(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u16);
|
mnl_attr_put_u16(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u16);
|
||||||
break;
|
break;
|
||||||
case MNL_TYPE_U32:
|
case MNL_TYPE_U32:
|
||||||
err = strtouint32_t(dl->opts.param_value, &val_u32);
|
if (conv_exists)
|
||||||
|
err = param_val_conv_uint_get(param_val_conv,
|
||||||
|
PARAM_VAL_CONV_LEN,
|
||||||
|
dl->opts.param_name,
|
||||||
|
dl->opts.param_value,
|
||||||
|
&val_u32);
|
||||||
|
else
|
||||||
|
err = strtouint32_t(dl->opts.param_value, &val_u32);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_param_value_parse;
|
goto err_param_value_parse;
|
||||||
if (val_u32 == ctx.value.vu32)
|
if (val_u32 == ctx.value.vu32)
|
||||||
|
|
|
||||||
|
|
@ -254,4 +254,3 @@ At the moment the focus has been on getting the architecture in place.
|
||||||
Expect new things in the spurious time i have to work on this
|
Expect new things in the spurious time i have to work on this
|
||||||
(particularly around end of year when i have typically get time off
|
(particularly around end of year when i have typically get time off
|
||||||
from work).
|
from work).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,4 +76,3 @@ filter protocol ip pref 6 u32 filter protocol ip pref 6 u32 fh 800: ht divisor 1
|
||||||
index 4 ref 1 bind 1 installed 118 sec used 82 sec
|
index 4 ref 1 bind 1 installed 118 sec used 82 sec
|
||||||
Sent 1680 bytes 20 pkts (dropped 10, overlimits 0 )
|
Sent 1680 bytes 20 pkts (dropped 10, overlimits 0 )
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ _PRINT_FUNC(null, const char*);
|
||||||
_PRINT_FUNC(string, const char*);
|
_PRINT_FUNC(string, const char*);
|
||||||
_PRINT_FUNC(uint, unsigned int);
|
_PRINT_FUNC(uint, unsigned int);
|
||||||
_PRINT_FUNC(u64, uint64_t);
|
_PRINT_FUNC(u64, uint64_t);
|
||||||
|
_PRINT_FUNC(hhu, unsigned char);
|
||||||
_PRINT_FUNC(hu, unsigned short);
|
_PRINT_FUNC(hu, unsigned short);
|
||||||
_PRINT_FUNC(hex, unsigned int);
|
_PRINT_FUNC(hex, unsigned int);
|
||||||
_PRINT_FUNC(0xhex, unsigned long long);
|
_PRINT_FUNC(0xhex, unsigned long long);
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num);
|
||||||
void jsonw_uint(json_writer_t *self, unsigned int number);
|
void jsonw_uint(json_writer_t *self, unsigned int number);
|
||||||
void jsonw_u64(json_writer_t *self, uint64_t number);
|
void jsonw_u64(json_writer_t *self, uint64_t number);
|
||||||
void jsonw_xint(json_writer_t *self, uint64_t number);
|
void jsonw_xint(json_writer_t *self, uint64_t number);
|
||||||
|
void jsonw_hhu(json_writer_t *self, unsigned char num);
|
||||||
void jsonw_hu(json_writer_t *self, unsigned short number);
|
void jsonw_hu(json_writer_t *self, unsigned short number);
|
||||||
void jsonw_int(json_writer_t *self, int number);
|
void jsonw_int(json_writer_t *self, int number);
|
||||||
void jsonw_s64(json_writer_t *self, int64_t number);
|
void jsonw_s64(json_writer_t *self, int64_t number);
|
||||||
|
|
@ -52,6 +53,7 @@ void jsonw_float_field(json_writer_t *self, const char *prop, double num);
|
||||||
void jsonw_uint_field(json_writer_t *self, const char *prop, unsigned int num);
|
void jsonw_uint_field(json_writer_t *self, const char *prop, unsigned int num);
|
||||||
void jsonw_u64_field(json_writer_t *self, const char *prop, uint64_t num);
|
void jsonw_u64_field(json_writer_t *self, const char *prop, uint64_t num);
|
||||||
void jsonw_xint_field(json_writer_t *self, const char *prop, uint64_t num);
|
void jsonw_xint_field(json_writer_t *self, const char *prop, uint64_t num);
|
||||||
|
void jsonw_hhu_field(json_writer_t *self, const char *prop, unsigned char num);
|
||||||
void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num);
|
void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num);
|
||||||
void jsonw_int_field(json_writer_t *self, const char *prop, int num);
|
void jsonw_int_field(json_writer_t *self, const char *prop, int num);
|
||||||
void jsonw_s64_field(json_writer_t *self, const char *prop, int64_t num);
|
void jsonw_s64_field(json_writer_t *self, const char *prop, int64_t num);
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ struct rtnl_handle {
|
||||||
FILE *dump_fp;
|
FILE *dump_fp;
|
||||||
#define RTNL_HANDLE_F_LISTEN_ALL_NSID 0x01
|
#define RTNL_HANDLE_F_LISTEN_ALL_NSID 0x01
|
||||||
#define RTNL_HANDLE_F_SUPPRESS_NLERR 0x02
|
#define RTNL_HANDLE_F_SUPPRESS_NLERR 0x02
|
||||||
|
#define RTNL_HANDLE_F_STRICT_CHK 0x04
|
||||||
int flags;
|
int flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -46,16 +47,22 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned int subscriptions,
|
||||||
__attribute__((warn_unused_result));
|
__attribute__((warn_unused_result));
|
||||||
|
|
||||||
void rtnl_close(struct rtnl_handle *rth);
|
void rtnl_close(struct rtnl_handle *rth);
|
||||||
|
void rtnl_set_strict_dump(struct rtnl_handle *rth);
|
||||||
|
|
||||||
int rtnl_addrdump_req(struct rtnl_handle *rth, int family)
|
typedef int (*req_filter_fn_t)(struct nlmsghdr *nlh, int reqlen);
|
||||||
|
|
||||||
|
int rtnl_addrdump_req(struct rtnl_handle *rth, int family,
|
||||||
|
req_filter_fn_t filter_fn)
|
||||||
__attribute__((warn_unused_result));
|
__attribute__((warn_unused_result));
|
||||||
int rtnl_addrlbldump_req(struct rtnl_handle *rth, int family)
|
int rtnl_addrlbldump_req(struct rtnl_handle *rth, int family)
|
||||||
__attribute__((warn_unused_result));
|
__attribute__((warn_unused_result));
|
||||||
int rtnl_routedump_req(struct rtnl_handle *rth, int family)
|
int rtnl_routedump_req(struct rtnl_handle *rth, int family,
|
||||||
|
req_filter_fn_t filter_fn)
|
||||||
__attribute__((warn_unused_result));
|
__attribute__((warn_unused_result));
|
||||||
int rtnl_ruledump_req(struct rtnl_handle *rth, int family)
|
int rtnl_ruledump_req(struct rtnl_handle *rth, int family)
|
||||||
__attribute__((warn_unused_result));
|
__attribute__((warn_unused_result));
|
||||||
int rtnl_neighdump_req(struct rtnl_handle *rth, int family)
|
int rtnl_neighdump_req(struct rtnl_handle *rth, int family,
|
||||||
|
req_filter_fn_t filter_fn)
|
||||||
__attribute__((warn_unused_result));
|
__attribute__((warn_unused_result));
|
||||||
int rtnl_neightbldump_req(struct rtnl_handle *rth, int family)
|
int rtnl_neightbldump_req(struct rtnl_handle *rth, int family)
|
||||||
__attribute__((warn_unused_result));
|
__attribute__((warn_unused_result));
|
||||||
|
|
@ -71,8 +78,6 @@ int rtnl_linkdump_req(struct rtnl_handle *rth, int fam)
|
||||||
int rtnl_linkdump_req_filter(struct rtnl_handle *rth, int fam, __u32 filt_mask)
|
int rtnl_linkdump_req_filter(struct rtnl_handle *rth, int fam, __u32 filt_mask)
|
||||||
__attribute__((warn_unused_result));
|
__attribute__((warn_unused_result));
|
||||||
|
|
||||||
typedef int (*req_filter_fn_t)(struct nlmsghdr *nlh, int reqlen);
|
|
||||||
|
|
||||||
int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, int fam,
|
int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, int fam,
|
||||||
req_filter_fn_t fn)
|
req_filter_fn_t fn)
|
||||||
__attribute__((warn_unused_result));
|
__attribute__((warn_unused_result));
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,14 @@ enum bpf_map_type {
|
||||||
BPF_MAP_TYPE_STACK,
|
BPF_MAP_TYPE_STACK,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Note that tracing related programs such as
|
||||||
|
* BPF_PROG_TYPE_{KPROBE,TRACEPOINT,PERF_EVENT,RAW_TRACEPOINT}
|
||||||
|
* are not subject to a stable API since kernel internal data
|
||||||
|
* structures can change from release to release and may
|
||||||
|
* therefore break existing tracing BPF programs. Tracing BPF
|
||||||
|
* programs correspond to /a/ specific kernel which is to be
|
||||||
|
* analyzed, and not /a/ specific kernel /and/ all future ones.
|
||||||
|
*/
|
||||||
enum bpf_prog_type {
|
enum bpf_prog_type {
|
||||||
BPF_PROG_TYPE_UNSPEC,
|
BPF_PROG_TYPE_UNSPEC,
|
||||||
BPF_PROG_TYPE_SOCKET_FILTER,
|
BPF_PROG_TYPE_SOCKET_FILTER,
|
||||||
|
|
@ -232,6 +240,20 @@ enum bpf_attach_type {
|
||||||
*/
|
*/
|
||||||
#define BPF_F_STRICT_ALIGNMENT (1U << 0)
|
#define BPF_F_STRICT_ALIGNMENT (1U << 0)
|
||||||
|
|
||||||
|
/* If BPF_F_ANY_ALIGNMENT is used in BPF_PROF_LOAD command, the
|
||||||
|
* verifier will allow any alignment whatsoever. On platforms
|
||||||
|
* with strict alignment requirements for loads ands stores (such
|
||||||
|
* as sparc and mips) the verifier validates that all loads and
|
||||||
|
* stores provably follow this requirement. This flag turns that
|
||||||
|
* checking and enforcement off.
|
||||||
|
*
|
||||||
|
* It is mostly used for testing when we want to validate the
|
||||||
|
* context and memory access aspects of the verifier, but because
|
||||||
|
* of an unaligned access the alignment check would trigger before
|
||||||
|
* the one we are interested in.
|
||||||
|
*/
|
||||||
|
#define BPF_F_ANY_ALIGNMENT (1U << 1)
|
||||||
|
|
||||||
/* when bpf_ldimm64->src_reg == BPF_PSEUDO_MAP_FD, bpf_ldimm64->imm == fd */
|
/* when bpf_ldimm64->src_reg == BPF_PSEUDO_MAP_FD, bpf_ldimm64->imm == fd */
|
||||||
#define BPF_PSEUDO_MAP_FD 1
|
#define BPF_PSEUDO_MAP_FD 1
|
||||||
|
|
||||||
|
|
@ -257,9 +279,6 @@ enum bpf_attach_type {
|
||||||
/* Specify numa node during map creation */
|
/* Specify numa node during map creation */
|
||||||
#define BPF_F_NUMA_NODE (1U << 2)
|
#define BPF_F_NUMA_NODE (1U << 2)
|
||||||
|
|
||||||
/* flags for BPF_PROG_QUERY */
|
|
||||||
#define BPF_F_QUERY_EFFECTIVE (1U << 0)
|
|
||||||
|
|
||||||
#define BPF_OBJ_NAME_LEN 16U
|
#define BPF_OBJ_NAME_LEN 16U
|
||||||
|
|
||||||
/* Flags for accessing BPF object */
|
/* Flags for accessing BPF object */
|
||||||
|
|
@ -269,6 +288,12 @@ enum bpf_attach_type {
|
||||||
/* Flag for stack_map, store build_id+offset instead of pointer */
|
/* Flag for stack_map, store build_id+offset instead of pointer */
|
||||||
#define BPF_F_STACK_BUILD_ID (1U << 5)
|
#define BPF_F_STACK_BUILD_ID (1U << 5)
|
||||||
|
|
||||||
|
/* Zero-initialize hash function seed. This should only be used for testing. */
|
||||||
|
#define BPF_F_ZERO_SEED (1U << 6)
|
||||||
|
|
||||||
|
/* flags for BPF_PROG_QUERY */
|
||||||
|
#define BPF_F_QUERY_EFFECTIVE (1U << 0)
|
||||||
|
|
||||||
enum bpf_stack_build_id_status {
|
enum bpf_stack_build_id_status {
|
||||||
/* user space need an empty entry to identify end of a trace */
|
/* user space need an empty entry to identify end of a trace */
|
||||||
BPF_STACK_BUILD_ID_EMPTY = 0,
|
BPF_STACK_BUILD_ID_EMPTY = 0,
|
||||||
|
|
@ -326,7 +351,7 @@ union bpf_attr {
|
||||||
__u32 log_level; /* verbosity level of verifier */
|
__u32 log_level; /* verbosity level of verifier */
|
||||||
__u32 log_size; /* size of user buffer */
|
__u32 log_size; /* size of user buffer */
|
||||||
__aligned_u64 log_buf; /* user supplied buffer */
|
__aligned_u64 log_buf; /* user supplied buffer */
|
||||||
__u32 kern_version; /* checked when prog_type=kprobe */
|
__u32 kern_version; /* not used */
|
||||||
__u32 prog_flags;
|
__u32 prog_flags;
|
||||||
char prog_name[BPF_OBJ_NAME_LEN];
|
char prog_name[BPF_OBJ_NAME_LEN];
|
||||||
__u32 prog_ifindex; /* ifindex of netdev to prep for */
|
__u32 prog_ifindex; /* ifindex of netdev to prep for */
|
||||||
|
|
@ -335,6 +360,13 @@ union bpf_attr {
|
||||||
* (context accesses, allowed helpers, etc).
|
* (context accesses, allowed helpers, etc).
|
||||||
*/
|
*/
|
||||||
__u32 expected_attach_type;
|
__u32 expected_attach_type;
|
||||||
|
__u32 prog_btf_fd; /* fd pointing to BTF type data */
|
||||||
|
__u32 func_info_rec_size; /* userspace bpf_func_info size */
|
||||||
|
__aligned_u64 func_info; /* func info */
|
||||||
|
__u32 func_info_cnt; /* number of bpf_func_info records */
|
||||||
|
__u32 line_info_rec_size; /* userspace bpf_line_info size */
|
||||||
|
__aligned_u64 line_info; /* line info */
|
||||||
|
__u32 line_info_cnt; /* number of bpf_line_info records */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct { /* anonymous struct used by BPF_OBJ_* commands */
|
struct { /* anonymous struct used by BPF_OBJ_* commands */
|
||||||
|
|
@ -353,8 +385,11 @@ union bpf_attr {
|
||||||
struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */
|
struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */
|
||||||
__u32 prog_fd;
|
__u32 prog_fd;
|
||||||
__u32 retval;
|
__u32 retval;
|
||||||
__u32 data_size_in;
|
__u32 data_size_in; /* input: len of data_in */
|
||||||
__u32 data_size_out;
|
__u32 data_size_out; /* input/output: len of data_out
|
||||||
|
* returns ENOSPC if data_out
|
||||||
|
* is too small.
|
||||||
|
*/
|
||||||
__aligned_u64 data_in;
|
__aligned_u64 data_in;
|
||||||
__aligned_u64 data_out;
|
__aligned_u64 data_out;
|
||||||
__u32 repeat;
|
__u32 repeat;
|
||||||
|
|
@ -475,18 +510,6 @@ union bpf_attr {
|
||||||
* Return
|
* Return
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
*
|
*
|
||||||
* int bpf_map_pop_elem(struct bpf_map *map, void *value)
|
|
||||||
* Description
|
|
||||||
* Pop an element from *map*.
|
|
||||||
* Return
|
|
||||||
* 0 on success, or a negative error in case of failure.
|
|
||||||
*
|
|
||||||
* int bpf_map_peek_elem(struct bpf_map *map, void *value)
|
|
||||||
* Description
|
|
||||||
* Get an element from *map* without removing it.
|
|
||||||
* Return
|
|
||||||
* 0 on success, or a negative error in case of failure.
|
|
||||||
*
|
|
||||||
* int bpf_probe_read(void *dst, u32 size, const void *src)
|
* int bpf_probe_read(void *dst, u32 size, const void *src)
|
||||||
* Description
|
* Description
|
||||||
* For tracing programs, safely attempt to read *size* bytes from
|
* For tracing programs, safely attempt to read *size* bytes from
|
||||||
|
|
@ -1910,9 +1933,9 @@ union bpf_attr {
|
||||||
* is set to metric from route (IPv4/IPv6 only), and ifindex
|
* is set to metric from route (IPv4/IPv6 only), and ifindex
|
||||||
* is set to the device index of the nexthop from the FIB lookup.
|
* is set to the device index of the nexthop from the FIB lookup.
|
||||||
*
|
*
|
||||||
* *plen* argument is the size of the passed in struct.
|
* *plen* argument is the size of the passed in struct.
|
||||||
* *flags* argument can be a combination of one or more of the
|
* *flags* argument can be a combination of one or more of the
|
||||||
* following values:
|
* following values:
|
||||||
*
|
*
|
||||||
* **BPF_FIB_LOOKUP_DIRECT**
|
* **BPF_FIB_LOOKUP_DIRECT**
|
||||||
* Do a direct table lookup vs full lookup using FIB
|
* Do a direct table lookup vs full lookup using FIB
|
||||||
|
|
@ -1921,9 +1944,9 @@ union bpf_attr {
|
||||||
* Perform lookup from an egress perspective (default is
|
* Perform lookup from an egress perspective (default is
|
||||||
* ingress).
|
* ingress).
|
||||||
*
|
*
|
||||||
* *ctx* is either **struct xdp_md** for XDP programs or
|
* *ctx* is either **struct xdp_md** for XDP programs or
|
||||||
* **struct sk_buff** tc cls_act programs.
|
* **struct sk_buff** tc cls_act programs.
|
||||||
* Return
|
* Return
|
||||||
* * < 0 if any input argument is invalid
|
* * < 0 if any input argument is invalid
|
||||||
* * 0 on success (packet is forwarded, nexthop neighbor exists)
|
* * 0 on success (packet is forwarded, nexthop neighbor exists)
|
||||||
* * > 0 one of **BPF_FIB_LKUP_RET_** codes explaining why the
|
* * > 0 one of **BPF_FIB_LKUP_RET_** codes explaining why the
|
||||||
|
|
@ -2068,8 +2091,8 @@ union bpf_attr {
|
||||||
* translated to a keycode using the rc keymap, and reported as
|
* translated to a keycode using the rc keymap, and reported as
|
||||||
* an input key down event. After a period a key up event is
|
* an input key down event. After a period a key up event is
|
||||||
* generated. This period can be extended by calling either
|
* generated. This period can be extended by calling either
|
||||||
* **bpf_rc_keydown** () again with the same values, or calling
|
* **bpf_rc_keydown**\ () again with the same values, or calling
|
||||||
* **bpf_rc_repeat** ().
|
* **bpf_rc_repeat**\ ().
|
||||||
*
|
*
|
||||||
* Some protocols include a toggle bit, in case the button was
|
* Some protocols include a toggle bit, in case the button was
|
||||||
* released and pressed again between consecutive scancodes.
|
* released and pressed again between consecutive scancodes.
|
||||||
|
|
@ -2152,21 +2175,22 @@ union bpf_attr {
|
||||||
* The *flags* meaning is specific for each map type,
|
* The *flags* meaning is specific for each map type,
|
||||||
* and has to be 0 for cgroup local storage.
|
* and has to be 0 for cgroup local storage.
|
||||||
*
|
*
|
||||||
* Depending on the bpf program type, a local storage area
|
* Depending on the BPF program type, a local storage area
|
||||||
* can be shared between multiple instances of the bpf program,
|
* can be shared between multiple instances of the BPF program,
|
||||||
* running simultaneously.
|
* running simultaneously.
|
||||||
*
|
*
|
||||||
* A user should care about the synchronization by himself.
|
* A user should care about the synchronization by himself.
|
||||||
* For example, by using the BPF_STX_XADD instruction to alter
|
* For example, by using the **BPF_STX_XADD** instruction to alter
|
||||||
* the shared data.
|
* the shared data.
|
||||||
* Return
|
* Return
|
||||||
* Pointer to the local storage area.
|
* A pointer to the local storage area.
|
||||||
*
|
*
|
||||||
* int bpf_sk_select_reuseport(struct sk_reuseport_md *reuse, struct bpf_map *map, void *key, u64 flags)
|
* int bpf_sk_select_reuseport(struct sk_reuseport_md *reuse, struct bpf_map *map, void *key, u64 flags)
|
||||||
* Description
|
* Description
|
||||||
* Select a SO_REUSEPORT sk from a BPF_MAP_TYPE_REUSEPORT_ARRAY map
|
* Select a **SO_REUSEPORT** socket from a
|
||||||
* It checks the selected sk is matching the incoming
|
* **BPF_MAP_TYPE_REUSEPORT_ARRAY** *map*.
|
||||||
* request in the skb.
|
* It checks the selected socket is matching the incoming
|
||||||
|
* request in the socket buffer.
|
||||||
* Return
|
* Return
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
*
|
*
|
||||||
|
|
@ -2174,7 +2198,7 @@ union bpf_attr {
|
||||||
* Description
|
* Description
|
||||||
* Look for TCP socket matching *tuple*, optionally in a child
|
* Look for TCP socket matching *tuple*, optionally in a child
|
||||||
* network namespace *netns*. The return value must be checked,
|
* network namespace *netns*. The return value must be checked,
|
||||||
* and if non-NULL, released via **bpf_sk_release**\ ().
|
* and if non-**NULL**, released via **bpf_sk_release**\ ().
|
||||||
*
|
*
|
||||||
* The *ctx* should point to the context of the program, such as
|
* The *ctx* should point to the context of the program, such as
|
||||||
* the skb or socket (depending on the hook in use). This is used
|
* the skb or socket (depending on the hook in use). This is used
|
||||||
|
|
@ -2202,15 +2226,15 @@ union bpf_attr {
|
||||||
* This helper is available only if the kernel was compiled with
|
* This helper is available only if the kernel was compiled with
|
||||||
* **CONFIG_NET** configuration option.
|
* **CONFIG_NET** configuration option.
|
||||||
* Return
|
* Return
|
||||||
* Pointer to *struct bpf_sock*, or NULL in case of failure.
|
* Pointer to **struct bpf_sock**, or **NULL** in case of failure.
|
||||||
* For sockets with reuseport option, the *struct bpf_sock*
|
* For sockets with reuseport option, the **struct bpf_sock**
|
||||||
* result is from reuse->socks[] using the hash of the tuple.
|
* result is from **reuse->socks**\ [] using the hash of the tuple.
|
||||||
*
|
*
|
||||||
* struct bpf_sock *bpf_sk_lookup_udp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u64 netns, u64 flags)
|
* struct bpf_sock *bpf_sk_lookup_udp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u64 netns, u64 flags)
|
||||||
* Description
|
* Description
|
||||||
* Look for UDP socket matching *tuple*, optionally in a child
|
* Look for UDP socket matching *tuple*, optionally in a child
|
||||||
* network namespace *netns*. The return value must be checked,
|
* network namespace *netns*. The return value must be checked,
|
||||||
* and if non-NULL, released via **bpf_sk_release**\ ().
|
* and if non-**NULL**, released via **bpf_sk_release**\ ().
|
||||||
*
|
*
|
||||||
* The *ctx* should point to the context of the program, such as
|
* The *ctx* should point to the context of the program, such as
|
||||||
* the skb or socket (depending on the hook in use). This is used
|
* the skb or socket (depending on the hook in use). This is used
|
||||||
|
|
@ -2238,33 +2262,71 @@ union bpf_attr {
|
||||||
* This helper is available only if the kernel was compiled with
|
* This helper is available only if the kernel was compiled with
|
||||||
* **CONFIG_NET** configuration option.
|
* **CONFIG_NET** configuration option.
|
||||||
* Return
|
* Return
|
||||||
* Pointer to *struct bpf_sock*, or NULL in case of failure.
|
* Pointer to **struct bpf_sock**, or **NULL** in case of failure.
|
||||||
* For sockets with reuseport option, the *struct bpf_sock*
|
* For sockets with reuseport option, the **struct bpf_sock**
|
||||||
* result is from reuse->socks[] using the hash of the tuple.
|
* result is from **reuse->socks**\ [] using the hash of the tuple.
|
||||||
*
|
*
|
||||||
* int bpf_sk_release(struct bpf_sock *sk)
|
* int bpf_sk_release(struct bpf_sock *sock)
|
||||||
* Description
|
* Description
|
||||||
* Release the reference held by *sock*. *sock* must be a non-NULL
|
* Release the reference held by *sock*. *sock* must be a
|
||||||
* pointer that was returned from bpf_sk_lookup_xxx\ ().
|
* non-**NULL** pointer that was returned from
|
||||||
|
* **bpf_sk_lookup_xxx**\ ().
|
||||||
* Return
|
* Return
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
*
|
*
|
||||||
|
* int bpf_map_pop_elem(struct bpf_map *map, void *value)
|
||||||
|
* Description
|
||||||
|
* Pop an element from *map*.
|
||||||
|
* Return
|
||||||
|
* 0 on success, or a negative error in case of failure.
|
||||||
|
*
|
||||||
|
* int bpf_map_peek_elem(struct bpf_map *map, void *value)
|
||||||
|
* Description
|
||||||
|
* Get an element from *map* without removing it.
|
||||||
|
* Return
|
||||||
|
* 0 on success, or a negative error in case of failure.
|
||||||
|
*
|
||||||
* int bpf_msg_push_data(struct sk_buff *skb, u32 start, u32 len, u64 flags)
|
* int bpf_msg_push_data(struct sk_buff *skb, u32 start, u32 len, u64 flags)
|
||||||
* Description
|
* Description
|
||||||
* For socket policies, insert *len* bytes into msg at offset
|
* For socket policies, insert *len* bytes into *msg* at offset
|
||||||
* *start*.
|
* *start*.
|
||||||
*
|
*
|
||||||
* If a program of type **BPF_PROG_TYPE_SK_MSG** is run on a
|
* If a program of type **BPF_PROG_TYPE_SK_MSG** is run on a
|
||||||
* *msg* it may want to insert metadata or options into the msg.
|
* *msg* it may want to insert metadata or options into the *msg*.
|
||||||
* This can later be read and used by any of the lower layer BPF
|
* This can later be read and used by any of the lower layer BPF
|
||||||
* hooks.
|
* hooks.
|
||||||
*
|
*
|
||||||
* This helper may fail if under memory pressure (a malloc
|
* This helper may fail if under memory pressure (a malloc
|
||||||
* fails) in these cases BPF programs will get an appropriate
|
* fails) in these cases BPF programs will get an appropriate
|
||||||
* error and BPF programs will need to handle them.
|
* error and BPF programs will need to handle them.
|
||||||
*
|
|
||||||
* Return
|
* Return
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
|
*
|
||||||
|
* int bpf_msg_pop_data(struct sk_msg_buff *msg, u32 start, u32 pop, u64 flags)
|
||||||
|
* Description
|
||||||
|
* Will remove *pop* bytes from a *msg* starting at byte *start*.
|
||||||
|
* This may result in **ENOMEM** errors under certain situations if
|
||||||
|
* an allocation and copy are required due to a full ring buffer.
|
||||||
|
* However, the helper will try to avoid doing the allocation
|
||||||
|
* if possible. Other errors can occur if input parameters are
|
||||||
|
* invalid either due to *start* byte not being valid part of *msg*
|
||||||
|
* payload and/or *pop* value being to large.
|
||||||
|
* Return
|
||||||
|
* 0 on success, or a negative error in case of failure.
|
||||||
|
*
|
||||||
|
* int bpf_rc_pointer_rel(void *ctx, s32 rel_x, s32 rel_y)
|
||||||
|
* Description
|
||||||
|
* This helper is used in programs implementing IR decoding, to
|
||||||
|
* report a successfully decoded pointer movement.
|
||||||
|
*
|
||||||
|
* The *ctx* should point to the lirc sample as passed into
|
||||||
|
* the program.
|
||||||
|
*
|
||||||
|
* This helper is only available is the kernel was compiled with
|
||||||
|
* the **CONFIG_BPF_LIRC_MODE2** configuration option set to
|
||||||
|
* "**y**".
|
||||||
|
* Return
|
||||||
|
* 0
|
||||||
*/
|
*/
|
||||||
#define __BPF_FUNC_MAPPER(FN) \
|
#define __BPF_FUNC_MAPPER(FN) \
|
||||||
FN(unspec), \
|
FN(unspec), \
|
||||||
|
|
@ -2357,7 +2419,9 @@ union bpf_attr {
|
||||||
FN(map_push_elem), \
|
FN(map_push_elem), \
|
||||||
FN(map_pop_elem), \
|
FN(map_pop_elem), \
|
||||||
FN(map_peek_elem), \
|
FN(map_peek_elem), \
|
||||||
FN(msg_push_data),
|
FN(msg_push_data), \
|
||||||
|
FN(msg_pop_data), \
|
||||||
|
FN(rc_pointer_rel),
|
||||||
|
|
||||||
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
|
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
|
||||||
* function eBPF program intends to call
|
* function eBPF program intends to call
|
||||||
|
|
@ -2474,6 +2538,8 @@ struct __sk_buff {
|
||||||
|
|
||||||
__u32 data_meta;
|
__u32 data_meta;
|
||||||
__bpf_md_ptr(struct bpf_flow_keys *, flow_keys);
|
__bpf_md_ptr(struct bpf_flow_keys *, flow_keys);
|
||||||
|
__u64 tstamp;
|
||||||
|
__u32 wire_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bpf_tunnel_key {
|
struct bpf_tunnel_key {
|
||||||
|
|
@ -2599,6 +2665,7 @@ struct sk_msg_md {
|
||||||
__u32 local_ip6[4]; /* Stored in network byte order */
|
__u32 local_ip6[4]; /* Stored in network byte order */
|
||||||
__u32 remote_port; /* Stored in network byte order */
|
__u32 remote_port; /* Stored in network byte order */
|
||||||
__u32 local_port; /* stored in host byte order */
|
__u32 local_port; /* stored in host byte order */
|
||||||
|
__u32 size; /* Total size of sk_msg */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sk_reuseport_md {
|
struct sk_reuseport_md {
|
||||||
|
|
@ -2649,6 +2716,18 @@ struct bpf_prog_info {
|
||||||
__u32 nr_jited_func_lens;
|
__u32 nr_jited_func_lens;
|
||||||
__aligned_u64 jited_ksyms;
|
__aligned_u64 jited_ksyms;
|
||||||
__aligned_u64 jited_func_lens;
|
__aligned_u64 jited_func_lens;
|
||||||
|
__u32 btf_id;
|
||||||
|
__u32 func_info_rec_size;
|
||||||
|
__aligned_u64 func_info;
|
||||||
|
__u32 nr_func_info;
|
||||||
|
__u32 nr_line_info;
|
||||||
|
__aligned_u64 line_info;
|
||||||
|
__aligned_u64 jited_line_info;
|
||||||
|
__u32 nr_jited_line_info;
|
||||||
|
__u32 line_info_rec_size;
|
||||||
|
__u32 jited_line_info_rec_size;
|
||||||
|
__u32 nr_prog_tags;
|
||||||
|
__aligned_u64 prog_tags;
|
||||||
} __attribute__((aligned(8)));
|
} __attribute__((aligned(8)));
|
||||||
|
|
||||||
struct bpf_map_info {
|
struct bpf_map_info {
|
||||||
|
|
@ -2960,4 +3039,19 @@ struct bpf_flow_keys {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct bpf_func_info {
|
||||||
|
__u32 insn_off;
|
||||||
|
__u32 type_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BPF_LINE_INFO_LINE_NUM(line_col) ((line_col) >> 10)
|
||||||
|
#define BPF_LINE_INFO_LINE_COL(line_col) ((line_col) & 0x3ff)
|
||||||
|
|
||||||
|
struct bpf_line_info {
|
||||||
|
__u32 insn_off;
|
||||||
|
__u32 file_name_off;
|
||||||
|
__u32 line_off;
|
||||||
|
__u32 line_col;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* __LINUX_BPF_H__ */
|
#endif /* __LINUX_BPF_H__ */
|
||||||
|
|
|
||||||
|
|
@ -34,13 +34,16 @@ struct btf_type {
|
||||||
* bits 0-15: vlen (e.g. # of struct's members)
|
* bits 0-15: vlen (e.g. # of struct's members)
|
||||||
* bits 16-23: unused
|
* bits 16-23: unused
|
||||||
* bits 24-27: kind (e.g. int, ptr, array...etc)
|
* bits 24-27: kind (e.g. int, ptr, array...etc)
|
||||||
* bits 28-31: unused
|
* bits 28-30: unused
|
||||||
|
* bit 31: kind_flag, currently used by
|
||||||
|
* struct, union and fwd
|
||||||
*/
|
*/
|
||||||
__u32 info;
|
__u32 info;
|
||||||
/* "size" is used by INT, ENUM, STRUCT and UNION.
|
/* "size" is used by INT, ENUM, STRUCT and UNION.
|
||||||
* "size" tells the size of the type it is describing.
|
* "size" tells the size of the type it is describing.
|
||||||
*
|
*
|
||||||
* "type" is used by PTR, TYPEDEF, VOLATILE, CONST and RESTRICT.
|
* "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
|
||||||
|
* FUNC and FUNC_PROTO.
|
||||||
* "type" is a type_id referring to another type.
|
* "type" is a type_id referring to another type.
|
||||||
*/
|
*/
|
||||||
union {
|
union {
|
||||||
|
|
@ -51,6 +54,7 @@ struct btf_type {
|
||||||
|
|
||||||
#define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f)
|
#define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f)
|
||||||
#define BTF_INFO_VLEN(info) ((info) & 0xffff)
|
#define BTF_INFO_VLEN(info) ((info) & 0xffff)
|
||||||
|
#define BTF_INFO_KFLAG(info) ((info) >> 31)
|
||||||
|
|
||||||
#define BTF_KIND_UNKN 0 /* Unknown */
|
#define BTF_KIND_UNKN 0 /* Unknown */
|
||||||
#define BTF_KIND_INT 1 /* Integer */
|
#define BTF_KIND_INT 1 /* Integer */
|
||||||
|
|
@ -64,8 +68,10 @@ struct btf_type {
|
||||||
#define BTF_KIND_VOLATILE 9 /* Volatile */
|
#define BTF_KIND_VOLATILE 9 /* Volatile */
|
||||||
#define BTF_KIND_CONST 10 /* Const */
|
#define BTF_KIND_CONST 10 /* Const */
|
||||||
#define BTF_KIND_RESTRICT 11 /* Restrict */
|
#define BTF_KIND_RESTRICT 11 /* Restrict */
|
||||||
#define BTF_KIND_MAX 11
|
#define BTF_KIND_FUNC 12 /* Function */
|
||||||
#define NR_BTF_KINDS 12
|
#define BTF_KIND_FUNC_PROTO 13 /* Function Proto */
|
||||||
|
#define BTF_KIND_MAX 13
|
||||||
|
#define NR_BTF_KINDS 14
|
||||||
|
|
||||||
/* For some specific BTF_KIND, "struct btf_type" is immediately
|
/* For some specific BTF_KIND, "struct btf_type" is immediately
|
||||||
* followed by extra data.
|
* followed by extra data.
|
||||||
|
|
@ -107,7 +113,29 @@ struct btf_array {
|
||||||
struct btf_member {
|
struct btf_member {
|
||||||
__u32 name_off;
|
__u32 name_off;
|
||||||
__u32 type;
|
__u32 type;
|
||||||
__u32 offset; /* offset in bits */
|
/* If the type info kind_flag is set, the btf_member offset
|
||||||
|
* contains both member bitfield size and bit offset. The
|
||||||
|
* bitfield size is set for bitfield members. If the type
|
||||||
|
* info kind_flag is not set, the offset contains only bit
|
||||||
|
* offset.
|
||||||
|
*/
|
||||||
|
__u32 offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* If the struct/union type info kind_flag is set, the
|
||||||
|
* following two macros are used to access bitfield_size
|
||||||
|
* and bit_offset from btf_member.offset.
|
||||||
|
*/
|
||||||
|
#define BTF_MEMBER_BITFIELD_SIZE(val) ((val) >> 24)
|
||||||
|
#define BTF_MEMBER_BIT_OFFSET(val) ((val) & 0xffffff)
|
||||||
|
|
||||||
|
/* BTF_KIND_FUNC_PROTO is followed by multiple "struct btf_param".
|
||||||
|
* The exact number of btf_param is stored in the vlen (of the
|
||||||
|
* info in "struct btf_type").
|
||||||
|
*/
|
||||||
|
struct btf_param {
|
||||||
|
__u32 name_off;
|
||||||
|
__u32 type;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __LINUX_BTF_H__ */
|
#endif /* __LINUX_BTF_H__ */
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,11 @@ enum devlink_param_cmode {
|
||||||
DEVLINK_PARAM_CMODE_MAX = __DEVLINK_PARAM_CMODE_MAX - 1
|
DEVLINK_PARAM_CMODE_MAX = __DEVLINK_PARAM_CMODE_MAX - 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum devlink_param_fw_load_policy_value {
|
||||||
|
DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER,
|
||||||
|
DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH,
|
||||||
|
};
|
||||||
|
|
||||||
enum devlink_attr {
|
enum devlink_attr {
|
||||||
/* don't change the order or add anything between, this is ABI! */
|
/* don't change the order or add anything between, this is ABI! */
|
||||||
DEVLINK_ATTR_UNSPEC,
|
DEVLINK_ATTR_UNSPEC,
|
||||||
|
|
|
||||||
|
|
@ -292,4 +292,25 @@ struct br_mcast_stats {
|
||||||
__u64 mcast_bytes[BR_MCAST_DIR_SIZE];
|
__u64 mcast_bytes[BR_MCAST_DIR_SIZE];
|
||||||
__u64 mcast_packets[BR_MCAST_DIR_SIZE];
|
__u64 mcast_packets[BR_MCAST_DIR_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* bridge boolean options
|
||||||
|
* BR_BOOLOPT_NO_LL_LEARN - disable learning from link-local packets
|
||||||
|
*
|
||||||
|
* IMPORTANT: if adding a new option do not forget to handle
|
||||||
|
* it in br_boolopt_toggle/get and bridge sysfs
|
||||||
|
*/
|
||||||
|
enum br_boolopt_id {
|
||||||
|
BR_BOOLOPT_NO_LL_LEARN,
|
||||||
|
BR_BOOLOPT_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
/* struct br_boolopt_multi - change multiple bridge boolean options
|
||||||
|
*
|
||||||
|
* @optval: new option values (bit per option)
|
||||||
|
* @optmask: options to change (bit per option)
|
||||||
|
*/
|
||||||
|
struct br_boolopt_multi {
|
||||||
|
__u32 optval;
|
||||||
|
__u32 optmask;
|
||||||
|
};
|
||||||
#endif /* _LINUX_IF_BRIDGE_H */
|
#endif /* _LINUX_IF_BRIDGE_H */
|
||||||
|
|
|
||||||
|
|
@ -286,6 +286,7 @@ enum {
|
||||||
IFLA_BR_MCAST_IGMP_VERSION,
|
IFLA_BR_MCAST_IGMP_VERSION,
|
||||||
IFLA_BR_MCAST_MLD_VERSION,
|
IFLA_BR_MCAST_MLD_VERSION,
|
||||||
IFLA_BR_VLAN_STATS_PER_PORT,
|
IFLA_BR_VLAN_STATS_PER_PORT,
|
||||||
|
IFLA_BR_MULTI_BOOLOPT,
|
||||||
__IFLA_BR_MAX,
|
__IFLA_BR_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -531,6 +532,7 @@ enum {
|
||||||
IFLA_VXLAN_LABEL,
|
IFLA_VXLAN_LABEL,
|
||||||
IFLA_VXLAN_GPE,
|
IFLA_VXLAN_GPE,
|
||||||
IFLA_VXLAN_TTL_INHERIT,
|
IFLA_VXLAN_TTL_INHERIT,
|
||||||
|
IFLA_VXLAN_DF,
|
||||||
__IFLA_VXLAN_MAX
|
__IFLA_VXLAN_MAX
|
||||||
};
|
};
|
||||||
#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
|
#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
|
||||||
|
|
@ -540,6 +542,14 @@ struct ifla_vxlan_port_range {
|
||||||
__be16 high;
|
__be16 high;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ifla_vxlan_df {
|
||||||
|
VXLAN_DF_UNSET = 0,
|
||||||
|
VXLAN_DF_SET,
|
||||||
|
VXLAN_DF_INHERIT,
|
||||||
|
__VXLAN_DF_END,
|
||||||
|
VXLAN_DF_MAX = __VXLAN_DF_END - 1,
|
||||||
|
};
|
||||||
|
|
||||||
/* GENEVE section */
|
/* GENEVE section */
|
||||||
enum {
|
enum {
|
||||||
IFLA_GENEVE_UNSPEC,
|
IFLA_GENEVE_UNSPEC,
|
||||||
|
|
@ -555,10 +565,19 @@ enum {
|
||||||
IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
|
IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
|
||||||
IFLA_GENEVE_LABEL,
|
IFLA_GENEVE_LABEL,
|
||||||
IFLA_GENEVE_TTL_INHERIT,
|
IFLA_GENEVE_TTL_INHERIT,
|
||||||
|
IFLA_GENEVE_DF,
|
||||||
__IFLA_GENEVE_MAX
|
__IFLA_GENEVE_MAX
|
||||||
};
|
};
|
||||||
#define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1)
|
#define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1)
|
||||||
|
|
||||||
|
enum ifla_geneve_df {
|
||||||
|
GENEVE_DF_UNSET = 0,
|
||||||
|
GENEVE_DF_SET,
|
||||||
|
GENEVE_DF_INHERIT,
|
||||||
|
__GENEVE_DF_END,
|
||||||
|
GENEVE_DF_MAX = __GENEVE_DF_END - 1,
|
||||||
|
};
|
||||||
|
|
||||||
/* PPP section */
|
/* PPP section */
|
||||||
enum {
|
enum {
|
||||||
IFLA_PPP_UNSPEC,
|
IFLA_PPP_UNSPEC,
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@
|
||||||
#define TUNGETVNETBE _IOR('T', 223, int)
|
#define TUNGETVNETBE _IOR('T', 223, int)
|
||||||
#define TUNSETSTEERINGEBPF _IOR('T', 224, int)
|
#define TUNSETSTEERINGEBPF _IOR('T', 224, int)
|
||||||
#define TUNSETFILTEREBPF _IOR('T', 225, int)
|
#define TUNSETFILTEREBPF _IOR('T', 225, int)
|
||||||
|
#define TUNSETCARRIER _IOW('T', 226, int)
|
||||||
|
|
||||||
/* TUNSETIFF ifr flags */
|
/* TUNSETIFF ifr flags */
|
||||||
#define IFF_TUN 0x0001
|
#define IFF_TUN 0x0001
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ enum {
|
||||||
NDA_MASTER,
|
NDA_MASTER,
|
||||||
NDA_LINK_NETNSID,
|
NDA_LINK_NETNSID,
|
||||||
NDA_SRC_VNI,
|
NDA_SRC_VNI,
|
||||||
|
NDA_PROTOCOL, /* Originator of entry */
|
||||||
__NDA_MAX
|
__NDA_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ enum {
|
||||||
NETNSA_NSID,
|
NETNSA_NSID,
|
||||||
NETNSA_PID,
|
NETNSA_PID,
|
||||||
NETNSA_FD,
|
NETNSA_FD,
|
||||||
|
NETNSA_TARGET_NSID,
|
||||||
|
NETNSA_CURRENT_NSID,
|
||||||
__NETNSA_MAX,
|
__NETNSA_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,10 +33,6 @@
|
||||||
#define NF_DROP_ERR(x) (((-x) << 16) | NF_DROP)
|
#define NF_DROP_ERR(x) (((-x) << 16) | NF_DROP)
|
||||||
|
|
||||||
/* only for userspace compatibility */
|
/* only for userspace compatibility */
|
||||||
/* Generic cache responses from hook functions.
|
|
||||||
<= 0x2000 is used for protocol-flags. */
|
|
||||||
#define NFC_UNKNOWN 0x4000
|
|
||||||
#define NFC_ALTERED 0x8000
|
|
||||||
|
|
||||||
/* NF_VERDICT_BITS should be 8 now, but userspace might break if this changes */
|
/* NF_VERDICT_BITS should be 8 now, but userspace might break if this changes */
|
||||||
#define NF_VERDICT_BITS 16
|
#define NF_VERDICT_BITS 16
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,9 @@
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
/* The protocol version */
|
/* The protocol versions */
|
||||||
#define IPSET_PROTOCOL 6
|
#define IPSET_PROTOCOL 7
|
||||||
|
#define IPSET_PROTOCOL_MIN 6
|
||||||
|
|
||||||
/* The max length of strings including NUL: set and type identifiers */
|
/* The max length of strings including NUL: set and type identifiers */
|
||||||
#define IPSET_MAXNAMELEN 32
|
#define IPSET_MAXNAMELEN 32
|
||||||
|
|
@ -38,17 +39,19 @@ enum ipset_cmd {
|
||||||
IPSET_CMD_TEST, /* 11: Test an element in a set */
|
IPSET_CMD_TEST, /* 11: Test an element in a set */
|
||||||
IPSET_CMD_HEADER, /* 12: Get set header data only */
|
IPSET_CMD_HEADER, /* 12: Get set header data only */
|
||||||
IPSET_CMD_TYPE, /* 13: Get set type */
|
IPSET_CMD_TYPE, /* 13: Get set type */
|
||||||
|
IPSET_CMD_GET_BYNAME, /* 14: Get set index by name */
|
||||||
|
IPSET_CMD_GET_BYINDEX, /* 15: Get set name by index */
|
||||||
IPSET_MSG_MAX, /* Netlink message commands */
|
IPSET_MSG_MAX, /* Netlink message commands */
|
||||||
|
|
||||||
/* Commands in userspace: */
|
/* Commands in userspace: */
|
||||||
IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* 14: Enter restore mode */
|
IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* 16: Enter restore mode */
|
||||||
IPSET_CMD_HELP, /* 15: Get help */
|
IPSET_CMD_HELP, /* 17: Get help */
|
||||||
IPSET_CMD_VERSION, /* 16: Get program version */
|
IPSET_CMD_VERSION, /* 18: Get program version */
|
||||||
IPSET_CMD_QUIT, /* 17: Quit from interactive mode */
|
IPSET_CMD_QUIT, /* 19: Quit from interactive mode */
|
||||||
|
|
||||||
IPSET_CMD_MAX,
|
IPSET_CMD_MAX,
|
||||||
|
|
||||||
IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* 18: Commit buffered commands */
|
IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* 20: Commit buffered commands */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Attributes at command level */
|
/* Attributes at command level */
|
||||||
|
|
@ -66,6 +69,7 @@ enum {
|
||||||
IPSET_ATTR_LINENO, /* 9: Restore lineno */
|
IPSET_ATTR_LINENO, /* 9: Restore lineno */
|
||||||
IPSET_ATTR_PROTOCOL_MIN, /* 10: Minimal supported version number */
|
IPSET_ATTR_PROTOCOL_MIN, /* 10: Minimal supported version number */
|
||||||
IPSET_ATTR_REVISION_MIN = IPSET_ATTR_PROTOCOL_MIN, /* type rev min */
|
IPSET_ATTR_REVISION_MIN = IPSET_ATTR_PROTOCOL_MIN, /* type rev min */
|
||||||
|
IPSET_ATTR_INDEX, /* 11: Kernel index of set */
|
||||||
__IPSET_ATTR_CMD_MAX,
|
__IPSET_ATTR_CMD_MAX,
|
||||||
};
|
};
|
||||||
#define IPSET_ATTR_CMD_MAX (__IPSET_ATTR_CMD_MAX - 1)
|
#define IPSET_ATTR_CMD_MAX (__IPSET_ATTR_CMD_MAX - 1)
|
||||||
|
|
@ -223,6 +227,7 @@ enum ipset_adt {
|
||||||
|
|
||||||
/* Sets are identified by an index in kernel space. Tweak with ip_set_id_t
|
/* Sets are identified by an index in kernel space. Tweak with ip_set_id_t
|
||||||
* and IPSET_INVALID_ID if you want to increase the max number of sets.
|
* and IPSET_INVALID_ID if you want to increase the max number of sets.
|
||||||
|
* Also, IPSET_ATTR_INDEX must be changed.
|
||||||
*/
|
*/
|
||||||
typedef __u16 ip_set_id_t;
|
typedef __u16 ip_set_id_t;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,34 +12,6 @@
|
||||||
|
|
||||||
#include <limits.h> /* for INT_MIN, INT_MAX */
|
#include <limits.h> /* for INT_MIN, INT_MAX */
|
||||||
|
|
||||||
/* IP Cache bits. */
|
|
||||||
/* Src IP address. */
|
|
||||||
#define NFC_IP_SRC 0x0001
|
|
||||||
/* Dest IP address. */
|
|
||||||
#define NFC_IP_DST 0x0002
|
|
||||||
/* Input device. */
|
|
||||||
#define NFC_IP_IF_IN 0x0004
|
|
||||||
/* Output device. */
|
|
||||||
#define NFC_IP_IF_OUT 0x0008
|
|
||||||
/* TOS. */
|
|
||||||
#define NFC_IP_TOS 0x0010
|
|
||||||
/* Protocol. */
|
|
||||||
#define NFC_IP_PROTO 0x0020
|
|
||||||
/* IP options. */
|
|
||||||
#define NFC_IP_OPTIONS 0x0040
|
|
||||||
/* Frag & flags. */
|
|
||||||
#define NFC_IP_FRAG 0x0080
|
|
||||||
|
|
||||||
/* Per-protocol information: only matters if proto match. */
|
|
||||||
/* TCP flags. */
|
|
||||||
#define NFC_IP_TCPFLAGS 0x0100
|
|
||||||
/* Source port. */
|
|
||||||
#define NFC_IP_SRC_PT 0x0200
|
|
||||||
/* Dest port. */
|
|
||||||
#define NFC_IP_DST_PT 0x0400
|
|
||||||
/* Something else about the proto */
|
|
||||||
#define NFC_IP_PROTO_UNKNOWN 0x2000
|
|
||||||
|
|
||||||
/* IP Hooks */
|
/* IP Hooks */
|
||||||
/* After promisc drops, checksum checks. */
|
/* After promisc drops, checksum checks. */
|
||||||
#define NF_IP_PRE_ROUTING 0
|
#define NF_IP_PRE_ROUTING 0
|
||||||
|
|
|
||||||
|
|
@ -15,35 +15,6 @@
|
||||||
|
|
||||||
#include <limits.h> /* for INT_MIN, INT_MAX */
|
#include <limits.h> /* for INT_MIN, INT_MAX */
|
||||||
|
|
||||||
/* IP Cache bits. */
|
|
||||||
/* Src IP address. */
|
|
||||||
#define NFC_IP6_SRC 0x0001
|
|
||||||
/* Dest IP address. */
|
|
||||||
#define NFC_IP6_DST 0x0002
|
|
||||||
/* Input device. */
|
|
||||||
#define NFC_IP6_IF_IN 0x0004
|
|
||||||
/* Output device. */
|
|
||||||
#define NFC_IP6_IF_OUT 0x0008
|
|
||||||
/* TOS. */
|
|
||||||
#define NFC_IP6_TOS 0x0010
|
|
||||||
/* Protocol. */
|
|
||||||
#define NFC_IP6_PROTO 0x0020
|
|
||||||
/* IP options. */
|
|
||||||
#define NFC_IP6_OPTIONS 0x0040
|
|
||||||
/* Frag & flags. */
|
|
||||||
#define NFC_IP6_FRAG 0x0080
|
|
||||||
|
|
||||||
|
|
||||||
/* Per-protocol information: only matters if proto match. */
|
|
||||||
/* TCP flags. */
|
|
||||||
#define NFC_IP6_TCPFLAGS 0x0100
|
|
||||||
/* Source port. */
|
|
||||||
#define NFC_IP6_SRC_PT 0x0200
|
|
||||||
/* Dest port. */
|
|
||||||
#define NFC_IP6_DST_PT 0x0400
|
|
||||||
/* Something else about the proto */
|
|
||||||
#define NFC_IP6_PROTO_UNKNOWN 0x2000
|
|
||||||
|
|
||||||
/* IP6 Hooks */
|
/* IP6 Hooks */
|
||||||
/* After promisc drops, checksum checks. */
|
/* After promisc drops, checksum checks. */
|
||||||
#define NF_IP6_PRE_ROUTING 0
|
#define NF_IP6_PRE_ROUTING 0
|
||||||
|
|
|
||||||
|
|
@ -485,6 +485,11 @@ enum {
|
||||||
|
|
||||||
TCA_FLOWER_IN_HW_COUNT,
|
TCA_FLOWER_IN_HW_COUNT,
|
||||||
|
|
||||||
|
TCA_FLOWER_KEY_PORT_SRC_MIN, /* be16 */
|
||||||
|
TCA_FLOWER_KEY_PORT_SRC_MAX, /* be16 */
|
||||||
|
TCA_FLOWER_KEY_PORT_DST_MIN, /* be16 */
|
||||||
|
TCA_FLOWER_KEY_PORT_DST_MAX, /* be16 */
|
||||||
|
|
||||||
__TCA_FLOWER_MAX,
|
__TCA_FLOWER_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -518,6 +523,8 @@ enum {
|
||||||
TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST = (1 << 1),
|
TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST = (1 << 1),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define TCA_FLOWER_MASK_FLAGS_RANGE (1 << 0) /* Range-based match */
|
||||||
|
|
||||||
/* Match-all classifier */
|
/* Match-all classifier */
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
|
||||||
|
|
@ -291,11 +291,38 @@ enum {
|
||||||
TCA_GRED_DPS,
|
TCA_GRED_DPS,
|
||||||
TCA_GRED_MAX_P,
|
TCA_GRED_MAX_P,
|
||||||
TCA_GRED_LIMIT,
|
TCA_GRED_LIMIT,
|
||||||
|
TCA_GRED_VQ_LIST, /* nested TCA_GRED_VQ_ENTRY */
|
||||||
__TCA_GRED_MAX,
|
__TCA_GRED_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TCA_GRED_MAX (__TCA_GRED_MAX - 1)
|
#define TCA_GRED_MAX (__TCA_GRED_MAX - 1)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TCA_GRED_VQ_ENTRY_UNSPEC,
|
||||||
|
TCA_GRED_VQ_ENTRY, /* nested TCA_GRED_VQ_* */
|
||||||
|
__TCA_GRED_VQ_ENTRY_MAX,
|
||||||
|
};
|
||||||
|
#define TCA_GRED_VQ_ENTRY_MAX (__TCA_GRED_VQ_ENTRY_MAX - 1)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TCA_GRED_VQ_UNSPEC,
|
||||||
|
TCA_GRED_VQ_PAD,
|
||||||
|
TCA_GRED_VQ_DP, /* u32 */
|
||||||
|
TCA_GRED_VQ_STAT_BYTES, /* u64 */
|
||||||
|
TCA_GRED_VQ_STAT_PACKETS, /* u32 */
|
||||||
|
TCA_GRED_VQ_STAT_BACKLOG, /* u32 */
|
||||||
|
TCA_GRED_VQ_STAT_PROB_DROP, /* u32 */
|
||||||
|
TCA_GRED_VQ_STAT_PROB_MARK, /* u32 */
|
||||||
|
TCA_GRED_VQ_STAT_FORCED_DROP, /* u32 */
|
||||||
|
TCA_GRED_VQ_STAT_FORCED_MARK, /* u32 */
|
||||||
|
TCA_GRED_VQ_STAT_PDROP, /* u32 */
|
||||||
|
TCA_GRED_VQ_STAT_OTHER, /* u32 */
|
||||||
|
TCA_GRED_VQ_FLAGS, /* u32 */
|
||||||
|
__TCA_GRED_VQ_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
#define TCA_GRED_VQ_MAX (__TCA_GRED_VQ_MAX - 1)
|
||||||
|
|
||||||
struct tc_gred_qopt {
|
struct tc_gred_qopt {
|
||||||
__u32 limit; /* HARD maximal queue length (bytes) */
|
__u32 limit; /* HARD maximal queue length (bytes) */
|
||||||
__u32 qth_min; /* Min average length threshold (bytes) */
|
__u32 qth_min; /* Min average length threshold (bytes) */
|
||||||
|
|
@ -864,6 +891,8 @@ enum {
|
||||||
|
|
||||||
TCA_FQ_LOW_RATE_THRESHOLD, /* per packet delay under this rate */
|
TCA_FQ_LOW_RATE_THRESHOLD, /* per packet delay under this rate */
|
||||||
|
|
||||||
|
TCA_FQ_CE_THRESHOLD, /* DCTCP-like CE-marking threshold */
|
||||||
|
|
||||||
__TCA_FQ_MAX
|
__TCA_FQ_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -882,6 +911,7 @@ struct tc_fq_qd_stats {
|
||||||
__u32 inactive_flows;
|
__u32 inactive_flows;
|
||||||
__u32 throttled_flows;
|
__u32 throttled_flows;
|
||||||
__u32 unthrottle_latency_ns;
|
__u32 unthrottle_latency_ns;
|
||||||
|
__u64 ce_mark; /* packets above ce_threshold */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Heavy-Hitter Filter */
|
/* Heavy-Hitter Filter */
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,7 @@ typedef __s32 sctp_assoc_t;
|
||||||
#define SCTP_STREAM_SCHEDULER_VALUE 124
|
#define SCTP_STREAM_SCHEDULER_VALUE 124
|
||||||
#define SCTP_INTERLEAVING_SUPPORTED 125
|
#define SCTP_INTERLEAVING_SUPPORTED 125
|
||||||
#define SCTP_SENDMSG_CONNECT 126
|
#define SCTP_SENDMSG_CONNECT 126
|
||||||
|
#define SCTP_EVENT 127
|
||||||
|
|
||||||
/* PR-SCTP policies */
|
/* PR-SCTP policies */
|
||||||
#define SCTP_PR_SCTP_NONE 0x0000
|
#define SCTP_PR_SCTP_NONE 0x0000
|
||||||
|
|
@ -632,7 +633,9 @@ union sctp_notification {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum sctp_sn_type {
|
enum sctp_sn_type {
|
||||||
SCTP_SN_TYPE_BASE = (1<<15),
|
SCTP_SN_TYPE_BASE = (1<<15),
|
||||||
|
SCTP_DATA_IO_EVENT = SCTP_SN_TYPE_BASE,
|
||||||
|
#define SCTP_DATA_IO_EVENT SCTP_DATA_IO_EVENT
|
||||||
SCTP_ASSOC_CHANGE,
|
SCTP_ASSOC_CHANGE,
|
||||||
#define SCTP_ASSOC_CHANGE SCTP_ASSOC_CHANGE
|
#define SCTP_ASSOC_CHANGE SCTP_ASSOC_CHANGE
|
||||||
SCTP_PEER_ADDR_CHANGE,
|
SCTP_PEER_ADDR_CHANGE,
|
||||||
|
|
@ -657,6 +660,8 @@ enum sctp_sn_type {
|
||||||
#define SCTP_ASSOC_RESET_EVENT SCTP_ASSOC_RESET_EVENT
|
#define SCTP_ASSOC_RESET_EVENT SCTP_ASSOC_RESET_EVENT
|
||||||
SCTP_STREAM_CHANGE_EVENT,
|
SCTP_STREAM_CHANGE_EVENT,
|
||||||
#define SCTP_STREAM_CHANGE_EVENT SCTP_STREAM_CHANGE_EVENT
|
#define SCTP_STREAM_CHANGE_EVENT SCTP_STREAM_CHANGE_EVENT
|
||||||
|
SCTP_SN_TYPE_MAX = SCTP_STREAM_CHANGE_EVENT,
|
||||||
|
#define SCTP_SN_TYPE_MAX SCTP_SN_TYPE_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Notification error codes used to fill up the error fields in some
|
/* Notification error codes used to fill up the error fields in some
|
||||||
|
|
@ -1144,6 +1149,12 @@ struct sctp_add_streams {
|
||||||
uint16_t sas_outstrms;
|
uint16_t sas_outstrms;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct sctp_event {
|
||||||
|
sctp_assoc_t se_assoc_id;
|
||||||
|
uint16_t se_type;
|
||||||
|
uint8_t se_on;
|
||||||
|
};
|
||||||
|
|
||||||
/* SCTP Stream schedulers */
|
/* SCTP Stream schedulers */
|
||||||
enum sctp_sched_type {
|
enum sctp_sched_type {
|
||||||
SCTP_SS_FCFS,
|
SCTP_SS_FCFS,
|
||||||
|
|
|
||||||
|
|
@ -243,6 +243,7 @@ enum
|
||||||
LINUX_MIB_TCPREQQFULLDROP, /* TCPReqQFullDrop */
|
LINUX_MIB_TCPREQQFULLDROP, /* TCPReqQFullDrop */
|
||||||
LINUX_MIB_TCPRETRANSFAIL, /* TCPRetransFail */
|
LINUX_MIB_TCPRETRANSFAIL, /* TCPRetransFail */
|
||||||
LINUX_MIB_TCPRCVCOALESCE, /* TCPRcvCoalesce */
|
LINUX_MIB_TCPRCVCOALESCE, /* TCPRcvCoalesce */
|
||||||
|
LINUX_MIB_TCPBACKLOGCOALESCE, /* TCPBacklogCoalesce */
|
||||||
LINUX_MIB_TCPOFOQUEUE, /* TCPOFOQueue */
|
LINUX_MIB_TCPOFOQUEUE, /* TCPOFOQueue */
|
||||||
LINUX_MIB_TCPOFODROP, /* TCPOFODrop */
|
LINUX_MIB_TCPOFODROP, /* TCPOFODrop */
|
||||||
LINUX_MIB_TCPOFOMERGE, /* TCPOFOMerge */
|
LINUX_MIB_TCPOFOMERGE, /* TCPOFOMerge */
|
||||||
|
|
|
||||||
|
|
@ -266,6 +266,7 @@ enum {
|
||||||
TCP_NLA_BYTES_RETRANS, /* Data bytes retransmitted */
|
TCP_NLA_BYTES_RETRANS, /* Data bytes retransmitted */
|
||||||
TCP_NLA_DSACK_DUPS, /* DSACK blocks received */
|
TCP_NLA_DSACK_DUPS, /* DSACK blocks received */
|
||||||
TCP_NLA_REORD_SEEN, /* reordering events seen */
|
TCP_NLA_REORD_SEEN, /* reordering events seen */
|
||||||
|
TCP_NLA_SRTT, /* smoothed RTT in usecs */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* for TCP_MD5SIG socket option */
|
/* for TCP_MD5SIG socket option */
|
||||||
|
|
|
||||||
|
|
@ -116,13 +116,6 @@ struct dn_naddr
|
||||||
unsigned char a_addr[DN_MAXADDL];
|
unsigned char a_addr[DN_MAXADDL];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IPX_NODE_LEN 6
|
|
||||||
|
|
||||||
struct ipx_addr {
|
|
||||||
u_int32_t ipx_net;
|
|
||||||
u_int8_t ipx_node[IPX_NODE_LEN];
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifndef AF_MPLS
|
#ifndef AF_MPLS
|
||||||
# define AF_MPLS 28
|
# define AF_MPLS 28
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -201,12 +194,6 @@ int matches(const char *arg, const char *pattern);
|
||||||
int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits);
|
int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits);
|
||||||
int inet_addr_match_rta(const inet_prefix *m, const struct rtattr *rta);
|
int inet_addr_match_rta(const inet_prefix *m, const struct rtattr *rta);
|
||||||
|
|
||||||
const char *dnet_ntop(int af, const void *addr, char *str, size_t len);
|
|
||||||
int dnet_pton(int af, const char *src, void *addr);
|
|
||||||
|
|
||||||
const char *ipx_ntop(int af, const void *addr, char *str, size_t len);
|
|
||||||
int ipx_pton(int af, const char *src, void *addr);
|
|
||||||
|
|
||||||
const char *mpls_ntop(int af, const void *addr, char *str, size_t len);
|
const char *mpls_ntop(int af, const void *addr, char *str, size_t len);
|
||||||
int mpls_pton(int af, const char *src, void *addr, size_t alen);
|
int mpls_pton(int af, const char *src, void *addr, size_t alen);
|
||||||
|
|
||||||
|
|
|
||||||
6
ip/ip.c
6
ip/ip.c
|
|
@ -53,7 +53,7 @@ static void usage(void)
|
||||||
" vrf | sr }\n"
|
" vrf | sr }\n"
|
||||||
" OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
|
" OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
|
||||||
" -h[uman-readable] | -iec | -j[son] | -p[retty] |\n"
|
" -h[uman-readable] | -iec | -j[son] | -p[retty] |\n"
|
||||||
" -f[amily] { inet | inet6 | ipx | dnet | mpls | bridge | link } |\n"
|
" -f[amily] { inet | inet6 | mpls | bridge | link } |\n"
|
||||||
" -4 | -6 | -I | -D | -M | -B | -0 |\n"
|
" -4 | -6 | -I | -D | -M | -B | -0 |\n"
|
||||||
" -l[oops] { maximum-addr-flush-attempts } | -br[ief] |\n"
|
" -l[oops] { maximum-addr-flush-attempts } | -br[ief] |\n"
|
||||||
" -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |\n"
|
" -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |\n"
|
||||||
|
|
@ -225,8 +225,6 @@ int main(int argc, char **argv)
|
||||||
preferred_family = AF_INET6;
|
preferred_family = AF_INET6;
|
||||||
} else if (strcmp(opt, "-0") == 0) {
|
} else if (strcmp(opt, "-0") == 0) {
|
||||||
preferred_family = AF_PACKET;
|
preferred_family = AF_PACKET;
|
||||||
} else if (strcmp(opt, "-I") == 0) {
|
|
||||||
preferred_family = AF_IPX;
|
|
||||||
} else if (strcmp(opt, "-D") == 0) {
|
} else if (strcmp(opt, "-D") == 0) {
|
||||||
preferred_family = AF_DECnet;
|
preferred_family = AF_DECnet;
|
||||||
} else if (strcmp(opt, "-M") == 0) {
|
} else if (strcmp(opt, "-M") == 0) {
|
||||||
|
|
@ -310,6 +308,8 @@ int main(int argc, char **argv)
|
||||||
if (rtnl_open(&rth, 0) < 0)
|
if (rtnl_open(&rth, 0) < 0)
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
|
rtnl_set_strict_dump(&rth);
|
||||||
|
|
||||||
if (strlen(basename) > 2)
|
if (strlen(basename) > 2)
|
||||||
return do_cmd(basename+2, argc, argv);
|
return do_cmd(basename+2, argc, argv);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,8 +84,7 @@ int do_seg6(int argc, char **argv);
|
||||||
int iplink_get(char *name, __u32 filt_mask);
|
int iplink_get(char *name, __u32 filt_mask);
|
||||||
int iplink_ifla_xstats(int argc, char **argv);
|
int iplink_ifla_xstats(int argc, char **argv);
|
||||||
|
|
||||||
int ip_linkaddr_list(int family, req_filter_fn_t filter_fn,
|
int ip_link_list(req_filter_fn_t filter_fn, struct nlmsg_chain *linfo);
|
||||||
struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo);
|
|
||||||
void free_nlmsg_chain(struct nlmsg_chain *info);
|
void free_nlmsg_chain(struct nlmsg_chain *info);
|
||||||
|
|
||||||
static inline int rtm_get_table(struct rtmsg *r, struct rtattr **tb)
|
static inline int rtm_get_table(struct rtmsg *r, struct rtattr **tb)
|
||||||
|
|
|
||||||
|
|
@ -1679,6 +1679,15 @@ static void ipaddr_filter(struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ipaddr_dump_filter(struct nlmsghdr *nlh, int reqlen)
|
||||||
|
{
|
||||||
|
struct ifaddrmsg *ifa = NLMSG_DATA(nlh);
|
||||||
|
|
||||||
|
ifa->ifa_index = filter.ifindex;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int ipaddr_flush(void)
|
static int ipaddr_flush(void)
|
||||||
{
|
{
|
||||||
int round = 0;
|
int round = 0;
|
||||||
|
|
@ -1689,7 +1698,8 @@ static int ipaddr_flush(void)
|
||||||
filter.flushe = sizeof(flushb);
|
filter.flushe = sizeof(flushb);
|
||||||
|
|
||||||
while ((max_flush_loops == 0) || (round < max_flush_loops)) {
|
while ((max_flush_loops == 0) || (round < max_flush_loops)) {
|
||||||
if (rtnl_addrdump_req(&rth, filter.family) < 0) {
|
if (rtnl_addrdump_req(&rth, filter.family,
|
||||||
|
ipaddr_dump_filter) < 0) {
|
||||||
perror("Cannot send dump request");
|
perror("Cannot send dump request");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
@ -1762,12 +1772,41 @@ static int iplink_filter_req(struct nlmsghdr *nlh, int reqlen)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ipaddr_link_get(int index, struct nlmsg_chain *linfo)
|
||||||
|
{
|
||||||
|
struct iplink_req req = {
|
||||||
|
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
|
||||||
|
.n.nlmsg_flags = NLM_F_REQUEST,
|
||||||
|
.n.nlmsg_type = RTM_GETLINK,
|
||||||
|
.i.ifi_family = filter.family,
|
||||||
|
.i.ifi_index = index,
|
||||||
|
};
|
||||||
|
__u32 filt_mask = RTEXT_FILTER_VF;
|
||||||
|
struct nlmsghdr *answer;
|
||||||
|
|
||||||
|
if (!show_stats)
|
||||||
|
filt_mask |= RTEXT_FILTER_SKIP_STATS;
|
||||||
|
|
||||||
|
addattr32(&req.n, sizeof(req), IFLA_EXT_MASK, filt_mask);
|
||||||
|
|
||||||
|
if (rtnl_talk(&rth, &req.n, &answer) < 0) {
|
||||||
|
perror("Cannot send link request");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store_nlmsg(answer, linfo) < 0) {
|
||||||
|
fprintf(stderr, "Failed to process link information\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* fills in linfo with link data and optionally ainfo with address info
|
/* fills in linfo with link data and optionally ainfo with address info
|
||||||
* caller can walk lists as desired and must call free_nlmsg_chain for
|
* caller can walk lists as desired and must call free_nlmsg_chain for
|
||||||
* both when done
|
* both when done
|
||||||
*/
|
*/
|
||||||
int ip_linkaddr_list(int family, req_filter_fn_t filter_fn,
|
int ip_link_list(req_filter_fn_t filter_fn, struct nlmsg_chain *linfo)
|
||||||
struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo)
|
|
||||||
{
|
{
|
||||||
if (rtnl_linkdump_req_filter_fn(&rth, preferred_family,
|
if (rtnl_linkdump_req_filter_fn(&rth, preferred_family,
|
||||||
filter_fn) < 0) {
|
filter_fn) < 0) {
|
||||||
|
|
@ -1780,16 +1819,19 @@ int ip_linkaddr_list(int family, req_filter_fn_t filter_fn,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ainfo) {
|
return 0;
|
||||||
if (rtnl_addrdump_req(&rth, family) < 0) {
|
}
|
||||||
perror("Cannot send dump request");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rtnl_dump_filter(&rth, store_nlmsg, ainfo) < 0) {
|
static int ip_addr_list(struct nlmsg_chain *ainfo)
|
||||||
fprintf(stderr, "Dump terminated\n");
|
{
|
||||||
return 1;
|
if (rtnl_addrdump_req(&rth, filter.family, ipaddr_dump_filter) < 0) {
|
||||||
}
|
perror("Cannot send dump request");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rtnl_dump_filter(&rth, store_nlmsg, ainfo) < 0) {
|
||||||
|
fprintf(stderr, "Dump terminated\n");
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -1798,7 +1840,7 @@ int ip_linkaddr_list(int family, req_filter_fn_t filter_fn,
|
||||||
static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
|
static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
|
||||||
{
|
{
|
||||||
struct nlmsg_chain linfo = { NULL, NULL};
|
struct nlmsg_chain linfo = { NULL, NULL};
|
||||||
struct nlmsg_chain _ainfo = { NULL, NULL}, *ainfo = NULL;
|
struct nlmsg_chain _ainfo = { NULL, NULL}, *ainfo = &_ainfo;
|
||||||
struct nlmsg_list *l;
|
struct nlmsg_list *l;
|
||||||
char *filter_dev = NULL;
|
char *filter_dev = NULL;
|
||||||
int no_link = 0;
|
int no_link = 0;
|
||||||
|
|
@ -1906,7 +1948,8 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
|
||||||
if (ipadd_save_prep())
|
if (ipadd_save_prep())
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
if (rtnl_addrdump_req(&rth, preferred_family) < 0) {
|
if (rtnl_addrdump_req(&rth, preferred_family,
|
||||||
|
ipaddr_dump_filter) < 0) {
|
||||||
perror("Cannot send dump request");
|
perror("Cannot send dump request");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
@ -1940,19 +1983,23 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filter.family != AF_PACKET) {
|
if (filter.ifindex) {
|
||||||
ainfo = &_ainfo;
|
if (ipaddr_link_get(filter.ifindex, &linfo) != 0)
|
||||||
|
goto out;
|
||||||
if (filter.oneline)
|
} else {
|
||||||
no_link = 1;
|
if (ip_link_list(iplink_filter_req, &linfo) != 0)
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ip_linkaddr_list(filter.family, iplink_filter_req,
|
if (filter.family != AF_PACKET) {
|
||||||
&linfo, ainfo) != 0)
|
if (filter.oneline)
|
||||||
goto out;
|
no_link = 1;
|
||||||
|
|
||||||
|
if (ip_addr_list(ainfo) != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (filter.family != AF_PACKET)
|
|
||||||
ipaddr_filter(&linfo, ainfo);
|
ipaddr_filter(&linfo, ainfo);
|
||||||
|
}
|
||||||
|
|
||||||
for (l = linfo.head; l; l = l->next) {
|
for (l = linfo.head; l; l = l->next) {
|
||||||
struct nlmsghdr *n = &l->h;
|
struct nlmsghdr *n = &l->h;
|
||||||
|
|
@ -1971,8 +2018,7 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (ainfo)
|
free_nlmsg_chain(ainfo);
|
||||||
free_nlmsg_chain(ainfo);
|
|
||||||
free_nlmsg_chain(&linfo);
|
free_nlmsg_chain(&linfo);
|
||||||
delete_json_obj();
|
delete_json_obj();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ static void print_explain(FILE *f)
|
||||||
" remote ADDR\n"
|
" remote ADDR\n"
|
||||||
" [ ttl TTL ]\n"
|
" [ ttl TTL ]\n"
|
||||||
" [ tos TOS ]\n"
|
" [ tos TOS ]\n"
|
||||||
|
" [ df DF ]\n"
|
||||||
" [ flowlabel LABEL ]\n"
|
" [ flowlabel LABEL ]\n"
|
||||||
" [ dstport PORT ]\n"
|
" [ dstport PORT ]\n"
|
||||||
" [ [no]external ]\n"
|
" [ [no]external ]\n"
|
||||||
|
|
@ -35,6 +36,7 @@ static void print_explain(FILE *f)
|
||||||
" ADDR := IP_ADDRESS\n"
|
" ADDR := IP_ADDRESS\n"
|
||||||
" TOS := { NUMBER | inherit }\n"
|
" TOS := { NUMBER | inherit }\n"
|
||||||
" TTL := { 1..255 | auto | inherit }\n"
|
" TTL := { 1..255 | auto | inherit }\n"
|
||||||
|
" DF := { unset | set | inherit }\n"
|
||||||
" LABEL := 0-1048575\n"
|
" LABEL := 0-1048575\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -115,6 +117,22 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv,
|
||||||
tos = uval;
|
tos = uval;
|
||||||
} else
|
} else
|
||||||
tos = 1;
|
tos = 1;
|
||||||
|
} else if (!matches(*argv, "df")) {
|
||||||
|
enum ifla_geneve_df df;
|
||||||
|
|
||||||
|
NEXT_ARG();
|
||||||
|
check_duparg(&attrs, IFLA_GENEVE_DF, "df", *argv);
|
||||||
|
if (strcmp(*argv, "unset") == 0)
|
||||||
|
df = GENEVE_DF_UNSET;
|
||||||
|
else if (strcmp(*argv, "set") == 0)
|
||||||
|
df = GENEVE_DF_SET;
|
||||||
|
else if (strcmp(*argv, "inherit") == 0)
|
||||||
|
df = GENEVE_DF_INHERIT;
|
||||||
|
else
|
||||||
|
invarg("DF must be 'unset', 'set' or 'inherit'",
|
||||||
|
*argv);
|
||||||
|
|
||||||
|
addattr8(n, 1024, IFLA_GENEVE_DF, df);
|
||||||
} else if (!matches(*argv, "label") ||
|
} else if (!matches(*argv, "label") ||
|
||||||
!matches(*argv, "flowlabel")) {
|
!matches(*argv, "flowlabel")) {
|
||||||
__u32 uval;
|
__u32 uval;
|
||||||
|
|
@ -287,6 +305,17 @@ static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
||||||
print_string(PRINT_FP, NULL, "tos %s ", "inherit");
|
print_string(PRINT_FP, NULL, "tos %s ", "inherit");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tb[IFLA_GENEVE_DF]) {
|
||||||
|
enum ifla_geneve_df df = rta_getattr_u8(tb[IFLA_GENEVE_DF]);
|
||||||
|
|
||||||
|
if (df == GENEVE_DF_UNSET)
|
||||||
|
print_string(PRINT_JSON, "df", "df %s ", "unset");
|
||||||
|
else if (df == GENEVE_DF_SET)
|
||||||
|
print_string(PRINT_ANY, "df", "df %s ", "set");
|
||||||
|
else if (df == GENEVE_DF_INHERIT)
|
||||||
|
print_string(PRINT_ANY, "df", "df %s ", "inherit");
|
||||||
|
}
|
||||||
|
|
||||||
if (tb[IFLA_GENEVE_LABEL]) {
|
if (tb[IFLA_GENEVE_LABEL]) {
|
||||||
__u32 label = rta_getattr_u32(tb[IFLA_GENEVE_LABEL]);
|
__u32 label = rta_getattr_u32(tb[IFLA_GENEVE_LABEL]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ static void print_explain(FILE *f)
|
||||||
" [ local ADDR ]\n"
|
" [ local ADDR ]\n"
|
||||||
" [ ttl TTL ]\n"
|
" [ ttl TTL ]\n"
|
||||||
" [ tos TOS ]\n"
|
" [ tos TOS ]\n"
|
||||||
|
" [ df DF ]\n"
|
||||||
" [ flowlabel LABEL ]\n"
|
" [ flowlabel LABEL ]\n"
|
||||||
" [ dev PHYS_DEV ]\n"
|
" [ dev PHYS_DEV ]\n"
|
||||||
" [ dstport PORT ]\n"
|
" [ dstport PORT ]\n"
|
||||||
|
|
@ -52,6 +53,7 @@ static void print_explain(FILE *f)
|
||||||
" ADDR := { IP_ADDRESS | any }\n"
|
" ADDR := { IP_ADDRESS | any }\n"
|
||||||
" TOS := { NUMBER | inherit }\n"
|
" TOS := { NUMBER | inherit }\n"
|
||||||
" TTL := { 1..255 | auto | inherit }\n"
|
" TTL := { 1..255 | auto | inherit }\n"
|
||||||
|
" DF := { unset | set | inherit }\n"
|
||||||
" LABEL := 0-1048575\n"
|
" LABEL := 0-1048575\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -170,6 +172,22 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
|
||||||
} else
|
} else
|
||||||
tos = 1;
|
tos = 1;
|
||||||
addattr8(n, 1024, IFLA_VXLAN_TOS, tos);
|
addattr8(n, 1024, IFLA_VXLAN_TOS, tos);
|
||||||
|
} else if (!matches(*argv, "df")) {
|
||||||
|
enum ifla_vxlan_df df;
|
||||||
|
|
||||||
|
NEXT_ARG();
|
||||||
|
check_duparg(&attrs, IFLA_VXLAN_DF, "df", *argv);
|
||||||
|
if (strcmp(*argv, "unset") == 0)
|
||||||
|
df = VXLAN_DF_UNSET;
|
||||||
|
else if (strcmp(*argv, "set") == 0)
|
||||||
|
df = VXLAN_DF_SET;
|
||||||
|
else if (strcmp(*argv, "inherit") == 0)
|
||||||
|
df = VXLAN_DF_INHERIT;
|
||||||
|
else
|
||||||
|
invarg("DF must be 'unset', 'set' or 'inherit'",
|
||||||
|
*argv);
|
||||||
|
|
||||||
|
addattr8(n, 1024, IFLA_VXLAN_DF, df);
|
||||||
} else if (!matches(*argv, "label") ||
|
} else if (!matches(*argv, "label") ||
|
||||||
!matches(*argv, "flowlabel")) {
|
!matches(*argv, "flowlabel")) {
|
||||||
__u32 uval;
|
__u32 uval;
|
||||||
|
|
@ -538,6 +556,17 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
||||||
print_string(PRINT_FP, NULL, "ttl %s ", "auto");
|
print_string(PRINT_FP, NULL, "ttl %s ", "auto");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tb[IFLA_VXLAN_DF]) {
|
||||||
|
enum ifla_vxlan_df df = rta_getattr_u8(tb[IFLA_VXLAN_DF]);
|
||||||
|
|
||||||
|
if (df == VXLAN_DF_UNSET)
|
||||||
|
print_string(PRINT_JSON, "df", "df %s ", "unset");
|
||||||
|
else if (df == VXLAN_DF_SET)
|
||||||
|
print_string(PRINT_ANY, "df", "df %s ", "set");
|
||||||
|
else if (df == VXLAN_DF_INHERIT)
|
||||||
|
print_string(PRINT_ANY, "df", "df %s ", "inherit");
|
||||||
|
}
|
||||||
|
|
||||||
if (tb[IFLA_VXLAN_LABEL]) {
|
if (tb[IFLA_VXLAN_LABEL]) {
|
||||||
__u32 label = rta_getattr_u32(tb[IFLA_VXLAN_LABEL]);
|
__u32 label = rta_getattr_u32(tb[IFLA_VXLAN_LABEL]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -220,21 +220,36 @@ void ipmroute_reset_filter(int ifindex)
|
||||||
filter.iif = ifindex;
|
filter.iif = ifindex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int iproute_dump_filter(struct nlmsghdr *nlh, int reqlen)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (filter.tb) {
|
||||||
|
err = addattr32(nlh, reqlen, RTA_TABLE, filter.tb);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int mroute_list(int argc, char **argv)
|
static int mroute_list(int argc, char **argv)
|
||||||
{
|
{
|
||||||
char *id = NULL;
|
char *id = NULL;
|
||||||
int family;
|
int family = preferred_family;
|
||||||
|
|
||||||
ipmroute_reset_filter(0);
|
ipmroute_reset_filter(0);
|
||||||
if (preferred_family == AF_UNSPEC)
|
if (family == AF_INET || family == AF_UNSPEC) {
|
||||||
family = AF_INET;
|
family = RTNL_FAMILY_IPMR;
|
||||||
else
|
|
||||||
family = AF_INET6;
|
|
||||||
if (family == AF_INET) {
|
|
||||||
filter.af = RTNL_FAMILY_IPMR;
|
filter.af = RTNL_FAMILY_IPMR;
|
||||||
filter.tb = RT_TABLE_DEFAULT; /* for backward compatibility */
|
filter.tb = RT_TABLE_DEFAULT; /* for backward compatibility */
|
||||||
} else
|
} else if (family == AF_INET6) {
|
||||||
|
family = RTNL_FAMILY_IP6MR;
|
||||||
filter.af = RTNL_FAMILY_IP6MR;
|
filter.af = RTNL_FAMILY_IP6MR;
|
||||||
|
} else {
|
||||||
|
/* family does not have multicast routing */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
filter.msrc.family = filter.mdst.family = family;
|
filter.msrc.family = filter.mdst.family = family;
|
||||||
|
|
||||||
|
|
@ -283,7 +298,7 @@ static int mroute_list(int argc, char **argv)
|
||||||
filter.iif = idx;
|
filter.iif = idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rtnl_routedump_req(&rth, filter.af) < 0) {
|
if (rtnl_routedump_req(&rth, filter.af, iproute_dump_filter) < 0) {
|
||||||
perror("Cannot send dump request");
|
perror("Cannot send dump request");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
81
ip/ipneigh.c
81
ip/ipneigh.c
|
|
@ -40,6 +40,8 @@ static struct
|
||||||
int flushp;
|
int flushp;
|
||||||
int flushe;
|
int flushe;
|
||||||
int master;
|
int master;
|
||||||
|
int protocol;
|
||||||
|
__u8 ndm_flags;
|
||||||
} filter;
|
} filter;
|
||||||
|
|
||||||
static void usage(void) __attribute__((noreturn));
|
static void usage(void) __attribute__((noreturn));
|
||||||
|
|
@ -48,7 +50,7 @@ static void usage(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: ip neigh { add | del | change | replace }\n"
|
fprintf(stderr, "Usage: ip neigh { add | del | change | replace }\n"
|
||||||
" { ADDR [ lladdr LLADDR ] [ nud STATE ] | proxy ADDR } [ dev DEV ]\n");
|
" { ADDR [ lladdr LLADDR ] [ nud STATE ] | proxy ADDR } [ dev DEV ]\n");
|
||||||
fprintf(stderr, " [ router ] [ extern_learn ]\n\n");
|
fprintf(stderr, " [ router ] [ extern_learn ] [ protocol PROTO ]\n\n");
|
||||||
fprintf(stderr, " ip neigh { show | flush } [ proxy ] [ to PREFIX ] [ dev DEV ] [ nud STATE ]\n");
|
fprintf(stderr, " ip neigh { show | flush } [ proxy ] [ to PREFIX ] [ dev DEV ] [ nud STATE ]\n");
|
||||||
fprintf(stderr, " [ vrf NAME ]\n\n");
|
fprintf(stderr, " [ vrf NAME ]\n\n");
|
||||||
fprintf(stderr, "STATE := { permanent | noarp | stale | reachable | none |\n"
|
fprintf(stderr, "STATE := { permanent | noarp | stale | reachable | none |\n"
|
||||||
|
|
@ -148,6 +150,14 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv)
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
dev = *argv;
|
dev = *argv;
|
||||||
dev_ok = 1;
|
dev_ok = 1;
|
||||||
|
} else if (matches(*argv, "protocol") == 0) {
|
||||||
|
__u32 proto;
|
||||||
|
|
||||||
|
NEXT_ARG();
|
||||||
|
if (rtnl_rtprot_a2n(&proto, *argv))
|
||||||
|
invarg("\"protocol\" value is invalid\n", *argv);
|
||||||
|
if (addattr8(&req.n, sizeof(req), NDA_PROTOCOL, proto))
|
||||||
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
if (strcmp(*argv, "to") == 0) {
|
if (strcmp(*argv, "to") == 0) {
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
|
|
@ -244,6 +254,7 @@ int print_neigh(struct nlmsghdr *n, void *arg)
|
||||||
int len = n->nlmsg_len;
|
int len = n->nlmsg_len;
|
||||||
struct rtattr *tb[NDA_MAX+1];
|
struct rtattr *tb[NDA_MAX+1];
|
||||||
static int logit = 1;
|
static int logit = 1;
|
||||||
|
__u8 protocol = 0;
|
||||||
|
|
||||||
if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH &&
|
if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH &&
|
||||||
n->nlmsg_type != RTM_GETNEIGH) {
|
n->nlmsg_type != RTM_GETNEIGH) {
|
||||||
|
|
@ -285,6 +296,12 @@ int print_neigh(struct nlmsghdr *n, void *arg)
|
||||||
if (inet_addr_match_rta(&filter.pfx, tb[NDA_DST]))
|
if (inet_addr_match_rta(&filter.pfx, tb[NDA_DST]))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (tb[NDA_PROTOCOL])
|
||||||
|
protocol = rta_getattr_u8(tb[NDA_PROTOCOL]);
|
||||||
|
|
||||||
|
if (filter.protocol && filter.protocol != protocol)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (filter.unused_only && tb[NDA_CACHEINFO]) {
|
if (filter.unused_only && tb[NDA_CACHEINFO]) {
|
||||||
struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
|
struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
|
||||||
|
|
||||||
|
|
@ -379,6 +396,13 @@ int print_neigh(struct nlmsghdr *n, void *arg)
|
||||||
if (r->ndm_state)
|
if (r->ndm_state)
|
||||||
print_neigh_state(r->ndm_state);
|
print_neigh_state(r->ndm_state);
|
||||||
|
|
||||||
|
if (protocol) {
|
||||||
|
SPRINT_BUF(b1);
|
||||||
|
|
||||||
|
print_string(PRINT_ANY, "protocol", " proto %s ",
|
||||||
|
rtnl_rtprot_n2a(protocol, b1, sizeof(b1)));
|
||||||
|
}
|
||||||
|
|
||||||
print_string(PRINT_FP, NULL, "\n", "");
|
print_string(PRINT_FP, NULL, "\n", "");
|
||||||
close_json_object();
|
close_json_object();
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
@ -393,16 +417,29 @@ void ipneigh_reset_filter(int ifindex)
|
||||||
filter.index = ifindex;
|
filter.index = ifindex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ipneigh_dump_filter(struct nlmsghdr *nlh, int reqlen)
|
||||||
|
{
|
||||||
|
struct ndmsg *ndm = NLMSG_DATA(nlh);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
ndm->ndm_flags = filter.ndm_flags;
|
||||||
|
|
||||||
|
if (filter.index) {
|
||||||
|
err = addattr32(nlh, reqlen, NDA_IFINDEX, filter.index);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (filter.master) {
|
||||||
|
err = addattr32(nlh, reqlen, NDA_MASTER, filter.master);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int do_show_or_flush(int argc, char **argv, int flush)
|
static int do_show_or_flush(int argc, char **argv, int flush)
|
||||||
{
|
{
|
||||||
struct {
|
|
||||||
struct nlmsghdr n;
|
|
||||||
struct ndmsg ndm;
|
|
||||||
char buf[256];
|
|
||||||
} req = {
|
|
||||||
.n.nlmsg_type = RTM_GETNEIGH,
|
|
||||||
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
|
|
||||||
};
|
|
||||||
char *filter_dev = NULL;
|
char *filter_dev = NULL;
|
||||||
int state_given = 0;
|
int state_given = 0;
|
||||||
|
|
||||||
|
|
@ -433,7 +470,6 @@ static int do_show_or_flush(int argc, char **argv, int flush)
|
||||||
ifindex = ll_name_to_index(*argv);
|
ifindex = ll_name_to_index(*argv);
|
||||||
if (!ifindex)
|
if (!ifindex)
|
||||||
invarg("Device does not exist\n", *argv);
|
invarg("Device does not exist\n", *argv);
|
||||||
addattr32(&req.n, sizeof(req), NDA_MASTER, ifindex);
|
|
||||||
filter.master = ifindex;
|
filter.master = ifindex;
|
||||||
} else if (strcmp(*argv, "vrf") == 0) {
|
} else if (strcmp(*argv, "vrf") == 0) {
|
||||||
int ifindex;
|
int ifindex;
|
||||||
|
|
@ -444,7 +480,6 @@ static int do_show_or_flush(int argc, char **argv, int flush)
|
||||||
invarg("Not a valid VRF name\n", *argv);
|
invarg("Not a valid VRF name\n", *argv);
|
||||||
if (!name_is_vrf(*argv))
|
if (!name_is_vrf(*argv))
|
||||||
invarg("Not a valid VRF name\n", *argv);
|
invarg("Not a valid VRF name\n", *argv);
|
||||||
addattr32(&req.n, sizeof(req), NDA_MASTER, ifindex);
|
|
||||||
filter.master = ifindex;
|
filter.master = ifindex;
|
||||||
} else if (strcmp(*argv, "unused") == 0) {
|
} else if (strcmp(*argv, "unused") == 0) {
|
||||||
filter.unused_only = 1;
|
filter.unused_only = 1;
|
||||||
|
|
@ -466,9 +501,19 @@ static int do_show_or_flush(int argc, char **argv, int flush)
|
||||||
if (state == 0)
|
if (state == 0)
|
||||||
state = 0x100;
|
state = 0x100;
|
||||||
filter.state |= state;
|
filter.state |= state;
|
||||||
} else if (strcmp(*argv, "proxy") == 0)
|
} else if (strcmp(*argv, "proxy") == 0) {
|
||||||
req.ndm.ndm_flags = NTF_PROXY;
|
filter.ndm_flags = NTF_PROXY;
|
||||||
else {
|
} else if (matches(*argv, "protocol") == 0) {
|
||||||
|
__u32 prot;
|
||||||
|
|
||||||
|
NEXT_ARG();
|
||||||
|
if (rtnl_rtprot_a2n(&prot, *argv)) {
|
||||||
|
if (strcmp(*argv, "all"))
|
||||||
|
invarg("invalid \"protocol\"\n", *argv);
|
||||||
|
prot = 0;
|
||||||
|
}
|
||||||
|
filter.protocol = prot;
|
||||||
|
} else {
|
||||||
if (strcmp(*argv, "to") == 0) {
|
if (strcmp(*argv, "to") == 0) {
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
}
|
}
|
||||||
|
|
@ -488,11 +533,8 @@ static int do_show_or_flush(int argc, char **argv, int flush)
|
||||||
filter.index = ll_name_to_index(filter_dev);
|
filter.index = ll_name_to_index(filter_dev);
|
||||||
if (!filter.index)
|
if (!filter.index)
|
||||||
return nodev(filter_dev);
|
return nodev(filter_dev);
|
||||||
addattr32(&req.n, sizeof(req), NDA_IFINDEX, filter.index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
req.ndm.ndm_family = filter.family;
|
|
||||||
|
|
||||||
if (flush) {
|
if (flush) {
|
||||||
int round = 0;
|
int round = 0;
|
||||||
char flushb[4096-512];
|
char flushb[4096-512];
|
||||||
|
|
@ -502,7 +544,8 @@ static int do_show_or_flush(int argc, char **argv, int flush)
|
||||||
filter.flushe = sizeof(flushb);
|
filter.flushe = sizeof(flushb);
|
||||||
|
|
||||||
while (round < MAX_ROUNDS) {
|
while (round < MAX_ROUNDS) {
|
||||||
if (rtnl_dump_request_n(&rth, &req.n) < 0) {
|
if (rtnl_neighdump_req(&rth, filter.family,
|
||||||
|
ipneigh_dump_filter) < 0) {
|
||||||
perror("Cannot send dump request");
|
perror("Cannot send dump request");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
@ -535,7 +578,7 @@ static int do_show_or_flush(int argc, char **argv, int flush)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rtnl_dump_request_n(&rth, &req.n) < 0) {
|
if (rtnl_neighdump_req(&rth, filter.family, ipneigh_dump_filter) < 0) {
|
||||||
perror("Cannot send dump request");
|
perror("Cannot send dump request");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
91
ip/iproute.c
91
ip/iproute.c
|
|
@ -83,7 +83,7 @@ static void usage(void)
|
||||||
"INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]...\n"
|
"INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]...\n"
|
||||||
"NH := [ encap ENCAPTYPE ENCAPHDR ] [ via [ FAMILY ] ADDRESS ]\n"
|
"NH := [ encap ENCAPTYPE ENCAPHDR ] [ via [ FAMILY ] ADDRESS ]\n"
|
||||||
" [ dev STRING ] [ weight NUMBER ] NHFLAGS\n"
|
" [ dev STRING ] [ weight NUMBER ] NHFLAGS\n"
|
||||||
"FAMILY := [ inet | inet6 | ipx | dnet | mpls | bridge | link ]\n"
|
"FAMILY := [ inet | inet6 | mpls | bridge | link ]\n"
|
||||||
"OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ] [ as [ to ] ADDRESS ]\n"
|
"OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ] [ as [ to ] ADDRESS ]\n"
|
||||||
" [ rtt TIME ] [ rttvar TIME ] [ reordering NUMBER ]\n"
|
" [ rtt TIME ] [ rttvar TIME ] [ reordering NUMBER ]\n"
|
||||||
" [ window NUMBER ] [ cwnd NUMBER ] [ initcwnd NUMBER ]\n"
|
" [ window NUMBER ] [ cwnd NUMBER ] [ initcwnd NUMBER ]\n"
|
||||||
|
|
@ -1535,24 +1535,6 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rtnl_rtcache_request(struct rtnl_handle *rth, int family)
|
|
||||||
{
|
|
||||||
struct {
|
|
||||||
struct nlmsghdr nlh;
|
|
||||||
struct rtmsg rtm;
|
|
||||||
} req = {
|
|
||||||
.nlh.nlmsg_len = sizeof(req),
|
|
||||||
.nlh.nlmsg_type = RTM_GETROUTE,
|
|
||||||
.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST,
|
|
||||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
|
||||||
.rtm.rtm_family = family,
|
|
||||||
.rtm.rtm_flags = RTM_F_CLONED,
|
|
||||||
};
|
|
||||||
struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
|
|
||||||
|
|
||||||
return sendto(rth->fd, (void *)&req, sizeof(req), 0, (struct sockaddr *)&nladdr, sizeof(nladdr));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int iproute_flush_cache(void)
|
static int iproute_flush_cache(void)
|
||||||
{
|
{
|
||||||
#define ROUTE_FLUSH_PATH "/proc/sys/net/ipv4/route/flush"
|
#define ROUTE_FLUSH_PATH "/proc/sys/net/ipv4/route/flush"
|
||||||
|
|
@ -1622,7 +1604,7 @@ static int save_route_prep(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)
|
static int iproute_flush(int family, rtnl_filter_t filter_fn)
|
||||||
{
|
{
|
||||||
time_t start = time(0);
|
time_t start = time(0);
|
||||||
char flushb[4096-512];
|
char flushb[4096-512];
|
||||||
|
|
@ -1630,12 +1612,12 @@ static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (filter.cloned) {
|
if (filter.cloned) {
|
||||||
if (do_ipv6 != AF_INET6) {
|
if (family != AF_INET6) {
|
||||||
iproute_flush_cache();
|
iproute_flush_cache();
|
||||||
if (show_stats)
|
if (show_stats)
|
||||||
printf("*** IPv4 routing cache is flushed.\n");
|
printf("*** IPv4 routing cache is flushed.\n");
|
||||||
}
|
}
|
||||||
if (do_ipv6 == AF_INET)
|
if (family == AF_INET)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1644,7 +1626,7 @@ static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)
|
||||||
filter.flushe = sizeof(flushb);
|
filter.flushe = sizeof(flushb);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (rtnl_routedump_req(&rth, do_ipv6) < 0) {
|
if (rtnl_routedump_req(&rth, family, NULL) < 0) {
|
||||||
perror("Cannot send dump request");
|
perror("Cannot send dump request");
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
@ -1656,7 +1638,7 @@ static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)
|
||||||
if (filter.flushed == 0) {
|
if (filter.flushed == 0) {
|
||||||
if (show_stats) {
|
if (show_stats) {
|
||||||
if (round == 0 &&
|
if (round == 0 &&
|
||||||
(!filter.cloned || do_ipv6 == AF_INET6))
|
(!filter.cloned || family == AF_INET6))
|
||||||
printf("Nothing to flush.\n");
|
printf("Nothing to flush.\n");
|
||||||
else
|
else
|
||||||
printf("*** Flush is complete after %d round%s ***\n",
|
printf("*** Flush is complete after %d round%s ***\n",
|
||||||
|
|
@ -1684,9 +1666,33 @@ static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int iproute_dump_filter(struct nlmsghdr *nlh, int reqlen)
|
||||||
|
{
|
||||||
|
struct rtmsg *rtm = NLMSG_DATA(nlh);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
rtm->rtm_protocol = filter.protocol;
|
||||||
|
if (filter.cloned)
|
||||||
|
rtm->rtm_flags |= RTM_F_CLONED;
|
||||||
|
|
||||||
|
if (filter.tb) {
|
||||||
|
err = addattr32(nlh, reqlen, RTA_TABLE, filter.tb);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter.oif) {
|
||||||
|
err = addattr32(nlh, reqlen, RTA_OIF, filter.oif);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int iproute_list_flush_or_save(int argc, char **argv, int action)
|
static int iproute_list_flush_or_save(int argc, char **argv, int action)
|
||||||
{
|
{
|
||||||
int do_ipv6 = preferred_family;
|
int dump_family = preferred_family;
|
||||||
char *id = NULL;
|
char *id = NULL;
|
||||||
char *od = NULL;
|
char *od = NULL;
|
||||||
unsigned int mark = 0;
|
unsigned int mark = 0;
|
||||||
|
|
@ -1805,13 +1811,13 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
family = read_family(*argv);
|
family = read_family(*argv);
|
||||||
if (family == AF_UNSPEC)
|
if (family == AF_UNSPEC)
|
||||||
family = do_ipv6;
|
family = dump_family;
|
||||||
else
|
else
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
get_prefix(&filter.rvia, *argv, family);
|
get_prefix(&filter.rvia, *argv, family);
|
||||||
} else if (strcmp(*argv, "src") == 0) {
|
} else if (strcmp(*argv, "src") == 0) {
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
get_prefix(&filter.rprefsrc, *argv, do_ipv6);
|
get_prefix(&filter.rprefsrc, *argv, dump_family);
|
||||||
} else if (matches(*argv, "realms") == 0) {
|
} else if (matches(*argv, "realms") == 0) {
|
||||||
__u32 realm;
|
__u32 realm;
|
||||||
|
|
||||||
|
|
@ -1831,15 +1837,15 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
if (matches(*argv, "root") == 0) {
|
if (matches(*argv, "root") == 0) {
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
get_prefix(&filter.rsrc, *argv, do_ipv6);
|
get_prefix(&filter.rsrc, *argv, dump_family);
|
||||||
} else if (matches(*argv, "match") == 0) {
|
} else if (matches(*argv, "match") == 0) {
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
get_prefix(&filter.msrc, *argv, do_ipv6);
|
get_prefix(&filter.msrc, *argv, dump_family);
|
||||||
} else {
|
} else {
|
||||||
if (matches(*argv, "exact") == 0) {
|
if (matches(*argv, "exact") == 0) {
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
}
|
}
|
||||||
get_prefix(&filter.msrc, *argv, do_ipv6);
|
get_prefix(&filter.msrc, *argv, dump_family);
|
||||||
filter.rsrc = filter.msrc;
|
filter.rsrc = filter.msrc;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1848,23 +1854,23 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
|
||||||
}
|
}
|
||||||
if (matches(*argv, "root") == 0) {
|
if (matches(*argv, "root") == 0) {
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
get_prefix(&filter.rdst, *argv, do_ipv6);
|
get_prefix(&filter.rdst, *argv, dump_family);
|
||||||
} else if (matches(*argv, "match") == 0) {
|
} else if (matches(*argv, "match") == 0) {
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
get_prefix(&filter.mdst, *argv, do_ipv6);
|
get_prefix(&filter.mdst, *argv, dump_family);
|
||||||
} else {
|
} else {
|
||||||
if (matches(*argv, "exact") == 0) {
|
if (matches(*argv, "exact") == 0) {
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
}
|
}
|
||||||
get_prefix(&filter.mdst, *argv, do_ipv6);
|
get_prefix(&filter.mdst, *argv, dump_family);
|
||||||
filter.rdst = filter.mdst;
|
filter.rdst = filter.mdst;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
argc--; argv++;
|
argc--; argv++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_ipv6 == AF_UNSPEC && filter.tb)
|
if (dump_family == AF_UNSPEC && filter.tb)
|
||||||
do_ipv6 = AF_INET;
|
dump_family = AF_INET;
|
||||||
|
|
||||||
if (id || od) {
|
if (id || od) {
|
||||||
int idx;
|
int idx;
|
||||||
|
|
@ -1887,18 +1893,11 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
|
||||||
filter.mark = mark;
|
filter.mark = mark;
|
||||||
|
|
||||||
if (action == IPROUTE_FLUSH)
|
if (action == IPROUTE_FLUSH)
|
||||||
return iproute_flush(do_ipv6, filter_fn);
|
return iproute_flush(dump_family, filter_fn);
|
||||||
|
|
||||||
if (!filter.cloned) {
|
if (rtnl_routedump_req(&rth, dump_family, iproute_dump_filter) < 0) {
|
||||||
if (rtnl_routedump_req(&rth, do_ipv6) < 0) {
|
perror("Cannot send dump request");
|
||||||
perror("Cannot send dump request");
|
return -2;
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
|
|
||||||
perror("Cannot send dump request");
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
new_json_obj(json);
|
new_json_obj(json);
|
||||||
|
|
|
||||||
66
ip/iprule.c
66
ip/iprule.c
|
|
@ -79,6 +79,9 @@ static struct
|
||||||
inet_prefix dst;
|
inet_prefix dst;
|
||||||
int protocol;
|
int protocol;
|
||||||
int protocolmask;
|
int protocolmask;
|
||||||
|
struct fib_rule_port_range sport;
|
||||||
|
struct fib_rule_port_range dport;
|
||||||
|
__u8 ipproto;
|
||||||
} filter;
|
} filter;
|
||||||
|
|
||||||
static inline int frh_get_table(struct fib_rule_hdr *frh, struct rtattr **tb)
|
static inline int frh_get_table(struct fib_rule_hdr *frh, struct rtattr **tb)
|
||||||
|
|
@ -175,6 +178,39 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filter.ipproto) {
|
||||||
|
__u8 ipproto = 0;
|
||||||
|
|
||||||
|
if (tb[FRA_IP_PROTO])
|
||||||
|
ipproto = rta_getattr_u8(tb[FRA_IP_PROTO]);
|
||||||
|
if (filter.ipproto != ipproto)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter.sport.start) {
|
||||||
|
const struct fib_rule_port_range *r;
|
||||||
|
|
||||||
|
if (!tb[FRA_SPORT_RANGE])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
r = RTA_DATA(tb[FRA_SPORT_RANGE]);
|
||||||
|
if (r->start != filter.sport.start ||
|
||||||
|
r->end != filter.sport.end)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter.dport.start) {
|
||||||
|
const struct fib_rule_port_range *r;
|
||||||
|
|
||||||
|
if (!tb[FRA_DPORT_RANGE])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
r = RTA_DATA(tb[FRA_DPORT_RANGE]);
|
||||||
|
if (r->start != filter.dport.start ||
|
||||||
|
r->end != filter.dport.end)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (filter.tun_id) {
|
if (filter.tun_id) {
|
||||||
__u64 tun_id = 0;
|
__u64 tun_id = 0;
|
||||||
|
|
||||||
|
|
@ -633,6 +669,36 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
|
||||||
filter.protocolmask = 0;
|
filter.protocolmask = 0;
|
||||||
}
|
}
|
||||||
filter.protocol = prot;
|
filter.protocol = prot;
|
||||||
|
} else if (strcmp(*argv, "ipproto") == 0) {
|
||||||
|
int ipproto;
|
||||||
|
|
||||||
|
NEXT_ARG();
|
||||||
|
ipproto = inet_proto_a2n(*argv);
|
||||||
|
if (ipproto < 0)
|
||||||
|
invarg("Invalid \"ipproto\" value\n", *argv);
|
||||||
|
filter.ipproto = ipproto;
|
||||||
|
} else if (strcmp(*argv, "sport") == 0) {
|
||||||
|
struct fib_rule_port_range r;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
NEXT_ARG();
|
||||||
|
ret = sscanf(*argv, "%hu-%hu", &r.start, &r.end);
|
||||||
|
if (ret == 1)
|
||||||
|
r.end = r.start;
|
||||||
|
else if (ret != 2)
|
||||||
|
invarg("invalid port range\n", *argv);
|
||||||
|
filter.sport = r;
|
||||||
|
} else if (strcmp(*argv, "dport") == 0) {
|
||||||
|
struct fib_rule_port_range r;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
NEXT_ARG();
|
||||||
|
ret = sscanf(*argv, "%hu-%hu", &r.start, &r.end);
|
||||||
|
if (ret == 1)
|
||||||
|
r.end = r.start;
|
||||||
|
else if (ret != 2)
|
||||||
|
invarg("invalid dport range\n", *argv);
|
||||||
|
filter.dport = r;
|
||||||
} else{
|
} else{
|
||||||
if (matches(*argv, "dst") == 0 ||
|
if (matches(*argv, "dst") == 0 ||
|
||||||
matches(*argv, "to") == 0) {
|
matches(*argv, "to") == 0) {
|
||||||
|
|
|
||||||
|
|
@ -589,7 +589,7 @@ static int ipvrf_show(int argc, char **argv)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ip_linkaddr_list(0, ipvrf_filter_req, &linfo, NULL) == 0) {
|
if (ip_link_list(ipvrf_filter_req, &linfo) == 0) {
|
||||||
struct nlmsg_list *l;
|
struct nlmsg_list *l;
|
||||||
unsigned nvrf = 0;
|
unsigned nvrf = 0;
|
||||||
int n;
|
int n;
|
||||||
|
|
|
||||||
101
lib/dnet_ntop.c
101
lib/dnet_ntop.c
|
|
@ -1,101 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
static __inline__ u_int16_t dn_ntohs(u_int16_t addr)
|
|
||||||
{
|
|
||||||
union {
|
|
||||||
u_int8_t byte[2];
|
|
||||||
u_int16_t word;
|
|
||||||
} u;
|
|
||||||
|
|
||||||
u.word = addr;
|
|
||||||
return ((u_int16_t)u.byte[0]) | (((u_int16_t)u.byte[1]) << 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ int do_digit(char *str, u_int16_t *addr, u_int16_t scale, size_t *pos, size_t len, int *started)
|
|
||||||
{
|
|
||||||
u_int16_t tmp = *addr / scale;
|
|
||||||
|
|
||||||
if (*pos == len)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (((tmp) > 0) || *started || (scale == 1)) {
|
|
||||||
*str = tmp + '0';
|
|
||||||
*started = 1;
|
|
||||||
(*pos)++;
|
|
||||||
*addr -= (tmp * scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const char *dnet_ntop1(const struct dn_naddr *dna, char *str, size_t len)
|
|
||||||
{
|
|
||||||
u_int16_t addr, area;
|
|
||||||
size_t pos = 0;
|
|
||||||
int started = 0;
|
|
||||||
|
|
||||||
memcpy(&addr, dna->a_addr, sizeof(addr));
|
|
||||||
addr = dn_ntohs(addr);
|
|
||||||
area = addr >> 10;
|
|
||||||
|
|
||||||
if (dna->a_len != 2)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
addr &= 0x03ff;
|
|
||||||
|
|
||||||
if (len == 0)
|
|
||||||
return str;
|
|
||||||
|
|
||||||
if (do_digit(str + pos, &area, 10, &pos, len, &started))
|
|
||||||
return str;
|
|
||||||
|
|
||||||
if (do_digit(str + pos, &area, 1, &pos, len, &started))
|
|
||||||
return str;
|
|
||||||
|
|
||||||
if (pos == len)
|
|
||||||
return str;
|
|
||||||
|
|
||||||
*(str + pos) = '.';
|
|
||||||
pos++;
|
|
||||||
started = 0;
|
|
||||||
|
|
||||||
if (do_digit(str + pos, &addr, 1000, &pos, len, &started))
|
|
||||||
return str;
|
|
||||||
|
|
||||||
if (do_digit(str + pos, &addr, 100, &pos, len, &started))
|
|
||||||
return str;
|
|
||||||
|
|
||||||
if (do_digit(str + pos, &addr, 10, &pos, len, &started))
|
|
||||||
return str;
|
|
||||||
|
|
||||||
if (do_digit(str + pos, &addr, 1, &pos, len, &started))
|
|
||||||
return str;
|
|
||||||
|
|
||||||
if (pos == len)
|
|
||||||
return str;
|
|
||||||
|
|
||||||
*(str + pos) = 0;
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const char *dnet_ntop(int af, const void *addr, char *str, size_t len)
|
|
||||||
{
|
|
||||||
switch(af) {
|
|
||||||
case AF_DECnet:
|
|
||||||
errno = 0;
|
|
||||||
return dnet_ntop1((struct dn_naddr *)addr, str, len);
|
|
||||||
default:
|
|
||||||
errno = EAFNOSUPPORT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
static __inline__ u_int16_t dn_htons(u_int16_t addr)
|
|
||||||
{
|
|
||||||
union {
|
|
||||||
u_int8_t byte[2];
|
|
||||||
u_int16_t word;
|
|
||||||
} u;
|
|
||||||
|
|
||||||
u.word = addr;
|
|
||||||
return ((u_int16_t)u.byte[0]) | (((u_int16_t)u.byte[1]) << 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int dnet_num(const char *src, u_int16_t * dst)
|
|
||||||
{
|
|
||||||
int rv = 0;
|
|
||||||
int tmp;
|
|
||||||
*dst = 0;
|
|
||||||
|
|
||||||
while ((tmp = *src++) != 0) {
|
|
||||||
tmp -= '0';
|
|
||||||
if ((tmp < 0) || (tmp > 9))
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
rv++;
|
|
||||||
(*dst) *= 10;
|
|
||||||
(*dst) += tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dnet_pton1(const char *src, struct dn_naddr *dna)
|
|
||||||
{
|
|
||||||
u_int16_t addr;
|
|
||||||
u_int16_t area = 0;
|
|
||||||
u_int16_t node = 0;
|
|
||||||
int pos;
|
|
||||||
|
|
||||||
pos = dnet_num(src, &area);
|
|
||||||
if ((pos == 0) || (area > 63) || (*(src + pos) != '.'))
|
|
||||||
return 0;
|
|
||||||
pos = dnet_num(src + pos + 1, &node);
|
|
||||||
if ((pos == 0) || (node > 1023))
|
|
||||||
return 0;
|
|
||||||
dna->a_len = 2;
|
|
||||||
addr = dn_htons((area << 10) | node);
|
|
||||||
memcpy(dna->a_addr, &addr, sizeof(addr));
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dnet_pton(int af, const char *src, void *addr)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
switch (af) {
|
|
||||||
case AF_DECnet:
|
|
||||||
errno = 0;
|
|
||||||
err = dnet_pton1(src, (struct dn_naddr *)addr);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
errno = EAFNOSUPPORT;
|
|
||||||
err = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
static __inline__ int do_digit(char *str, u_int32_t addr, u_int32_t scale, size_t *pos, size_t len)
|
|
||||||
{
|
|
||||||
u_int32_t tmp = addr >> (scale * 4);
|
|
||||||
|
|
||||||
if (*pos == len)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
tmp &= 0x0f;
|
|
||||||
if (tmp > 9)
|
|
||||||
*str = tmp + 'A' - 10;
|
|
||||||
else
|
|
||||||
*str = tmp + '0';
|
|
||||||
(*pos)++;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *ipx_ntop1(const struct ipx_addr *addr, char *str, size_t len)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
size_t pos = 0;
|
|
||||||
|
|
||||||
if (len == 0)
|
|
||||||
return str;
|
|
||||||
|
|
||||||
for(i = 7; i >= 0; i--)
|
|
||||||
if (do_digit(str + pos, ntohl(addr->ipx_net), i, &pos, len))
|
|
||||||
return str;
|
|
||||||
|
|
||||||
if (pos == len)
|
|
||||||
return str;
|
|
||||||
|
|
||||||
*(str + pos) = '.';
|
|
||||||
pos++;
|
|
||||||
|
|
||||||
for(i = 0; i < 6; i++) {
|
|
||||||
if (do_digit(str + pos, addr->ipx_node[i], 1, &pos, len))
|
|
||||||
return str;
|
|
||||||
if (do_digit(str + pos, addr->ipx_node[i], 0, &pos, len))
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pos == len)
|
|
||||||
return str;
|
|
||||||
|
|
||||||
*(str + pos) = 0;
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const char *ipx_ntop(int af, const void *addr, char *str, size_t len)
|
|
||||||
{
|
|
||||||
switch(af) {
|
|
||||||
case AF_IPX:
|
|
||||||
errno = 0;
|
|
||||||
return ipx_ntop1((struct ipx_addr *)addr, str, len);
|
|
||||||
default:
|
|
||||||
errno = EAFNOSUPPORT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
@ -1,97 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
static int ipx_getnet(u_int32_t *net, const char *str)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
u_int32_t tmp;
|
|
||||||
|
|
||||||
for(i = 0; *str && (i < 8); i++) {
|
|
||||||
|
|
||||||
if ((tmp = get_hex(*str)) == -1) {
|
|
||||||
if (*str == '.')
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
str++;
|
|
||||||
(*net) <<= 4;
|
|
||||||
(*net) |= tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*str == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ipx_getnode(u_int8_t *node, const char *str)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
u_int32_t tmp;
|
|
||||||
|
|
||||||
for(i = 0; i < 6; i++) {
|
|
||||||
if ((tmp = get_hex(*str++)) == -1)
|
|
||||||
return -1;
|
|
||||||
node[i] = (u_int8_t)tmp;
|
|
||||||
node[i] <<= 4;
|
|
||||||
if ((tmp = get_hex(*str++)) == -1)
|
|
||||||
return -1;
|
|
||||||
node[i] |= (u_int8_t)tmp;
|
|
||||||
if (*str == ':')
|
|
||||||
str++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ipx_pton1(const char *src, struct ipx_addr *addr)
|
|
||||||
{
|
|
||||||
char *sep = (char *)src;
|
|
||||||
int no_node = 0;
|
|
||||||
|
|
||||||
memset(addr, 0, sizeof(struct ipx_addr));
|
|
||||||
|
|
||||||
while(*sep && (*sep != '.'))
|
|
||||||
sep++;
|
|
||||||
|
|
||||||
if (*sep != '.')
|
|
||||||
no_node = 1;
|
|
||||||
|
|
||||||
if (ipx_getnet(&addr->ipx_net, src))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
addr->ipx_net = htonl(addr->ipx_net);
|
|
||||||
|
|
||||||
if (no_node)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (ipx_getnode(addr->ipx_node, sep + 1))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ipx_pton(int af, const char *src, void *addr)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
switch (af) {
|
|
||||||
case AF_IPX:
|
|
||||||
errno = 0;
|
|
||||||
err = ipx_pton1(src, (struct ipx_addr *)addr);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
errno = EAFNOSUPPORT;
|
|
||||||
err = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
@ -118,6 +118,7 @@ void close_json_array(enum output_type type, const char *str)
|
||||||
}
|
}
|
||||||
_PRINT_FUNC(int, int);
|
_PRINT_FUNC(int, int);
|
||||||
_PRINT_FUNC(s64, int64_t);
|
_PRINT_FUNC(s64, int64_t);
|
||||||
|
_PRINT_FUNC(hhu, unsigned char);
|
||||||
_PRINT_FUNC(hu, unsigned short);
|
_PRINT_FUNC(hu, unsigned short);
|
||||||
_PRINT_FUNC(uint, unsigned int);
|
_PRINT_FUNC(uint, unsigned int);
|
||||||
_PRINT_FUNC(u64, uint64_t);
|
_PRINT_FUNC(u64, uint64_t);
|
||||||
|
|
|
||||||
|
|
@ -211,6 +211,11 @@ void jsonw_float(json_writer_t *self, double num)
|
||||||
jsonw_printf(self, "%g", num);
|
jsonw_printf(self, "%g", num);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void jsonw_hhu(json_writer_t *self, unsigned char num)
|
||||||
|
{
|
||||||
|
jsonw_printf(self, "%hhu", num);
|
||||||
|
}
|
||||||
|
|
||||||
void jsonw_hu(json_writer_t *self, unsigned short num)
|
void jsonw_hu(json_writer_t *self, unsigned short num)
|
||||||
{
|
{
|
||||||
jsonw_printf(self, "%hu", num);
|
jsonw_printf(self, "%hu", num);
|
||||||
|
|
@ -288,6 +293,12 @@ void jsonw_xint_field(json_writer_t *self, const char *prop, uint64_t num)
|
||||||
jsonw_xint(self, num);
|
jsonw_xint(self, num);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void jsonw_hhu_field(json_writer_t *self, const char *prop, unsigned char num)
|
||||||
|
{
|
||||||
|
jsonw_name(self, prop);
|
||||||
|
jsonw_hhu(self, num);
|
||||||
|
}
|
||||||
|
|
||||||
void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num)
|
void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num)
|
||||||
{
|
{
|
||||||
jsonw_name(self, prop);
|
jsonw_name(self, prop);
|
||||||
|
|
|
||||||
217
lib/libnetlink.c
217
lib/libnetlink.c
|
|
@ -28,6 +28,8 @@
|
||||||
|
|
||||||
#include "libnetlink.h"
|
#include "libnetlink.h"
|
||||||
|
|
||||||
|
#define __aligned(x) __attribute__((aligned(x)))
|
||||||
|
|
||||||
#ifndef SOL_NETLINK
|
#ifndef SOL_NETLINK
|
||||||
#define SOL_NETLINK 270
|
#define SOL_NETLINK 270
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -67,6 +69,14 @@ static int err_attr_cb(const struct nlattr *attr, void *data)
|
||||||
return MNL_CB_OK;
|
return MNL_CB_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_ext_ack_msg(bool is_err, const char *msg)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: %s", is_err ? "Error" : "Warning", msg);
|
||||||
|
if (msg[strlen(msg) - 1] != '.')
|
||||||
|
fprintf(stderr, ".");
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
/* dump netlink extended ack error message */
|
/* dump netlink extended ack error message */
|
||||||
int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)
|
int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)
|
||||||
{
|
{
|
||||||
|
|
@ -108,12 +118,29 @@ int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)
|
||||||
if (msg && *msg != '\0') {
|
if (msg && *msg != '\0') {
|
||||||
bool is_err = !!err->error;
|
bool is_err = !!err->error;
|
||||||
|
|
||||||
fprintf(stderr, "%s: %s",
|
print_ext_ack_msg(is_err, msg);
|
||||||
is_err ? "Error" : "Warning", msg);
|
return is_err ? 1 : 0;
|
||||||
if (msg[strlen(msg) - 1] != '.')
|
}
|
||||||
fprintf(stderr, ".");
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nl_dump_ext_ack_done(const struct nlmsghdr *nlh, int error)
|
||||||
|
{
|
||||||
|
struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
|
||||||
|
unsigned int hlen = sizeof(int);
|
||||||
|
const char *msg = NULL;
|
||||||
|
|
||||||
|
if (mnl_attr_parse(nlh, hlen, err_attr_cb, tb) != MNL_CB_OK)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (tb[NLMSGERR_ATTR_MSG])
|
||||||
|
msg = mnl_attr_get_str(tb[NLMSGERR_ATTR_MSG]);
|
||||||
|
|
||||||
|
if (msg && *msg != '\0') {
|
||||||
|
bool is_err = !!error;
|
||||||
|
|
||||||
|
print_ext_ack_msg(is_err, msg);
|
||||||
return is_err ? 1 : 0;
|
return is_err ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,8 +154,25 @@ int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nl_dump_ext_ack_done(const struct nlmsghdr *nlh, int error)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Older kernels may not support strict dump and filtering */
|
||||||
|
void rtnl_set_strict_dump(struct rtnl_handle *rth)
|
||||||
|
{
|
||||||
|
int one = 1;
|
||||||
|
|
||||||
|
if (setsockopt(rth->fd, SOL_NETLINK, NETLINK_GET_STRICT_CHK,
|
||||||
|
&one, sizeof(one)) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rth->flags |= RTNL_HANDLE_F_STRICT_CHK;
|
||||||
|
}
|
||||||
|
|
||||||
void rtnl_close(struct rtnl_handle *rth)
|
void rtnl_close(struct rtnl_handle *rth)
|
||||||
{
|
{
|
||||||
if (rth->fd >= 0) {
|
if (rth->fd >= 0) {
|
||||||
|
|
@ -202,19 +246,29 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtnl_addrdump_req(struct rtnl_handle *rth, int family)
|
int rtnl_addrdump_req(struct rtnl_handle *rth, int family,
|
||||||
|
req_filter_fn_t filter_fn)
|
||||||
{
|
{
|
||||||
struct {
|
struct {
|
||||||
struct nlmsghdr nlh;
|
struct nlmsghdr nlh;
|
||||||
struct ifaddrmsg ifm;
|
struct ifaddrmsg ifm;
|
||||||
|
char buf[128];
|
||||||
} req = {
|
} req = {
|
||||||
.nlh.nlmsg_len = sizeof(req),
|
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
|
||||||
.nlh.nlmsg_type = RTM_GETADDR,
|
.nlh.nlmsg_type = RTM_GETADDR,
|
||||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||||
.ifm.ifa_family = family,
|
.ifm.ifa_family = family,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (filter_fn) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = filter_fn(&req.nlh, sizeof(req));
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
return send(rth->fd, &req, sizeof(req), 0);
|
return send(rth->fd, &req, sizeof(req), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -224,7 +278,7 @@ int rtnl_addrlbldump_req(struct rtnl_handle *rth, int family)
|
||||||
struct nlmsghdr nlh;
|
struct nlmsghdr nlh;
|
||||||
struct ifaddrlblmsg ifal;
|
struct ifaddrlblmsg ifal;
|
||||||
} req = {
|
} req = {
|
||||||
.nlh.nlmsg_len = sizeof(req),
|
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg)),
|
||||||
.nlh.nlmsg_type = RTM_GETADDRLABEL,
|
.nlh.nlmsg_type = RTM_GETADDRLABEL,
|
||||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||||
|
|
@ -234,19 +288,29 @@ int rtnl_addrlbldump_req(struct rtnl_handle *rth, int family)
|
||||||
return send(rth->fd, &req, sizeof(req), 0);
|
return send(rth->fd, &req, sizeof(req), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtnl_routedump_req(struct rtnl_handle *rth, int family)
|
int rtnl_routedump_req(struct rtnl_handle *rth, int family,
|
||||||
|
req_filter_fn_t filter_fn)
|
||||||
{
|
{
|
||||||
struct {
|
struct {
|
||||||
struct nlmsghdr nlh;
|
struct nlmsghdr nlh;
|
||||||
struct rtmsg rtm;
|
struct rtmsg rtm;
|
||||||
|
char buf[128];
|
||||||
} req = {
|
} req = {
|
||||||
.nlh.nlmsg_len = sizeof(req),
|
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
|
||||||
.nlh.nlmsg_type = RTM_GETROUTE,
|
.nlh.nlmsg_type = RTM_GETROUTE,
|
||||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||||
.rtm.rtm_family = family,
|
.rtm.rtm_family = family,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (filter_fn) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = filter_fn(&req.nlh, sizeof(req));
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
return send(rth->fd, &req, sizeof(req), 0);
|
return send(rth->fd, &req, sizeof(req), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -256,7 +320,7 @@ int rtnl_ruledump_req(struct rtnl_handle *rth, int family)
|
||||||
struct nlmsghdr nlh;
|
struct nlmsghdr nlh;
|
||||||
struct fib_rule_hdr frh;
|
struct fib_rule_hdr frh;
|
||||||
} req = {
|
} req = {
|
||||||
.nlh.nlmsg_len = sizeof(req),
|
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)),
|
||||||
.nlh.nlmsg_type = RTM_GETRULE,
|
.nlh.nlmsg_type = RTM_GETRULE,
|
||||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||||
|
|
@ -266,19 +330,29 @@ int rtnl_ruledump_req(struct rtnl_handle *rth, int family)
|
||||||
return send(rth->fd, &req, sizeof(req), 0);
|
return send(rth->fd, &req, sizeof(req), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtnl_neighdump_req(struct rtnl_handle *rth, int family)
|
int rtnl_neighdump_req(struct rtnl_handle *rth, int family,
|
||||||
|
req_filter_fn_t filter_fn)
|
||||||
{
|
{
|
||||||
struct {
|
struct {
|
||||||
struct nlmsghdr nlh;
|
struct nlmsghdr nlh;
|
||||||
struct ndmsg ndm;
|
struct ndmsg ndm;
|
||||||
|
char buf[256];
|
||||||
} req = {
|
} req = {
|
||||||
.nlh.nlmsg_len = sizeof(req),
|
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
|
||||||
.nlh.nlmsg_type = RTM_GETNEIGH,
|
.nlh.nlmsg_type = RTM_GETNEIGH,
|
||||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||||
.ndm.ndm_family = family,
|
.ndm.ndm_family = family,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (filter_fn) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = filter_fn(&req.nlh, sizeof(req));
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
return send(rth->fd, &req, sizeof(req), 0);
|
return send(rth->fd, &req, sizeof(req), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -288,7 +362,7 @@ int rtnl_neightbldump_req(struct rtnl_handle *rth, int family)
|
||||||
struct nlmsghdr nlh;
|
struct nlmsghdr nlh;
|
||||||
struct ndtmsg ndtmsg;
|
struct ndtmsg ndtmsg;
|
||||||
} req = {
|
} req = {
|
||||||
.nlh.nlmsg_len = sizeof(req),
|
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg)),
|
||||||
.nlh.nlmsg_type = RTM_GETNEIGHTBL,
|
.nlh.nlmsg_type = RTM_GETNEIGHTBL,
|
||||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||||
|
|
@ -304,7 +378,7 @@ int rtnl_mdbdump_req(struct rtnl_handle *rth, int family)
|
||||||
struct nlmsghdr nlh;
|
struct nlmsghdr nlh;
|
||||||
struct br_port_msg bpm;
|
struct br_port_msg bpm;
|
||||||
} req = {
|
} req = {
|
||||||
.nlh.nlmsg_len = sizeof(req),
|
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_port_msg)),
|
||||||
.nlh.nlmsg_type = RTM_GETMDB,
|
.nlh.nlmsg_type = RTM_GETMDB,
|
||||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||||
|
|
@ -319,8 +393,9 @@ int rtnl_netconfdump_req(struct rtnl_handle *rth, int family)
|
||||||
struct {
|
struct {
|
||||||
struct nlmsghdr nlh;
|
struct nlmsghdr nlh;
|
||||||
struct netconfmsg ncm;
|
struct netconfmsg ncm;
|
||||||
|
char buf[0] __aligned(NLMSG_ALIGNTO);
|
||||||
} req = {
|
} req = {
|
||||||
.nlh.nlmsg_len = sizeof(req),
|
.nlh.nlmsg_len = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct netconfmsg))),
|
||||||
.nlh.nlmsg_type = RTM_GETNETCONF,
|
.nlh.nlmsg_type = RTM_GETNETCONF,
|
||||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||||
|
|
@ -335,8 +410,9 @@ int rtnl_nsiddump_req(struct rtnl_handle *rth, int family)
|
||||||
struct {
|
struct {
|
||||||
struct nlmsghdr nlh;
|
struct nlmsghdr nlh;
|
||||||
struct rtgenmsg rtm;
|
struct rtgenmsg rtm;
|
||||||
|
char buf[0] __aligned(NLMSG_ALIGNTO);
|
||||||
} req = {
|
} req = {
|
||||||
.nlh.nlmsg_len = sizeof(req),
|
.nlh.nlmsg_len = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct rtgenmsg))),
|
||||||
.nlh.nlmsg_type = RTM_GETNSID,
|
.nlh.nlmsg_type = RTM_GETNSID,
|
||||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||||
|
|
@ -346,41 +422,11 @@ int rtnl_nsiddump_req(struct rtnl_handle *rth, int family)
|
||||||
return send(rth->fd, &req, sizeof(req), 0);
|
return send(rth->fd, &req, sizeof(req), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtnl_linkdump_req(struct rtnl_handle *rth, int family)
|
static int __rtnl_linkdump_req(struct rtnl_handle *rth, int family)
|
||||||
{
|
|
||||||
return rtnl_linkdump_req_filter(rth, family, RTEXT_FILTER_VF);
|
|
||||||
}
|
|
||||||
|
|
||||||
int rtnl_linkdump_req_filter(struct rtnl_handle *rth, int family,
|
|
||||||
__u32 filt_mask)
|
|
||||||
{
|
{
|
||||||
struct {
|
struct {
|
||||||
struct nlmsghdr nlh;
|
struct nlmsghdr nlh;
|
||||||
struct ifinfomsg ifm;
|
struct ifinfomsg ifm;
|
||||||
/* attribute has to be NLMSG aligned */
|
|
||||||
struct rtattr ext_req __attribute__ ((aligned(NLMSG_ALIGNTO)));
|
|
||||||
__u32 ext_filter_mask;
|
|
||||||
} req = {
|
|
||||||
.nlh.nlmsg_len = sizeof(req),
|
|
||||||
.nlh.nlmsg_type = RTM_GETLINK,
|
|
||||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
|
||||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
|
||||||
.ifm.ifi_family = family,
|
|
||||||
.ext_req.rta_type = IFLA_EXT_MASK,
|
|
||||||
.ext_req.rta_len = RTA_LENGTH(sizeof(__u32)),
|
|
||||||
.ext_filter_mask = filt_mask,
|
|
||||||
};
|
|
||||||
|
|
||||||
return send(rth->fd, &req, sizeof(req), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, int family,
|
|
||||||
req_filter_fn_t filter_fn)
|
|
||||||
{
|
|
||||||
struct {
|
|
||||||
struct nlmsghdr nlh;
|
|
||||||
struct ifinfomsg ifm;
|
|
||||||
char buf[1024];
|
|
||||||
} req = {
|
} req = {
|
||||||
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
|
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
|
||||||
.nlh.nlmsg_type = RTM_GETLINK,
|
.nlh.nlmsg_type = RTM_GETLINK,
|
||||||
|
|
@ -388,16 +434,73 @@ int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, int family,
|
||||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||||
.ifm.ifi_family = family,
|
.ifm.ifi_family = family,
|
||||||
};
|
};
|
||||||
int err;
|
|
||||||
|
|
||||||
if (!filter_fn)
|
return send(rth->fd, &req, sizeof(req), 0);
|
||||||
return -EINVAL;
|
}
|
||||||
|
|
||||||
err = filter_fn(&req.nlh, sizeof(req));
|
int rtnl_linkdump_req(struct rtnl_handle *rth, int family)
|
||||||
if (err)
|
{
|
||||||
return err;
|
if (family == AF_UNSPEC)
|
||||||
|
return rtnl_linkdump_req_filter(rth, family, RTEXT_FILTER_VF);
|
||||||
|
|
||||||
return send(rth->fd, &req, req.nlh.nlmsg_len, 0);
|
return __rtnl_linkdump_req(rth, family);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtnl_linkdump_req_filter(struct rtnl_handle *rth, int family,
|
||||||
|
__u32 filt_mask)
|
||||||
|
{
|
||||||
|
if (family == AF_UNSPEC || family == AF_BRIDGE) {
|
||||||
|
struct {
|
||||||
|
struct nlmsghdr nlh;
|
||||||
|
struct ifinfomsg ifm;
|
||||||
|
/* attribute has to be NLMSG aligned */
|
||||||
|
struct rtattr ext_req __aligned(NLMSG_ALIGNTO);
|
||||||
|
__u32 ext_filter_mask;
|
||||||
|
} req = {
|
||||||
|
.nlh.nlmsg_len = sizeof(req),
|
||||||
|
.nlh.nlmsg_type = RTM_GETLINK,
|
||||||
|
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||||
|
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||||
|
.ifm.ifi_family = family,
|
||||||
|
.ext_req.rta_type = IFLA_EXT_MASK,
|
||||||
|
.ext_req.rta_len = RTA_LENGTH(sizeof(__u32)),
|
||||||
|
.ext_filter_mask = filt_mask,
|
||||||
|
};
|
||||||
|
|
||||||
|
return send(rth->fd, &req, sizeof(req), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return __rtnl_linkdump_req(rth, family);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, int family,
|
||||||
|
req_filter_fn_t filter_fn)
|
||||||
|
{
|
||||||
|
if (family == AF_UNSPEC) {
|
||||||
|
struct {
|
||||||
|
struct nlmsghdr nlh;
|
||||||
|
struct ifinfomsg ifm;
|
||||||
|
char buf[1024];
|
||||||
|
} req = {
|
||||||
|
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
|
||||||
|
.nlh.nlmsg_type = RTM_GETLINK,
|
||||||
|
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||||
|
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||||
|
.ifm.ifi_family = family,
|
||||||
|
};
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!filter_fn)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
err = filter_fn(&req.nlh, sizeof(req));
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return send(rth->fd, &req, req.nlh.nlmsg_len, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return __rtnl_linkdump_req(rth, family);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtnl_statsdump_req_filter(struct rtnl_handle *rth, int fam, __u32 filt_mask)
|
int rtnl_statsdump_req_filter(struct rtnl_handle *rth, int fam, __u32 filt_mask)
|
||||||
|
|
@ -512,6 +615,10 @@ static int rtnl_dump_done(struct nlmsghdr *h)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
|
/* check for any messages returned from kernel */
|
||||||
|
if (nl_dump_ext_ack_done(h, len))
|
||||||
|
return len;
|
||||||
|
|
||||||
errno = -len;
|
errno = -len;
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
case ENOENT:
|
case ENOENT:
|
||||||
|
|
|
||||||
25
lib/utils.c
25
lib/utils.c
|
|
@ -600,18 +600,6 @@ static int __get_addr_1(inet_prefix *addr, const char *name, int family)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (family == AF_DECnet) {
|
|
||||||
struct dn_naddr dna;
|
|
||||||
|
|
||||||
addr->family = AF_DECnet;
|
|
||||||
if (dnet_pton(AF_DECnet, name, &dna) <= 0)
|
|
||||||
return -1;
|
|
||||||
memcpy(addr->data, dna.a_addr, 2);
|
|
||||||
addr->bytelen = 2;
|
|
||||||
addr->bitlen = -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (family == AF_MPLS) {
|
if (family == AF_MPLS) {
|
||||||
unsigned int maxlabels;
|
unsigned int maxlabels;
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -1000,15 +988,6 @@ const char *rt_addr_n2a_r(int af, int len,
|
||||||
return inet_ntop(af, addr, buf, buflen);
|
return inet_ntop(af, addr, buf, buflen);
|
||||||
case AF_MPLS:
|
case AF_MPLS:
|
||||||
return mpls_ntop(af, addr, buf, buflen);
|
return mpls_ntop(af, addr, buf, buflen);
|
||||||
case AF_IPX:
|
|
||||||
return ipx_ntop(af, addr, buf, buflen);
|
|
||||||
case AF_DECnet:
|
|
||||||
{
|
|
||||||
struct dn_naddr dna = { 2, { 0, 0, } };
|
|
||||||
|
|
||||||
memcpy(dna.a_addr, addr, 2);
|
|
||||||
return dnet_ntop(af, &dna, buf, buflen);
|
|
||||||
}
|
|
||||||
case AF_PACKET:
|
case AF_PACKET:
|
||||||
return ll_addr_n2a(addr, len, ARPHRD_VOID, buf, buflen);
|
return ll_addr_n2a(addr, len, ARPHRD_VOID, buf, buflen);
|
||||||
case AF_BRIDGE:
|
case AF_BRIDGE:
|
||||||
|
|
@ -1050,8 +1029,6 @@ int read_family(const char *name)
|
||||||
family = AF_INET;
|
family = AF_INET;
|
||||||
else if (strcmp(name, "inet6") == 0)
|
else if (strcmp(name, "inet6") == 0)
|
||||||
family = AF_INET6;
|
family = AF_INET6;
|
||||||
else if (strcmp(name, "dnet") == 0)
|
|
||||||
family = AF_DECnet;
|
|
||||||
else if (strcmp(name, "link") == 0)
|
else if (strcmp(name, "link") == 0)
|
||||||
family = AF_PACKET;
|
family = AF_PACKET;
|
||||||
else if (strcmp(name, "ipx") == 0)
|
else if (strcmp(name, "ipx") == 0)
|
||||||
|
|
@ -1069,8 +1046,6 @@ const char *family_name(int family)
|
||||||
return "inet";
|
return "inet";
|
||||||
if (family == AF_INET6)
|
if (family == AF_INET6)
|
||||||
return "inet6";
|
return "inet6";
|
||||||
if (family == AF_DECnet)
|
|
||||||
return "dnet";
|
|
||||||
if (family == AF_PACKET)
|
if (family == AF_PACKET)
|
||||||
return "link";
|
return "link";
|
||||||
if (family == AF_IPX)
|
if (family == AF_IPX)
|
||||||
|
|
|
||||||
|
|
@ -496,6 +496,8 @@ the following additional arguments are supported:
|
||||||
] [
|
] [
|
||||||
.BI tos " TOS "
|
.BI tos " TOS "
|
||||||
] [
|
] [
|
||||||
|
.BI df " DF "
|
||||||
|
] [
|
||||||
.BI flowlabel " FLOWLABEL "
|
.BI flowlabel " FLOWLABEL "
|
||||||
] [
|
] [
|
||||||
.BI dstport " PORT "
|
.BI dstport " PORT "
|
||||||
|
|
@ -565,6 +567,18 @@ parameter.
|
||||||
.BI tos " TOS"
|
.BI tos " TOS"
|
||||||
- specifies the TOS value to use in outgoing packets.
|
- specifies the TOS value to use in outgoing packets.
|
||||||
|
|
||||||
|
.sp
|
||||||
|
.BI df " DF"
|
||||||
|
- specifies the usage of the Don't Fragment flag (DF) bit in outgoing packets
|
||||||
|
with IPv4 headers. The value
|
||||||
|
.B inherit
|
||||||
|
causes the bit to be copied from the original IP header. The values
|
||||||
|
.B unset
|
||||||
|
and
|
||||||
|
.B set
|
||||||
|
cause the bit to be always unset or always set, respectively. By default, the
|
||||||
|
bit is not set.
|
||||||
|
|
||||||
.sp
|
.sp
|
||||||
.BI flowlabel " FLOWLABEL"
|
.BI flowlabel " FLOWLABEL"
|
||||||
- specifies the flow label to use in outgoing packets.
|
- specifies the flow label to use in outgoing packets.
|
||||||
|
|
@ -1166,6 +1180,8 @@ the following additional arguments are supported:
|
||||||
] [
|
] [
|
||||||
.BI tos " TOS "
|
.BI tos " TOS "
|
||||||
] [
|
] [
|
||||||
|
.BI df " DF "
|
||||||
|
] [
|
||||||
.BI flowlabel " FLOWLABEL "
|
.BI flowlabel " FLOWLABEL "
|
||||||
] [
|
] [
|
||||||
.BI dstport " PORT"
|
.BI dstport " PORT"
|
||||||
|
|
@ -1198,6 +1214,18 @@ ttl. Default option is "0".
|
||||||
.BI tos " TOS"
|
.BI tos " TOS"
|
||||||
- specifies the TOS value to use in outgoing packets.
|
- specifies the TOS value to use in outgoing packets.
|
||||||
|
|
||||||
|
.sp
|
||||||
|
.BI df " DF"
|
||||||
|
- specifies the usage of the Don't Fragment flag (DF) bit in outgoing packets
|
||||||
|
with IPv4 headers. The value
|
||||||
|
.B inherit
|
||||||
|
causes the bit to be copied from the original IP header. The values
|
||||||
|
.B unset
|
||||||
|
and
|
||||||
|
.B set
|
||||||
|
cause the bit to be always unset or always set, respectively. By default, the
|
||||||
|
bit is not set.
|
||||||
|
|
||||||
.sp
|
.sp
|
||||||
.BI flowlabel " FLOWLABEL"
|
.BI flowlabel " FLOWLABEL"
|
||||||
- specifies the flow label to use in outgoing packets.
|
- specifies the flow label to use in outgoing packets.
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ replace " } "
|
||||||
|
|
||||||
.ti -8
|
.ti -8
|
||||||
.IR FAMILY " := [ "
|
.IR FAMILY " := [ "
|
||||||
.BR inet " | " inet6 " | " ipx " | " dnet " | " mpls " | " bridge " | " link " ]"
|
.BR inet " | " inet6 " | " mpls " | " bridge " | " link " ]"
|
||||||
|
|
||||||
.ti -8
|
.ti -8
|
||||||
.IR OPTIONS " := " FLAGS " [ "
|
.IR OPTIONS " := " FLAGS " [ "
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ ip \- show / manipulate routing, network devices, interfaces and tunnels
|
||||||
\fB\-r\fR[\fIesolve\fR] |
|
\fB\-r\fR[\fIesolve\fR] |
|
||||||
\fB\-iec\fR |
|
\fB\-iec\fR |
|
||||||
\fB\-f\fR[\fIamily\fR] {
|
\fB\-f\fR[\fIamily\fR] {
|
||||||
.BR inet " | " inet6 " | " ipx " | " dnet " | " link " } | "
|
.BR inet " | " inet6 " | " link " } | "
|
||||||
\fB-4\fR |
|
\fB-4\fR |
|
||||||
\fB-6\fR |
|
\fB-6\fR |
|
||||||
\fB-I\fR |
|
\fB-I\fR |
|
||||||
|
|
@ -94,7 +94,7 @@ Zero (0) means loop until all addresses are removed.
|
||||||
.TP
|
.TP
|
||||||
.BR "\-f" , " \-family " <FAMILY>
|
.BR "\-f" , " \-family " <FAMILY>
|
||||||
Specifies the protocol family to use. The protocol family identifier can be one of
|
Specifies the protocol family to use. The protocol family identifier can be one of
|
||||||
.BR "inet" , " inet6" , " bridge" , " ipx" , " dnet" , " mpls"
|
.BR "inet" , " inet6" , " bridge" , " mpls"
|
||||||
or
|
or
|
||||||
.BR link .
|
.BR link .
|
||||||
If this option is not present,
|
If this option is not present,
|
||||||
|
|
@ -125,16 +125,6 @@ shortcut for
|
||||||
shortcut for
|
shortcut for
|
||||||
.BR "\-family bridge" .
|
.BR "\-family bridge" .
|
||||||
|
|
||||||
.TP
|
|
||||||
.B \-D
|
|
||||||
shortcut for
|
|
||||||
.BR "\-family decnet" .
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B \-I
|
|
||||||
shortcut for
|
|
||||||
.BR "\-family ipx" .
|
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B \-M
|
.B \-M
|
||||||
shortcut for
|
shortcut for
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
.TH RDMA\-DEV 8 "06 Jul 2017" "iproute2" "Linux"
|
.TH RDMA\-DEV 8 "06 Jul 2017" "iproute2" "Linux"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
rdmak-dev \- RDMA device configuration
|
rdma-dev \- RDMA device configuration
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.sp
|
.sp
|
||||||
.ad l
|
.ad l
|
||||||
|
|
@ -22,10 +22,18 @@ rdmak-dev \- RDMA device configuration
|
||||||
.B rdma dev show
|
.B rdma dev show
|
||||||
.RI "[ " DEV " ]"
|
.RI "[ " DEV " ]"
|
||||||
|
|
||||||
|
.ti -8
|
||||||
|
.B rdma dev set
|
||||||
|
.RI "[ " DEV " ]"
|
||||||
|
.BR name
|
||||||
|
.BR NEWNAME
|
||||||
|
|
||||||
.ti -8
|
.ti -8
|
||||||
.B rdma dev help
|
.B rdma dev help
|
||||||
|
|
||||||
.SH "DESCRIPTION"
|
.SH "DESCRIPTION"
|
||||||
|
.SS rdma dev set - rename rdma device
|
||||||
|
|
||||||
.SS rdma dev show - display rdma device attributes
|
.SS rdma dev show - display rdma device attributes
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
|
|
@ -45,6 +53,11 @@ rdma dev show mlx5_3
|
||||||
Shows the state of specified RDMA device.
|
Shows the state of specified RDMA device.
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
|
rdma dev set mlx5_3 name rdma_0
|
||||||
|
.RS 4
|
||||||
|
Renames the mlx5_3 device to rdma_0.
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.BR rdma (8),
|
.BR rdma (8),
|
||||||
|
|
|
||||||
|
|
@ -56,8 +56,9 @@ flower \- flow based traffic control filter
|
||||||
.IR MASKED_IP_TTL " | { "
|
.IR MASKED_IP_TTL " | { "
|
||||||
.BR dst_ip " | " src_ip " } "
|
.BR dst_ip " | " src_ip " } "
|
||||||
.IR PREFIX " | { "
|
.IR PREFIX " | { "
|
||||||
.BR dst_port " | " src_port " } "
|
.BR dst_port " | " src_port " } { "
|
||||||
.IR port_number " } | "
|
.IR port_number " | "
|
||||||
|
.IR min_port_number-max_port_number " } | "
|
||||||
.B tcp_flags
|
.B tcp_flags
|
||||||
.IR MASKED_TCP_FLAGS " | "
|
.IR MASKED_TCP_FLAGS " | "
|
||||||
.B type
|
.B type
|
||||||
|
|
@ -220,10 +221,12 @@ must be a valid IPv4 or IPv6 address, depending on the \fBprotocol\fR
|
||||||
option to tc filter, optionally followed by a slash and the prefix length.
|
option to tc filter, optionally followed by a slash and the prefix length.
|
||||||
If the prefix is missing, \fBtc\fR assumes a full-length host match.
|
If the prefix is missing, \fBtc\fR assumes a full-length host match.
|
||||||
.TP
|
.TP
|
||||||
.BI dst_port " NUMBER"
|
.IR \fBdst_port " { " NUMBER " | " " MIN_VALUE-MAX_VALUE " }
|
||||||
.TQ
|
.TQ
|
||||||
.BI src_port " NUMBER"
|
.IR \fBsrc_port " { " NUMBER " | " " MIN_VALUE-MAX_VALUE " }
|
||||||
Match on layer 4 protocol source or destination port number. Only available for
|
Match on layer 4 protocol source or destination port number. Alternatively, the
|
||||||
|
mininum and maximum values can be specified to match on a range of layer 4
|
||||||
|
protocol source or destination port numbers. Only available for
|
||||||
.BR ip_proto " values " udp ", " tcp " and " sctp
|
.BR ip_proto " values " udp ", " tcp " and " sctp
|
||||||
which have to be specified in beforehand.
|
which have to be specified in beforehand.
|
||||||
.TP
|
.TP
|
||||||
|
|
|
||||||
|
|
@ -15,23 +15,28 @@ BYTES ] [
|
||||||
.B maxrate
|
.B maxrate
|
||||||
RATE ] [
|
RATE ] [
|
||||||
.B buckets
|
.B buckets
|
||||||
NUMBER ] [
|
NUMBER ] [
|
||||||
|
.B orphan_mask
|
||||||
|
NUMBER ] [
|
||||||
.B pacing
|
.B pacing
|
||||||
|
|
|
|
||||||
.B nopacing
|
.B nopacing
|
||||||
]
|
] [
|
||||||
|
.B ce_threshold
|
||||||
|
TIME ]
|
||||||
|
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
FQ (Fair Queue) is a classless packet scheduler meant to be mostly
|
FQ (Fair Queue) is a classless packet scheduler meant to be mostly
|
||||||
used for locally generated traffic. It is designed to achieve per flow pacing.
|
used for locally generated traffic. It is designed to achieve per flow pacing.
|
||||||
FQ does flow separation, and is able to respect pacing requirements set by TCP stack.
|
FQ does flow separation, and is able to respect pacing requirements set by TCP stack.
|
||||||
All packets belonging to a socket are considered as a 'flow'.
|
All packets belonging to a socket are considered as a 'flow'.
|
||||||
For non local packets (router workload), packet rxhash is used as fallback.
|
For non local packets (router workload), packet hash is used as fallback.
|
||||||
|
|
||||||
An application can specify a maximum pacing rate using the
|
An application can specify a maximum pacing rate using the
|
||||||
.B SO_MAX_PACING_RATE
|
.B SO_MAX_PACING_RATE
|
||||||
setsockopt call. This packet scheduler adds delay between packets to
|
setsockopt call. This packet scheduler adds delay between packets to
|
||||||
respect rate limitation set by TCP stack.
|
respect rate limitation set on each socket. Note that after linux-4.20, linux adopted EDT (Earliest Departure Time)
|
||||||
|
and TCP directly sets the appropriate Departure Time for each skb.
|
||||||
|
|
||||||
Dequeueing happens in a round-robin fashion.
|
Dequeueing happens in a round-robin fashion.
|
||||||
A special FIFO queue is reserved for high priority packets (
|
A special FIFO queue is reserved for high priority packets (
|
||||||
|
|
@ -72,18 +77,28 @@ is ignored only if it is larger than this value.
|
||||||
The size of the hash table used for flow lookups. Each bucket is assigned a
|
The size of the hash table used for flow lookups. Each bucket is assigned a
|
||||||
red-black tree for efficient collision sorting.
|
red-black tree for efficient collision sorting.
|
||||||
Default: 1024.
|
Default: 1024.
|
||||||
|
.SS orphan_mask
|
||||||
|
For packets not owned by a socket, fq is able to mask a part of skb->hash
|
||||||
|
and reduce number of buckets associated with the traffic. This is a DDOS
|
||||||
|
prevention mechanism, and the default is 1023 (meaning no more than 1024 flows
|
||||||
|
are allocated for these packets)
|
||||||
.SS [no]pacing
|
.SS [no]pacing
|
||||||
Enable or disable flow pacing. Default is enabled.
|
Enable or disable flow pacing. Default is enabled.
|
||||||
|
.SS ce_threshold
|
||||||
|
sets a threshold above which all packets are marked with ECN Congestion
|
||||||
|
Experienced. This is useful for DCTCP-style congestion control algorithms that
|
||||||
|
require marking at very shallow queueing thresholds.
|
||||||
|
|
||||||
.SH EXAMPLES
|
.SH EXAMPLES
|
||||||
#tc qdisc add dev eth0 root fq
|
#tc qdisc add dev eth0 root est 1sec 4sec fq ce_threshold 4ms
|
||||||
.br
|
.br
|
||||||
#tc -s -d qdisc
|
#tc -s -d qdisc sh dev eth0
|
||||||
.br
|
.br
|
||||||
qdisc fq 8003: dev eth0 root refcnt 2 limit 10000p flow_limit 100p buckets 1024 quantum 3028 initial_quantum 15140
|
qdisc fq 800e: root refcnt 9 limit 10000p flow_limit 1000p buckets 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 low_rate_threshold 550Kbit refill_delay 40.0ms ce_threshold 4.0ms
|
||||||
Sent 503727981 bytes 1146972 pkt (dropped 0, overlimits 0 requeues 54452)
|
Sent 533368436185 bytes 352296695 pkt (dropped 0, overlimits 0 requeues 1339864)
|
||||||
backlog 0b 0p requeues 54452
|
rate 39220Mbit 3238202pps backlog 12417828b 358p requeues 1339864
|
||||||
1289 flows (1289 inactive, 0 throttled)
|
1052 flows (852 inactive, 0 throttled)
|
||||||
0 gc, 31 highprio, 27411 throttled
|
112 gc, 0 highprio, 212 throttled, 21501 ns latency, 470241 ce_mark
|
||||||
.br
|
.br
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.BR tc (8),
|
.BR tc (8),
|
||||||
|
|
|
||||||
|
|
@ -424,7 +424,7 @@ static int do_one_request(struct nlmsghdr *n)
|
||||||
|
|
||||||
static void load_initial_table(void)
|
static void load_initial_table(void)
|
||||||
{
|
{
|
||||||
if (rtnl_neighdump_req(&rth, AF_INET) < 0) {
|
if (rtnl_neighdump_req(&rth, AF_INET, NULL) < 0) {
|
||||||
perror("dump request failed");
|
perror("dump request failed");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
35
rdma/dev.c
35
rdma/dev.c
|
|
@ -14,6 +14,7 @@
|
||||||
static int dev_help(struct rd *rd)
|
static int dev_help(struct rd *rd)
|
||||||
{
|
{
|
||||||
pr_out("Usage: %s dev show [DEV]\n", rd->filename);
|
pr_out("Usage: %s dev show [DEV]\n", rd->filename);
|
||||||
|
pr_out(" %s dev set [DEV] name DEVNAME\n", rd->filename);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -258,17 +259,51 @@ static int dev_one_show(struct rd *rd)
|
||||||
return rd_exec_cmd(rd, cmds, "parameter");
|
return rd_exec_cmd(rd, cmds, "parameter");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dev_set_name(struct rd *rd)
|
||||||
|
{
|
||||||
|
uint32_t seq;
|
||||||
|
|
||||||
|
if (rd_no_arg(rd)) {
|
||||||
|
pr_err("Please provide device new name.\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rd_prepare_msg(rd, RDMA_NLDEV_CMD_SET,
|
||||||
|
&seq, (NLM_F_REQUEST | NLM_F_ACK));
|
||||||
|
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
|
||||||
|
mnl_attr_put_strz(rd->nlh, RDMA_NLDEV_ATTR_DEV_NAME, rd_argv(rd));
|
||||||
|
|
||||||
|
return rd_send_msg(rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dev_one_set(struct rd *rd)
|
||||||
|
{
|
||||||
|
const struct rd_cmd cmds[] = {
|
||||||
|
{ NULL, dev_help},
|
||||||
|
{ "name", dev_set_name},
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
return rd_exec_cmd(rd, cmds, "parameter");
|
||||||
|
}
|
||||||
|
|
||||||
static int dev_show(struct rd *rd)
|
static int dev_show(struct rd *rd)
|
||||||
{
|
{
|
||||||
return rd_exec_dev(rd, dev_one_show);
|
return rd_exec_dev(rd, dev_one_show);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dev_set(struct rd *rd)
|
||||||
|
{
|
||||||
|
return rd_exec_require_dev(rd, dev_one_set);
|
||||||
|
}
|
||||||
|
|
||||||
int cmd_dev(struct rd *rd)
|
int cmd_dev(struct rd *rd)
|
||||||
{
|
{
|
||||||
const struct rd_cmd cmds[] = {
|
const struct rd_cmd cmds[] = {
|
||||||
{ NULL, dev_show },
|
{ NULL, dev_show },
|
||||||
{ "show", dev_show },
|
{ "show", dev_show },
|
||||||
{ "list", dev_show },
|
{ "list", dev_show },
|
||||||
|
{ "set", dev_set },
|
||||||
{ "help", dev_help },
|
{ "help", dev_help },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
36
rdma/link.c
36
rdma/link.c
|
|
@ -19,7 +19,7 @@ static int link_help(struct rd *rd)
|
||||||
|
|
||||||
static const char *caps_to_str(uint32_t idx)
|
static const char *caps_to_str(uint32_t idx)
|
||||||
{
|
{
|
||||||
#define RDMA_PORT_FLAGS(x) \
|
#define RDMA_PORT_FLAGS_LOW(x) \
|
||||||
x(RESERVED, 0) \
|
x(RESERVED, 0) \
|
||||||
x(SM, 1) \
|
x(SM, 1) \
|
||||||
x(NOTICE, 2) \
|
x(NOTICE, 2) \
|
||||||
|
|
@ -53,13 +53,39 @@ static const char *caps_to_str(uint32_t idx)
|
||||||
x(MULT_FDB, 30) \
|
x(MULT_FDB, 30) \
|
||||||
x(HIERARCHY_INFO, 31)
|
x(HIERARCHY_INFO, 31)
|
||||||
|
|
||||||
enum { RDMA_PORT_FLAGS(RDMA_BITMAP_ENUM) };
|
#define RDMA_PORT_FLAGS_HIGH(x) \
|
||||||
|
x(SET_NODE_DESC, 0) \
|
||||||
|
x(EXT_INFO, 1) \
|
||||||
|
x(VIRT, 2) \
|
||||||
|
x(SWITCH_POR_STATE_TABLE, 3) \
|
||||||
|
x(LINK_WIDTH_2X, 4) \
|
||||||
|
x(LINK_SPEED_HDR, 5)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Separation below is needed to allow compilation of rdmatool
|
||||||
|
* on 32bits systems. On such systems, C-enum is limited to be
|
||||||
|
* int and can't hold more than 32 bits.
|
||||||
|
*/
|
||||||
|
enum { RDMA_PORT_FLAGS_LOW(RDMA_BITMAP_ENUM) };
|
||||||
|
enum { RDMA_PORT_FLAGS_HIGH(RDMA_BITMAP_ENUM) };
|
||||||
|
|
||||||
static const char * const
|
static const char * const
|
||||||
rdma_port_names[] = { RDMA_PORT_FLAGS(RDMA_BITMAP_NAMES) };
|
rdma_port_names_low[] = { RDMA_PORT_FLAGS_LOW(RDMA_BITMAP_NAMES) };
|
||||||
#undef RDMA_PORT_FLAGS
|
static const char * const
|
||||||
|
rdma_port_names_high[] = { RDMA_PORT_FLAGS_HIGH(RDMA_BITMAP_NAMES) };
|
||||||
|
uint32_t high_idx;
|
||||||
|
#undef RDMA_PORT_FLAGS_LOW
|
||||||
|
#undef RDMA_PORT_FLAGS_HIGH
|
||||||
|
|
||||||
return rdma_port_names[idx];
|
if (idx < ARRAY_SIZE(rdma_port_names_low) && rdma_port_names_low[idx])
|
||||||
|
return rdma_port_names_low[idx];
|
||||||
|
|
||||||
|
high_idx = idx - ARRAY_SIZE(rdma_port_names_low);
|
||||||
|
if (high_idx < ARRAY_SIZE(rdma_port_names_high) &&
|
||||||
|
rdma_port_names_high[high_idx])
|
||||||
|
return rdma_port_names_high[high_idx];
|
||||||
|
|
||||||
|
return "UNKNOWN";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void link_print_caps(struct rd *rd, struct nlattr **tb)
|
static void link_print_caps(struct rd *rd, struct nlattr **tb)
|
||||||
|
|
|
||||||
12
rdma/rdma.h
12
rdma/rdma.h
|
|
@ -74,6 +74,13 @@ struct rd_cmd {
|
||||||
int (*func)(struct rd *rd);
|
int (*func)(struct rd *rd);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parser interface
|
||||||
|
*/
|
||||||
|
bool rd_no_arg(struct rd *rd);
|
||||||
|
void rd_arg_inc(struct rd *rd);
|
||||||
|
|
||||||
|
char *rd_argv(struct rd *rd);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Commands interface
|
* Commands interface
|
||||||
|
|
@ -83,11 +90,14 @@ int cmd_link(struct rd *rd);
|
||||||
int cmd_res(struct rd *rd);
|
int cmd_res(struct rd *rd);
|
||||||
int rd_exec_cmd(struct rd *rd, const struct rd_cmd *c, const char *str);
|
int rd_exec_cmd(struct rd *rd, const struct rd_cmd *c, const char *str);
|
||||||
int rd_exec_dev(struct rd *rd, int (*cb)(struct rd *rd));
|
int rd_exec_dev(struct rd *rd, int (*cb)(struct rd *rd));
|
||||||
|
int rd_exec_require_dev(struct rd *rd, int (*cb)(struct rd *rd));
|
||||||
int rd_exec_link(struct rd *rd, int (*cb)(struct rd *rd), bool strict_port);
|
int rd_exec_link(struct rd *rd, int (*cb)(struct rd *rd), bool strict_port);
|
||||||
void rd_free(struct rd *rd);
|
void rd_free(struct rd *rd);
|
||||||
int rd_set_arg_to_devname(struct rd *rd);
|
int rd_set_arg_to_devname(struct rd *rd);
|
||||||
int rd_argc(struct rd *rd);
|
int rd_argc(struct rd *rd);
|
||||||
|
|
||||||
|
int strcmpx(const char *str1, const char *str2);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Device manipulation
|
* Device manipulation
|
||||||
*/
|
*/
|
||||||
|
|
@ -108,12 +118,14 @@ int rd_recv_msg(struct rd *rd, mnl_cb_t callback, void *data, uint32_t seq);
|
||||||
void rd_prepare_msg(struct rd *rd, uint32_t cmd, uint32_t *seq, uint16_t flags);
|
void rd_prepare_msg(struct rd *rd, uint32_t cmd, uint32_t *seq, uint16_t flags);
|
||||||
int rd_dev_init_cb(const struct nlmsghdr *nlh, void *data);
|
int rd_dev_init_cb(const struct nlmsghdr *nlh, void *data);
|
||||||
int rd_attr_cb(const struct nlattr *attr, void *data);
|
int rd_attr_cb(const struct nlattr *attr, void *data);
|
||||||
|
int rd_attr_check(const struct nlattr *attr, int *typep);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print helpers
|
* Print helpers
|
||||||
*/
|
*/
|
||||||
void print_driver_table(struct rd *rd, struct nlattr *tb);
|
void print_driver_table(struct rd *rd, struct nlattr *tb);
|
||||||
void newline(struct rd *rd);
|
void newline(struct rd *rd);
|
||||||
|
void newline_indent(struct rd *rd);
|
||||||
#define MAX_LINE_LENGTH 80
|
#define MAX_LINE_LENGTH 80
|
||||||
|
|
||||||
#endif /* _RDMA_TOOL_H_ */
|
#endif /* _RDMA_TOOL_H_ */
|
||||||
|
|
|
||||||
22
rdma/utils.c
22
rdma/utils.c
|
|
@ -18,14 +18,14 @@ int rd_argc(struct rd *rd)
|
||||||
return rd->argc;
|
return rd->argc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *rd_argv(struct rd *rd)
|
char *rd_argv(struct rd *rd)
|
||||||
{
|
{
|
||||||
if (!rd_argc(rd))
|
if (!rd_argc(rd))
|
||||||
return NULL;
|
return NULL;
|
||||||
return *rd->argv;
|
return *rd->argv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int strcmpx(const char *str1, const char *str2)
|
int strcmpx(const char *str1, const char *str2)
|
||||||
{
|
{
|
||||||
if (strlen(str1) > strlen(str2))
|
if (strlen(str1) > strlen(str2))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -39,7 +39,7 @@ static bool rd_argv_match(struct rd *rd, const char *pattern)
|
||||||
return strcmpx(rd_argv(rd), pattern) == 0;
|
return strcmpx(rd_argv(rd), pattern) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rd_arg_inc(struct rd *rd)
|
void rd_arg_inc(struct rd *rd)
|
||||||
{
|
{
|
||||||
if (!rd_argc(rd))
|
if (!rd_argc(rd))
|
||||||
return;
|
return;
|
||||||
|
|
@ -47,7 +47,7 @@ static void rd_arg_inc(struct rd *rd)
|
||||||
rd->argv++;
|
rd->argv++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool rd_no_arg(struct rd *rd)
|
bool rd_no_arg(struct rd *rd)
|
||||||
{
|
{
|
||||||
return rd_argc(rd) == 0;
|
return rd_argc(rd) == 0;
|
||||||
}
|
}
|
||||||
|
|
@ -404,7 +404,7 @@ static const enum mnl_attr_data_type nldev_policy[RDMA_NLDEV_ATTR_MAX] = {
|
||||||
[RDMA_NLDEV_ATTR_DRIVER_U64] = MNL_TYPE_U64,
|
[RDMA_NLDEV_ATTR_DRIVER_U64] = MNL_TYPE_U64,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int rd_attr_check(const struct nlattr *attr, int *typep)
|
int rd_attr_check(const struct nlattr *attr, int *typep)
|
||||||
{
|
{
|
||||||
int type;
|
int type;
|
||||||
|
|
||||||
|
|
@ -577,6 +577,16 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rd_exec_require_dev(struct rd *rd, int (*cb)(struct rd *rd))
|
||||||
|
{
|
||||||
|
if (rd_no_arg(rd)) {
|
||||||
|
pr_err("Please provide device name.\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rd_exec_dev(rd, cb);
|
||||||
|
}
|
||||||
|
|
||||||
int rd_exec_cmd(struct rd *rd, const struct rd_cmd *cmds, const char *str)
|
int rd_exec_cmd(struct rd *rd, const struct rd_cmd *cmds, const char *str)
|
||||||
{
|
{
|
||||||
const struct rd_cmd *c;
|
const struct rd_cmd *c;
|
||||||
|
|
@ -696,7 +706,7 @@ void newline(struct rd *rd)
|
||||||
pr_out("\n");
|
pr_out("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void newline_indent(struct rd *rd)
|
void newline_indent(struct rd *rd)
|
||||||
{
|
{
|
||||||
newline(rd);
|
newline(rd);
|
||||||
if (!rd->json_output)
|
if (!rd->json_output)
|
||||||
|
|
|
||||||
|
|
@ -473,24 +473,57 @@ static int flower_port_attr_type(__u8 ip_proto, enum flower_endpoint endpoint)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int flower_port_range_attr_type(__u8 ip_proto, enum flower_endpoint type,
|
||||||
|
__be16 *min_port_type,
|
||||||
|
__be16 *max_port_type)
|
||||||
|
{
|
||||||
|
if (ip_proto == IPPROTO_TCP || ip_proto == IPPROTO_UDP ||
|
||||||
|
ip_proto == IPPROTO_SCTP) {
|
||||||
|
if (type == FLOWER_ENDPOINT_SRC) {
|
||||||
|
*min_port_type = TCA_FLOWER_KEY_PORT_SRC_MIN;
|
||||||
|
*max_port_type = TCA_FLOWER_KEY_PORT_SRC_MAX;
|
||||||
|
} else {
|
||||||
|
*min_port_type = TCA_FLOWER_KEY_PORT_DST_MIN;
|
||||||
|
*max_port_type = TCA_FLOWER_KEY_PORT_DST_MAX;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int flower_parse_port(char *str, __u8 ip_proto,
|
static int flower_parse_port(char *str, __u8 ip_proto,
|
||||||
enum flower_endpoint endpoint,
|
enum flower_endpoint endpoint,
|
||||||
struct nlmsghdr *n)
|
struct nlmsghdr *n)
|
||||||
{
|
{
|
||||||
|
__u16 min, max;
|
||||||
int ret;
|
int ret;
|
||||||
int type;
|
|
||||||
__be16 port;
|
|
||||||
|
|
||||||
type = flower_port_attr_type(ip_proto, endpoint);
|
ret = sscanf(str, "%hu-%hu", &min, &max);
|
||||||
if (type < 0)
|
|
||||||
|
if (ret == 1) {
|
||||||
|
int type;
|
||||||
|
|
||||||
|
type = flower_port_attr_type(ip_proto, endpoint);
|
||||||
|
if (type < 0)
|
||||||
|
return -1;
|
||||||
|
addattr16(n, MAX_MSG, type, htons(min));
|
||||||
|
} else if (ret == 2) {
|
||||||
|
__be16 min_port_type, max_port_type;
|
||||||
|
|
||||||
|
if (max <= min) {
|
||||||
|
fprintf(stderr, "max value should be greater than min value\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (flower_port_range_attr_type(ip_proto, endpoint,
|
||||||
|
&min_port_type, &max_port_type))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
addattr16(n, MAX_MSG, min_port_type, htons(min));
|
||||||
|
addattr16(n, MAX_MSG, max_port_type, htons(max));
|
||||||
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
ret = get_be16(&port, str, 10);
|
|
||||||
if (ret)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
addattr16(n, MAX_MSG, type, port);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1490,6 +1523,29 @@ static void flower_print_port(char *name, struct rtattr *attr)
|
||||||
print_hu(PRINT_ANY, name, namefrm, rta_getattr_be16(attr));
|
print_hu(PRINT_ANY, name, namefrm, rta_getattr_be16(attr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void flower_print_port_range(char *name, struct rtattr *min_attr,
|
||||||
|
struct rtattr *max_attr)
|
||||||
|
{
|
||||||
|
if (!min_attr || !max_attr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (is_json_context()) {
|
||||||
|
open_json_object(name);
|
||||||
|
print_hu(PRINT_JSON, "start", NULL, rta_getattr_be16(min_attr));
|
||||||
|
print_hu(PRINT_JSON, "end", NULL, rta_getattr_be16(max_attr));
|
||||||
|
close_json_object();
|
||||||
|
} else {
|
||||||
|
SPRINT_BUF(namefrm);
|
||||||
|
SPRINT_BUF(out);
|
||||||
|
size_t done;
|
||||||
|
|
||||||
|
done = sprintf(out, "%u", rta_getattr_be16(min_attr));
|
||||||
|
sprintf(out + done, "-%u", rta_getattr_be16(max_attr));
|
||||||
|
sprintf(namefrm, "\n %s %%s", name);
|
||||||
|
print_string(PRINT_ANY, name, namefrm, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void flower_print_tcp_flags(const char *name, struct rtattr *flags_attr,
|
static void flower_print_tcp_flags(const char *name, struct rtattr *flags_attr,
|
||||||
struct rtattr *mask_attr)
|
struct rtattr *mask_attr)
|
||||||
{
|
{
|
||||||
|
|
@ -1678,6 +1734,7 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
|
||||||
struct rtattr *opt, __u32 handle)
|
struct rtattr *opt, __u32 handle)
|
||||||
{
|
{
|
||||||
struct rtattr *tb[TCA_FLOWER_MAX + 1];
|
struct rtattr *tb[TCA_FLOWER_MAX + 1];
|
||||||
|
__be16 min_port_type, max_port_type;
|
||||||
int nl_type, nl_mask_type;
|
int nl_type, nl_mask_type;
|
||||||
__be16 eth_type = 0;
|
__be16 eth_type = 0;
|
||||||
__u8 ip_proto = 0xff;
|
__u8 ip_proto = 0xff;
|
||||||
|
|
@ -1796,6 +1853,16 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
|
||||||
if (nl_type >= 0)
|
if (nl_type >= 0)
|
||||||
flower_print_port("src_port", tb[nl_type]);
|
flower_print_port("src_port", tb[nl_type]);
|
||||||
|
|
||||||
|
if (!flower_port_range_attr_type(ip_proto, FLOWER_ENDPOINT_DST,
|
||||||
|
&min_port_type, &max_port_type))
|
||||||
|
flower_print_port_range("dst_port",
|
||||||
|
tb[min_port_type], tb[max_port_type]);
|
||||||
|
|
||||||
|
if (!flower_port_range_attr_type(ip_proto, FLOWER_ENDPOINT_SRC,
|
||||||
|
&min_port_type, &max_port_type))
|
||||||
|
flower_print_port_range("src_port",
|
||||||
|
tb[min_port_type], tb[max_port_type]);
|
||||||
|
|
||||||
flower_print_tcp_flags("tcp_flags", tb[TCA_FLOWER_KEY_TCP_FLAGS],
|
flower_print_tcp_flags("tcp_flags", tb[TCA_FLOWER_KEY_TCP_FLAGS],
|
||||||
tb[TCA_FLOWER_KEY_TCP_FLAGS_MASK]);
|
tb[TCA_FLOWER_KEY_TCP_FLAGS_MASK]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -188,8 +188,7 @@ static int choke_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
|
||||||
fprintf(f, "limit %up min %up max %up ",
|
fprintf(f, "limit %up min %up max %up ",
|
||||||
qopt->limit, qopt->qth_min, qopt->qth_max);
|
qopt->limit, qopt->qth_min, qopt->qth_max);
|
||||||
|
|
||||||
if (qopt->flags & TC_RED_ECN)
|
tc_red_print_flags(qopt->flags);
|
||||||
fprintf(f, "ecn ");
|
|
||||||
|
|
||||||
if (show_details) {
|
if (show_details) {
|
||||||
fprintf(f, "ewma %u ", qopt->Wlog);
|
fprintf(f, "ewma %u ", qopt->Wlog);
|
||||||
|
|
|
||||||
32
tc/q_fq.c
32
tc/q_fq.c
|
|
@ -56,6 +56,7 @@ static void explain(void)
|
||||||
fprintf(stderr, " [ [no]pacing ] [ refill_delay TIME ]\n");
|
fprintf(stderr, " [ [no]pacing ] [ refill_delay TIME ]\n");
|
||||||
fprintf(stderr, " [ low_rate_threshold RATE ]\n");
|
fprintf(stderr, " [ low_rate_threshold RATE ]\n");
|
||||||
fprintf(stderr, " [ orphan_mask MASK]\n");
|
fprintf(stderr, " [ orphan_mask MASK]\n");
|
||||||
|
fprintf(stderr, " [ ce_threshold TIME ]\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int ilog2(unsigned int val)
|
static unsigned int ilog2(unsigned int val)
|
||||||
|
|
@ -83,6 +84,7 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||||
unsigned int defrate;
|
unsigned int defrate;
|
||||||
unsigned int refill_delay;
|
unsigned int refill_delay;
|
||||||
unsigned int orphan_mask;
|
unsigned int orphan_mask;
|
||||||
|
unsigned int ce_threshold;
|
||||||
bool set_plimit = false;
|
bool set_plimit = false;
|
||||||
bool set_flow_plimit = false;
|
bool set_flow_plimit = false;
|
||||||
bool set_quantum = false;
|
bool set_quantum = false;
|
||||||
|
|
@ -92,6 +94,7 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||||
bool set_refill_delay = false;
|
bool set_refill_delay = false;
|
||||||
bool set_orphan_mask = false;
|
bool set_orphan_mask = false;
|
||||||
bool set_low_rate_threshold = false;
|
bool set_low_rate_threshold = false;
|
||||||
|
bool set_ce_threshold = false;
|
||||||
int pacing = -1;
|
int pacing = -1;
|
||||||
struct rtattr *tail;
|
struct rtattr *tail;
|
||||||
|
|
||||||
|
|
@ -135,6 +138,13 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
set_low_rate_threshold = true;
|
set_low_rate_threshold = true;
|
||||||
|
} else if (strcmp(*argv, "ce_threshold") == 0) {
|
||||||
|
NEXT_ARG();
|
||||||
|
if (get_time(&ce_threshold, *argv)) {
|
||||||
|
fprintf(stderr, "Illegal \"ce_threshold\"\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
set_ce_threshold = true;
|
||||||
} else if (strcmp(*argv, "defrate") == 0) {
|
} else if (strcmp(*argv, "defrate") == 0) {
|
||||||
NEXT_ARG();
|
NEXT_ARG();
|
||||||
if (strchr(*argv, '%')) {
|
if (strchr(*argv, '%')) {
|
||||||
|
|
@ -226,6 +236,9 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||||
if (set_orphan_mask)
|
if (set_orphan_mask)
|
||||||
addattr_l(n, 1024, TCA_FQ_ORPHAN_MASK,
|
addattr_l(n, 1024, TCA_FQ_ORPHAN_MASK,
|
||||||
&orphan_mask, sizeof(refill_delay));
|
&orphan_mask, sizeof(refill_delay));
|
||||||
|
if (set_ce_threshold)
|
||||||
|
addattr_l(n, 1024, TCA_FQ_CE_THRESHOLD,
|
||||||
|
&ce_threshold, sizeof(ce_threshold));
|
||||||
addattr_nest_end(n, tail);
|
addattr_nest_end(n, tail);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -239,6 +252,7 @@ static int fq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
|
||||||
unsigned int rate, quantum;
|
unsigned int rate, quantum;
|
||||||
unsigned int refill_delay;
|
unsigned int refill_delay;
|
||||||
unsigned int orphan_mask;
|
unsigned int orphan_mask;
|
||||||
|
unsigned int ce_threshold;
|
||||||
|
|
||||||
SPRINT_BUF(b1);
|
SPRINT_BUF(b1);
|
||||||
|
|
||||||
|
|
@ -310,21 +324,28 @@ static int fq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
|
||||||
fprintf(f, "refill_delay %s ", sprint_time(refill_delay, b1));
|
fprintf(f, "refill_delay %s ", sprint_time(refill_delay, b1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tb[TCA_FQ_CE_THRESHOLD] &&
|
||||||
|
RTA_PAYLOAD(tb[TCA_FQ_CE_THRESHOLD]) >= sizeof(__u32)) {
|
||||||
|
ce_threshold = rta_getattr_u32(tb[TCA_FQ_CE_THRESHOLD]);
|
||||||
|
if (ce_threshold != ~0U)
|
||||||
|
fprintf(f, "ce_threshold %s ", sprint_time(ce_threshold, b1));
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fq_print_xstats(struct qdisc_util *qu, FILE *f,
|
static int fq_print_xstats(struct qdisc_util *qu, FILE *f,
|
||||||
struct rtattr *xstats)
|
struct rtattr *xstats)
|
||||||
{
|
{
|
||||||
struct tc_fq_qd_stats *st;
|
struct tc_fq_qd_stats *st, _st;
|
||||||
|
|
||||||
if (xstats == NULL)
|
if (xstats == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (RTA_PAYLOAD(xstats) < sizeof(*st))
|
memset(&_st, 0, sizeof(_st));
|
||||||
return -1;
|
memcpy(&_st, RTA_DATA(xstats), min(RTA_PAYLOAD(xstats), sizeof(*st)));
|
||||||
|
|
||||||
st = RTA_DATA(xstats);
|
st = &_st;
|
||||||
|
|
||||||
fprintf(f, " %u flows (%u inactive, %u throttled)",
|
fprintf(f, " %u flows (%u inactive, %u throttled)",
|
||||||
st->flows, st->inactive_flows, st->throttled_flows);
|
st->flows, st->inactive_flows, st->throttled_flows);
|
||||||
|
|
@ -343,6 +364,9 @@ static int fq_print_xstats(struct qdisc_util *qu, FILE *f,
|
||||||
if (st->unthrottle_latency_ns)
|
if (st->unthrottle_latency_ns)
|
||||||
fprintf(f, ", %u ns latency", st->unthrottle_latency_ns);
|
fprintf(f, ", %u ns latency", st->unthrottle_latency_ns);
|
||||||
|
|
||||||
|
if (st->ce_mark)
|
||||||
|
fprintf(f, ", %llu ce_mark", st->ce_mark);
|
||||||
|
|
||||||
if (st->flows_plimit)
|
if (st->flows_plimit)
|
||||||
fprintf(f, ", %llu flows_plimit", st->flows_plimit);
|
fprintf(f, ", %llu flows_plimit", st->flows_plimit);
|
||||||
|
|
||||||
|
|
|
||||||
266
tc/q_gred.c
266
tc/q_gred.c
|
|
@ -37,10 +37,10 @@
|
||||||
static void explain(void)
|
static void explain(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: tc qdisc { add | replace | change } ... gred setup vqs NUMBER\n");
|
fprintf(stderr, "Usage: tc qdisc { add | replace | change } ... gred setup vqs NUMBER\n");
|
||||||
fprintf(stderr, " default DEFAULT_VQ [ grio ] [ limit BYTES ]\n");
|
fprintf(stderr, " default DEFAULT_VQ [ grio ] [ limit BYTES ] [ecn] [harddrop]\n");
|
||||||
fprintf(stderr, " tc qdisc change ... gred vq VQ [ prio VALUE ] limit BYTES\n");
|
fprintf(stderr, " tc qdisc change ... gred vq VQ [ prio VALUE ] limit BYTES\n");
|
||||||
fprintf(stderr, " min BYTES max BYTES avpkt BYTES [ burst PACKETS ]\n");
|
fprintf(stderr, " min BYTES max BYTES avpkt BYTES [ burst PACKETS ]\n");
|
||||||
fprintf(stderr, " [ probability PROBABILITY ] [ bandwidth KBPS ]\n");
|
fprintf(stderr, " [ probability PROBABILITY ] [ bandwidth KBPS ] [ecn] [harddrop]\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int init_gred(struct qdisc_util *qu, int argc, char **argv,
|
static int init_gred(struct qdisc_util *qu, int argc, char **argv,
|
||||||
|
|
@ -87,6 +87,10 @@ static int init_gred(struct qdisc_util *qu, int argc, char **argv,
|
||||||
fprintf(stderr, "Illegal \"limit\"\n");
|
fprintf(stderr, "Illegal \"limit\"\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
} else if (strcmp(*argv, "ecn") == 0) {
|
||||||
|
opt.flags |= TC_RED_ECN;
|
||||||
|
} else if (strcmp(*argv, "harddrop") == 0) {
|
||||||
|
opt.flags |= TC_RED_HARDDROP;
|
||||||
} else if (strcmp(*argv, "help") == 0) {
|
} else if (strcmp(*argv, "help") == 0) {
|
||||||
explain();
|
explain();
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -117,15 +121,16 @@ static int init_gred(struct qdisc_util *qu, int argc, char **argv,
|
||||||
*/
|
*/
|
||||||
static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
|
static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
|
||||||
{
|
{
|
||||||
|
struct rtattr *tail, *entry, *vqs;
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
struct tc_gred_qopt opt = { 0 };
|
struct tc_gred_qopt opt = { 0 };
|
||||||
unsigned int burst = 0;
|
unsigned int burst = 0;
|
||||||
unsigned int avpkt = 0;
|
unsigned int avpkt = 0;
|
||||||
|
unsigned int flags = 0;
|
||||||
double probability = 0.02;
|
double probability = 0.02;
|
||||||
unsigned int rate = 0;
|
unsigned int rate = 0;
|
||||||
int parm;
|
int parm;
|
||||||
__u8 sbuf[256];
|
__u8 sbuf[256];
|
||||||
struct rtattr *tail;
|
|
||||||
__u32 max_P;
|
__u32 max_P;
|
||||||
|
|
||||||
opt.DP = MAX_DPs;
|
opt.DP = MAX_DPs;
|
||||||
|
|
@ -208,6 +213,10 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ok++;
|
ok++;
|
||||||
|
} else if (strcmp(*argv, "ecn") == 0) {
|
||||||
|
flags |= TC_RED_ECN;
|
||||||
|
} else if (strcmp(*argv, "harddrop") == 0) {
|
||||||
|
flags |= TC_RED_HARDDROP;
|
||||||
} else if (strcmp(*argv, "help") == 0) {
|
} else if (strcmp(*argv, "help") == 0) {
|
||||||
explain();
|
explain();
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -261,22 +270,167 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n
|
||||||
addattr_l(n, 1024, TCA_GRED_STAB, sbuf, 256);
|
addattr_l(n, 1024, TCA_GRED_STAB, sbuf, 256);
|
||||||
max_P = probability * pow(2, 32);
|
max_P = probability * pow(2, 32);
|
||||||
addattr32(n, 1024, TCA_GRED_MAX_P, max_P);
|
addattr32(n, 1024, TCA_GRED_MAX_P, max_P);
|
||||||
|
|
||||||
|
vqs = addattr_nest(n, 1024, TCA_GRED_VQ_LIST);
|
||||||
|
entry = addattr_nest(n, 1024, TCA_GRED_VQ_ENTRY);
|
||||||
|
addattr32(n, 1024, TCA_GRED_VQ_DP, opt.DP);
|
||||||
|
addattr32(n, 1024, TCA_GRED_VQ_FLAGS, flags);
|
||||||
|
addattr_nest_end(n, entry);
|
||||||
|
addattr_nest_end(n, vqs);
|
||||||
|
|
||||||
addattr_nest_end(n, tail);
|
addattr_nest_end(n, tail);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct tc_gred_info {
|
||||||
|
bool flags_present;
|
||||||
|
__u64 bytes;
|
||||||
|
__u32 packets;
|
||||||
|
__u32 backlog;
|
||||||
|
__u32 prob_drop;
|
||||||
|
__u32 prob_mark;
|
||||||
|
__u32 forced_drop;
|
||||||
|
__u32 forced_mark;
|
||||||
|
__u32 pdrop;
|
||||||
|
__u32 other;
|
||||||
|
__u32 flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
gred_parse_vqs(struct tc_gred_info *info, struct rtattr *vqs)
|
||||||
|
{
|
||||||
|
int rem = RTA_PAYLOAD(vqs);
|
||||||
|
unsigned int offset = 0;
|
||||||
|
|
||||||
|
while (rem > offset) {
|
||||||
|
struct rtattr *tb_entry[TCA_GRED_VQ_ENTRY_MAX + 1] = {};
|
||||||
|
struct rtattr *tb[TCA_GRED_VQ_MAX + 1] = {};
|
||||||
|
struct rtattr *entry;
|
||||||
|
unsigned int len;
|
||||||
|
unsigned int dp;
|
||||||
|
|
||||||
|
entry = RTA_DATA(vqs) + offset;
|
||||||
|
|
||||||
|
parse_rtattr(tb_entry, TCA_GRED_VQ_ENTRY_MAX, entry,
|
||||||
|
rem - offset);
|
||||||
|
len = RTA_LENGTH(RTA_PAYLOAD(entry));
|
||||||
|
offset += len;
|
||||||
|
|
||||||
|
if (!tb_entry[TCA_GRED_VQ_ENTRY]) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR: Failed to parse Virtual Queue entry\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_rtattr_nested(tb, TCA_GRED_VQ_MAX,
|
||||||
|
tb_entry[TCA_GRED_VQ_ENTRY]);
|
||||||
|
|
||||||
|
if (!tb[TCA_GRED_VQ_DP]) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR: Virtual Queue without DP attribute\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dp = rta_getattr_u32(tb[TCA_GRED_VQ_DP]);
|
||||||
|
|
||||||
|
if (tb[TCA_GRED_VQ_STAT_BYTES])
|
||||||
|
info[dp].bytes =
|
||||||
|
rta_getattr_u32(tb[TCA_GRED_VQ_STAT_BYTES]);
|
||||||
|
if (tb[TCA_GRED_VQ_STAT_PACKETS])
|
||||||
|
info[dp].packets =
|
||||||
|
rta_getattr_u32(tb[TCA_GRED_VQ_STAT_PACKETS]);
|
||||||
|
if (tb[TCA_GRED_VQ_STAT_BACKLOG])
|
||||||
|
info[dp].backlog =
|
||||||
|
rta_getattr_u32(tb[TCA_GRED_VQ_STAT_BACKLOG]);
|
||||||
|
if (tb[TCA_GRED_VQ_STAT_PROB_DROP])
|
||||||
|
info[dp].prob_drop =
|
||||||
|
rta_getattr_u32(tb[TCA_GRED_VQ_STAT_PROB_DROP]);
|
||||||
|
if (tb[TCA_GRED_VQ_STAT_PROB_MARK])
|
||||||
|
info[dp].prob_mark =
|
||||||
|
rta_getattr_u32(tb[TCA_GRED_VQ_STAT_PROB_MARK]);
|
||||||
|
if (tb[TCA_GRED_VQ_STAT_FORCED_DROP])
|
||||||
|
info[dp].forced_drop =
|
||||||
|
rta_getattr_u32(tb[TCA_GRED_VQ_STAT_FORCED_DROP]);
|
||||||
|
if (tb[TCA_GRED_VQ_STAT_FORCED_MARK])
|
||||||
|
info[dp].forced_mark =
|
||||||
|
rta_getattr_u32(tb[TCA_GRED_VQ_STAT_FORCED_MARK]);
|
||||||
|
if (tb[TCA_GRED_VQ_STAT_PDROP])
|
||||||
|
info[dp].pdrop =
|
||||||
|
rta_getattr_u32(tb[TCA_GRED_VQ_STAT_PDROP]);
|
||||||
|
if (tb[TCA_GRED_VQ_STAT_OTHER])
|
||||||
|
info[dp].other =
|
||||||
|
rta_getattr_u32(tb[TCA_GRED_VQ_STAT_OTHER]);
|
||||||
|
info[dp].flags_present = !!tb[TCA_GRED_VQ_FLAGS];
|
||||||
|
if (tb[TCA_GRED_VQ_FLAGS])
|
||||||
|
info[dp].flags =
|
||||||
|
rta_getattr_u32(tb[TCA_GRED_VQ_FLAGS]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gred_print_stats(struct tc_gred_info *info, struct tc_gred_qopt *qopt)
|
||||||
|
{
|
||||||
|
__u64 bytes = info ? info->bytes : qopt->bytesin;
|
||||||
|
|
||||||
|
SPRINT_BUF(b1);
|
||||||
|
|
||||||
|
if (!is_json_context())
|
||||||
|
printf("\n Queue size: ");
|
||||||
|
|
||||||
|
print_uint(PRINT_JSON, "qave", NULL, qopt->qave);
|
||||||
|
print_string(PRINT_FP, NULL, "average %s ",
|
||||||
|
sprint_size(qopt->qave, b1));
|
||||||
|
|
||||||
|
print_uint(PRINT_JSON, "backlog", NULL, qopt->backlog);
|
||||||
|
print_string(PRINT_FP, NULL, "current %s ",
|
||||||
|
sprint_size(qopt->backlog, b1));
|
||||||
|
|
||||||
|
if (!is_json_context())
|
||||||
|
printf("\n Dropped packets: ");
|
||||||
|
|
||||||
|
if (info) {
|
||||||
|
print_uint(PRINT_ANY, "forced_drop", "forced %u ",
|
||||||
|
info->forced_drop);
|
||||||
|
print_uint(PRINT_ANY, "prob_drop", "early %u ",
|
||||||
|
info->prob_drop);
|
||||||
|
print_uint(PRINT_ANY, "pdrop", "pdrop %u ", info->pdrop);
|
||||||
|
print_uint(PRINT_ANY, "other", "other %u ", info->other);
|
||||||
|
|
||||||
|
if (!is_json_context())
|
||||||
|
printf("\n Marked packets: ");
|
||||||
|
print_uint(PRINT_ANY, "forced_mark", "forced %u ",
|
||||||
|
info->forced_mark);
|
||||||
|
print_uint(PRINT_ANY, "prob_mark", "early %u ",
|
||||||
|
info->prob_mark);
|
||||||
|
} else {
|
||||||
|
print_uint(PRINT_ANY, "forced_drop", "forced %u ",
|
||||||
|
qopt->forced);
|
||||||
|
print_uint(PRINT_ANY, "prob_drop", "early %u ", qopt->early);
|
||||||
|
print_uint(PRINT_ANY, "pdrop", "pdrop %u ", qopt->pdrop);
|
||||||
|
print_uint(PRINT_ANY, "other", "other %u ", qopt->other);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_json_context())
|
||||||
|
printf("\n Total packets: ");
|
||||||
|
|
||||||
|
print_uint(PRINT_ANY, "packets", "%u ", qopt->packets);
|
||||||
|
|
||||||
|
print_uint(PRINT_JSON, "bytes", NULL, bytes);
|
||||||
|
print_string(PRINT_FP, NULL, "(%s) ", sprint_size(bytes, b1));
|
||||||
|
}
|
||||||
|
|
||||||
static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
|
static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
|
||||||
{
|
{
|
||||||
|
struct tc_gred_info infos[MAX_DPs] = {};
|
||||||
struct rtattr *tb[TCA_GRED_MAX + 1];
|
struct rtattr *tb[TCA_GRED_MAX + 1];
|
||||||
struct tc_gred_sopt *sopt;
|
struct tc_gred_sopt *sopt;
|
||||||
struct tc_gred_qopt *qopt;
|
struct tc_gred_qopt *qopt;
|
||||||
|
bool vq_info = false;
|
||||||
__u32 *max_p = NULL;
|
__u32 *max_p = NULL;
|
||||||
__u32 *limit = NULL;
|
__u32 *limit = NULL;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
SPRINT_BUF(b1);
|
SPRINT_BUF(b1);
|
||||||
SPRINT_BUF(b2);
|
|
||||||
SPRINT_BUF(b3);
|
|
||||||
|
|
||||||
if (opt == NULL)
|
if (opt == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -302,47 +456,69 @@ static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bad hack! should really return a proper message as shown above*/
|
if (tb[TCA_GRED_VQ_LIST]) {
|
||||||
|
gred_parse_vqs(infos, tb[TCA_GRED_VQ_LIST]);
|
||||||
fprintf(f, "vqs %u default %u %s",
|
vq_info = true;
|
||||||
sopt->DPs,
|
|
||||||
sopt->def_DP,
|
|
||||||
sopt->grio ? "grio " : "");
|
|
||||||
|
|
||||||
if (limit)
|
|
||||||
fprintf(f, "limit %s ",
|
|
||||||
sprint_size(*limit, b1));
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_DPs; i++, qopt++) {
|
|
||||||
if (qopt->DP >= MAX_DPs) continue;
|
|
||||||
fprintf(f, "\n vq %u prio %hhu limit %s min %s max %s ",
|
|
||||||
qopt->DP,
|
|
||||||
qopt->prio,
|
|
||||||
sprint_size(qopt->limit, b1),
|
|
||||||
sprint_size(qopt->qth_min, b2),
|
|
||||||
sprint_size(qopt->qth_max, b3));
|
|
||||||
if (show_details) {
|
|
||||||
fprintf(f, "ewma %u ", qopt->Wlog);
|
|
||||||
if (max_p)
|
|
||||||
fprintf(f, "probability %lg ", max_p[i] / pow(2, 32));
|
|
||||||
else
|
|
||||||
fprintf(f, "Plog %u ", qopt->Plog);
|
|
||||||
fprintf(f, "Scell_log %u ", qopt->Scell_log);
|
|
||||||
}
|
|
||||||
if (show_stats) {
|
|
||||||
fprintf(f, "\n Queue size: average %s current %s ",
|
|
||||||
sprint_size(qopt->qave, b1),
|
|
||||||
sprint_size(qopt->backlog, b2));
|
|
||||||
fprintf(f, "\n Dropped packets: forced %u early %u pdrop %u other %u ",
|
|
||||||
qopt->forced,
|
|
||||||
qopt->early,
|
|
||||||
qopt->pdrop,
|
|
||||||
qopt->other);
|
|
||||||
fprintf(f, "\n Total packets: %u (%s) ",
|
|
||||||
qopt->packets,
|
|
||||||
sprint_size(qopt->bytesin, b1));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print_uint(PRINT_ANY, "dp_cnt", "vqs %u ", sopt->DPs);
|
||||||
|
print_uint(PRINT_ANY, "dp_default", "default %u ", sopt->def_DP);
|
||||||
|
|
||||||
|
if (sopt->grio)
|
||||||
|
print_bool(PRINT_ANY, "grio", "grio ", true);
|
||||||
|
else
|
||||||
|
print_bool(PRINT_ANY, "grio", NULL, false);
|
||||||
|
|
||||||
|
if (limit) {
|
||||||
|
print_uint(PRINT_JSON, "limit", NULL, *limit);
|
||||||
|
print_string(PRINT_FP, NULL, "limit %s ",
|
||||||
|
sprint_size(*limit, b1));
|
||||||
|
}
|
||||||
|
|
||||||
|
tc_red_print_flags(sopt->flags);
|
||||||
|
|
||||||
|
open_json_array(PRINT_JSON, "vqs");
|
||||||
|
for (i = 0; i < MAX_DPs; i++, qopt++) {
|
||||||
|
if (qopt->DP >= MAX_DPs)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
open_json_object(NULL);
|
||||||
|
|
||||||
|
print_uint(PRINT_ANY, "vq", "\n vq %u ", qopt->DP);
|
||||||
|
print_hhu(PRINT_ANY, "prio", "prio %hhu ", qopt->prio);
|
||||||
|
|
||||||
|
print_uint(PRINT_JSON, "limit", NULL, qopt->limit);
|
||||||
|
print_string(PRINT_FP, NULL, "limit %s ",
|
||||||
|
sprint_size(qopt->limit, b1));
|
||||||
|
|
||||||
|
print_uint(PRINT_JSON, "min", NULL, qopt->qth_min);
|
||||||
|
print_string(PRINT_FP, NULL, "min %s ",
|
||||||
|
sprint_size(qopt->qth_min, b1));
|
||||||
|
|
||||||
|
print_uint(PRINT_JSON, "max", NULL, qopt->qth_max);
|
||||||
|
print_string(PRINT_FP, NULL, "max %s ",
|
||||||
|
sprint_size(qopt->qth_max, b1));
|
||||||
|
|
||||||
|
if (infos[i].flags_present)
|
||||||
|
tc_red_print_flags(infos[i].flags);
|
||||||
|
|
||||||
|
if (show_details) {
|
||||||
|
print_uint(PRINT_ANY, "ewma", "ewma %u ", qopt->Wlog);
|
||||||
|
if (max_p)
|
||||||
|
print_float(PRINT_ANY, "probability",
|
||||||
|
"probability %lg ",
|
||||||
|
max_p[i] / pow(2, 32));
|
||||||
|
else
|
||||||
|
print_uint(PRINT_ANY, "Plog", "Plog %u ",
|
||||||
|
qopt->Plog);
|
||||||
|
print_uint(PRINT_ANY, "Scell_log", "Scell_log %u ",
|
||||||
|
qopt->Scell_log);
|
||||||
|
}
|
||||||
|
if (show_stats)
|
||||||
|
gred_print_stats(vq_info ? &infos[i] : NULL, qopt);
|
||||||
|
close_json_object();
|
||||||
|
}
|
||||||
|
close_json_array(PRINT_JSON, "vqs");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
14
tc/q_red.c
14
tc/q_red.c
|
|
@ -189,18 +189,8 @@ static int red_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
|
||||||
print_uint(PRINT_JSON, "max", NULL, qopt->qth_max);
|
print_uint(PRINT_JSON, "max", NULL, qopt->qth_max);
|
||||||
print_string(PRINT_FP, NULL, "max %s ", sprint_size(qopt->qth_max, b3));
|
print_string(PRINT_FP, NULL, "max %s ", sprint_size(qopt->qth_max, b3));
|
||||||
|
|
||||||
if (qopt->flags & TC_RED_ECN)
|
tc_red_print_flags(qopt->flags);
|
||||||
print_bool(PRINT_ANY, "ecn", "ecn ", true);
|
|
||||||
else
|
|
||||||
print_bool(PRINT_ANY, "ecn", NULL, false);
|
|
||||||
if (qopt->flags & TC_RED_HARDDROP)
|
|
||||||
print_bool(PRINT_ANY, "harddrop", "harddrop ", true);
|
|
||||||
else
|
|
||||||
print_bool(PRINT_ANY, "harddrop", NULL, false);
|
|
||||||
if (qopt->flags & TC_RED_ADAPTATIVE)
|
|
||||||
print_bool(PRINT_ANY, "adaptive", "adaptive ", true);
|
|
||||||
else
|
|
||||||
print_bool(PRINT_ANY, "adaptive", NULL, false);
|
|
||||||
if (show_details) {
|
if (show_details) {
|
||||||
print_uint(PRINT_ANY, "ewma", "ewma %u ", qopt->Wlog);
|
print_uint(PRINT_ANY, "ewma", "ewma %u ", qopt->Wlog);
|
||||||
if (max_P)
|
if (max_P)
|
||||||
|
|
|
||||||
|
|
@ -235,8 +235,7 @@ static int sfq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
|
||||||
sprint_size(qopt_ext->qth_min, b2),
|
sprint_size(qopt_ext->qth_min, b2),
|
||||||
sprint_size(qopt_ext->qth_max, b3),
|
sprint_size(qopt_ext->qth_max, b3),
|
||||||
qopt_ext->max_P / pow(2, 32));
|
qopt_ext->max_P / pow(2, 32));
|
||||||
if (qopt_ext->flags & TC_RED_ECN)
|
tc_red_print_flags(qopt_ext->flags);
|
||||||
fprintf(f, "ecn ");
|
|
||||||
if (show_stats) {
|
if (show_stats) {
|
||||||
fprintf(f, "\n prob_mark %u prob_mark_head %u prob_drop %u",
|
fprintf(f, "\n prob_mark %u prob_mark_head %u prob_drop %u",
|
||||||
qopt_ext->stats.prob_mark,
|
qopt_ext->stats.prob_mark,
|
||||||
|
|
|
||||||
20
tc/tc_red.c
20
tc/tc_red.c
|
|
@ -20,7 +20,9 @@
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
#include "tc_core.h"
|
#include "tc_core.h"
|
||||||
|
#include "tc_util.h"
|
||||||
#include "tc_red.h"
|
#include "tc_red.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -97,3 +99,21 @@ int tc_red_eval_idle_damping(int Wlog, unsigned int avpkt, unsigned int bps, __u
|
||||||
sbuf[255] = 31;
|
sbuf[255] = 31;
|
||||||
return clog;
|
return clog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tc_red_print_flags(__u32 flags)
|
||||||
|
{
|
||||||
|
if (flags & TC_RED_ECN)
|
||||||
|
print_bool(PRINT_ANY, "ecn", "ecn ", true);
|
||||||
|
else
|
||||||
|
print_bool(PRINT_ANY, "ecn", NULL, false);
|
||||||
|
|
||||||
|
if (flags & TC_RED_HARDDROP)
|
||||||
|
print_bool(PRINT_ANY, "harddrop", "harddrop ", true);
|
||||||
|
else
|
||||||
|
print_bool(PRINT_ANY, "harddrop", NULL, false);
|
||||||
|
|
||||||
|
if (flags & TC_RED_ADAPTATIVE)
|
||||||
|
print_bool(PRINT_ANY, "adaptive", "adaptive ", true);
|
||||||
|
else
|
||||||
|
print_bool(PRINT_ANY, "adaptive", NULL, false);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,5 +6,6 @@ int tc_red_eval_P(unsigned qmin, unsigned qmax, double prob);
|
||||||
int tc_red_eval_ewma(unsigned qmin, unsigned burst, unsigned avpkt);
|
int tc_red_eval_ewma(unsigned qmin, unsigned burst, unsigned avpkt);
|
||||||
int tc_red_eval_idle_damping(int wlog, unsigned avpkt, unsigned bandwidth,
|
int tc_red_eval_idle_damping(int wlog, unsigned avpkt, unsigned bandwidth,
|
||||||
__u8 *sbuf);
|
__u8 *sbuf);
|
||||||
|
void tc_red_print_flags(__u32 flags);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# vim: ft=sh
|
|
||||||
|
|
||||||
. lib/generic.sh
|
|
||||||
|
|
||||||
QDISCS="cbq htb dsmark"
|
|
||||||
|
|
||||||
if [ ! -d tests/cls ]; then
|
|
||||||
ts_log "tests/cls folder does not exist"
|
|
||||||
ts_skip
|
|
||||||
fi
|
|
||||||
|
|
||||||
for q in ${QDISCS}; do
|
|
||||||
ts_log "Preparing classifier testbed with qdisc $q"
|
|
||||||
|
|
||||||
for c in tests/cls/*.c; do
|
|
||||||
|
|
||||||
case "$q" in
|
|
||||||
cbq)
|
|
||||||
ts_tc "cls-testbed" "cbq root qdisc creation" \
|
|
||||||
qdisc add dev $DEV root handle 10:0 \
|
|
||||||
cbq bandwidth 100Mbit avpkt 1400 mpu 64
|
|
||||||
ts_tc "cls-testbed" "cbq root class creation" \
|
|
||||||
class add dev $DEV parent 10:0 classid 10:12 \
|
|
||||||
cbq bandwidth 100mbit rate 100mbit allot 1514 prio 3 \
|
|
||||||
maxburst 1 avpkt 500 bounded
|
|
||||||
;;
|
|
||||||
htb)
|
|
||||||
ts_qdisc_available "htb"
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
ts_log "cls-testbed: HTB is unsupported by $TC, skipping"
|
|
||||||
continue;
|
|
||||||
fi
|
|
||||||
ts_tc "cls-testbed" "htb root qdisc creation" \
|
|
||||||
qdisc add dev $DEV root handle 10:0 htb
|
|
||||||
ts_tc "cls-testbed" "htb root class creation" \
|
|
||||||
class add dev $DEV parent 10:0 classid 10:12 \
|
|
||||||
htb rate 100Mbit quantum 1514
|
|
||||||
;;
|
|
||||||
dsmark)
|
|
||||||
ts_qdisc_available "dsmark"
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
ts_log "cls-testbed: dsmark is unsupported by $TC, skipping"
|
|
||||||
continue;
|
|
||||||
fi
|
|
||||||
ts_tc "cls-testbed" "dsmark root qdisc creation" \
|
|
||||||
qdisc add dev $DEV root handle 20:0 \
|
|
||||||
dsmark indices 64 default_index 1 set_tc_index
|
|
||||||
ts_tc "cls-testbed" "dsmark class creation" \
|
|
||||||
class change dev $DEV parent 20:0 classid 20:12 \
|
|
||||||
dsmark mask 0xff value 2
|
|
||||||
ts_tc "cls-testbed" "prio inner qdisc creation" \
|
|
||||||
qdisc add dev $DEV parent 20:0 handle 10:0 prio
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
ts_err "cls-testbed: no testbed configuration found for qdisc $q"
|
|
||||||
continue
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
ts_tc "cls-testbed" "tree listing" qdisc list dev eth0
|
|
||||||
ts_tc "cls-testbed" "tree class listing" class list dev eth0
|
|
||||||
ts_log "cls-testbed: starting classifier test $c"
|
|
||||||
$c
|
|
||||||
|
|
||||||
case "$q" in
|
|
||||||
*)
|
|
||||||
ts_tc "cls-testbed" "generic qdisc tree deletion" \
|
|
||||||
qdisc del dev $DEV root
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
done
|
|
||||||
Loading…
Reference in New Issue