Merge branch 'master' into net-next

This commit is contained in:
Stephen Hemminger 2017-05-30 17:55:17 -07:00
commit 309d5c2f83
6 changed files with 267 additions and 82 deletions

View File

@ -25,6 +25,16 @@ struct rtnl_handle {
int flags;
};
struct nlmsg_list {
struct nlmsg_list *next;
struct nlmsghdr h;
};
struct nlmsg_chain {
struct nlmsg_list *head;
struct nlmsg_list *tail;
};
extern int rcvbuf;
int rtnl_open(struct rtnl_handle *rth, unsigned int subscriptions)

View File

@ -1,8 +1,29 @@
struct link_filter {
int ifindex;
int family;
int oneline;
int showqueue;
inet_prefix pfx;
int scope, scopemask;
int flags, flagmask;
int up;
char *label;
int flushed;
char *flushb;
int flushp;
int flushe;
int group;
int master;
char *kind;
char *slave_kind;
};
int get_operstate(const char *name);
int print_linkinfo(const struct sockaddr_nl *who,
struct nlmsghdr *n, void *arg);
int print_linkinfo_brief(const struct sockaddr_nl *who,
struct nlmsghdr *n, void *arg);
struct nlmsghdr *n, void *arg,
struct link_filter *filter);
int print_addrinfo(const struct sockaddr_nl *who,
struct nlmsghdr *n, void *arg);
int print_addrlabel(const struct sockaddr_nl *who,
@ -65,6 +86,10 @@ int do_seg6(int argc, char **argv);
int iplink_get(unsigned int flags, char *name, __u32 filt_mask);
int iplink_ifla_xstats(int argc, char **argv);
int ip_linkaddr_list(int family, req_filter_fn_t filter_fn,
struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo);
void free_nlmsg_chain(struct nlmsg_chain *info);
static inline int rtm_get_table(struct rtmsg *r, struct rtattr **tb)
{
__u32 table = r->rtm_table;

View File

@ -44,27 +44,7 @@ enum {
IPADD_SAVE,
};
static struct
{
int ifindex;
int family;
int oneline;
int showqueue;
inet_prefix pfx;
int scope, scopemask;
int flags, flagmask;
int up;
char *label;
int flushed;
char *flushb;
int flushp;
int flushe;
int group;
int master;
char *kind;
char *slave_kind;
} filter;
static struct link_filter filter;
static int do_link;
static void usage(void) __attribute__((noreturn));
@ -654,7 +634,8 @@ static void print_link_stats(FILE *fp, struct nlmsghdr *n)
}
int print_linkinfo_brief(const struct sockaddr_nl *who,
struct nlmsghdr *n, void *arg)
struct nlmsghdr *n, void *arg,
struct link_filter *pfilter)
{
FILE *fp = (FILE *)arg;
struct ifinfomsg *ifi = NLMSG_DATA(n);
@ -671,9 +652,12 @@ int print_linkinfo_brief(const struct sockaddr_nl *who,
if (len < 0)
return -1;
if (filter.ifindex && ifi->ifi_index != filter.ifindex)
if (!pfilter)
pfilter = &filter;
if (pfilter->ifindex && ifi->ifi_index != pfilter->ifindex)
return -1;
if (filter.up && !(ifi->ifi_flags&IFF_UP))
if (pfilter->up && !(ifi->ifi_flags&IFF_UP))
return -1;
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
@ -684,30 +668,30 @@ int print_linkinfo_brief(const struct sockaddr_nl *who,
name = rta_getattr_str(tb[IFLA_IFNAME]);
}
if (filter.label &&
(!filter.family || filter.family == AF_PACKET) &&
fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0))
if (pfilter->label &&
(!pfilter->family || pfilter->family == AF_PACKET) &&
fnmatch(pfilter->label, RTA_DATA(tb[IFLA_IFNAME]), 0))
return -1;
if (tb[IFLA_GROUP]) {
int group = rta_getattr_u32(tb[IFLA_GROUP]);
if (filter.group != -1 && group != filter.group)
if (pfilter->group != -1 && group != pfilter->group)
return -1;
}
if (tb[IFLA_MASTER]) {
int master = rta_getattr_u32(tb[IFLA_MASTER]);
if (filter.master > 0 && master != filter.master)
if (pfilter->master > 0 && master != pfilter->master)
return -1;
} else if (filter.master > 0)
} else if (pfilter->master > 0)
return -1;
if (filter.kind && match_link_kind(tb, filter.kind, 0))
if (pfilter->kind && match_link_kind(tb, pfilter->kind, 0))
return -1;
if (filter.slave_kind && match_link_kind(tb, filter.slave_kind, 1))
if (pfilter->slave_kind && match_link_kind(tb, pfilter->slave_kind, 1))
return -1;
if (n->nlmsg_type == RTM_DELLINK)
@ -733,7 +717,7 @@ int print_linkinfo_brief(const struct sockaddr_nl *who,
if (tb[IFLA_OPERSTATE])
print_operstate(fp, rta_getattr_u8(tb[IFLA_OPERSTATE]));
if (filter.family == AF_PACKET) {
if (pfilter->family == AF_PACKET) {
SPRINT_BUF(b1);
if (tb[IFLA_ADDRESS]) {
color_fprintf(fp, COLOR_MAC, "%s ",
@ -744,10 +728,10 @@ int print_linkinfo_brief(const struct sockaddr_nl *who,
}
}
if (filter.family == AF_PACKET)
if (pfilter->family == AF_PACKET)
print_link_flags(fp, ifi->ifi_flags, m_flag);
if (filter.family == AF_PACKET)
if (pfilter->family == AF_PACKET)
fprintf(fp, "\n");
fflush(fp);
return 0;
@ -1211,16 +1195,6 @@ brief_exit:
return 0;
}
struct nlmsg_list {
struct nlmsg_list *next;
struct nlmsghdr h;
};
struct nlmsg_chain {
struct nlmsg_list *head;
struct nlmsg_list *tail;
};
static int print_selected_addrinfo(struct ifinfomsg *ifi,
struct nlmsg_list *ainfo, FILE *fp)
{
@ -1371,7 +1345,7 @@ static int ipaddr_restore(void)
exit(rtnl_from_file(stdin, &restore_handler, NULL));
}
static void free_nlmsg_chain(struct nlmsg_chain *info)
void free_nlmsg_chain(struct nlmsg_chain *info)
{
struct nlmsg_list *l, *n;
@ -1534,10 +1508,43 @@ static int iplink_filter_req(struct nlmsghdr *nlh, int reqlen)
return 0;
}
/* 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
* both when done
*/
int ip_linkaddr_list(int family, req_filter_fn_t filter_fn,
struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo)
{
if (rtnl_wilddump_req_filter_fn(&rth, preferred_family, RTM_GETLINK,
filter_fn) < 0) {
perror("Cannot send dump request");
return 1;
}
if (rtnl_dump_filter(&rth, store_nlmsg, linfo) < 0) {
fprintf(stderr, "Dump terminated\n");
return 1;
}
if (ainfo) {
if (rtnl_wilddump_request(&rth, family, RTM_GETADDR) < 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;
}
static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
{
struct nlmsg_chain linfo = { NULL, NULL};
struct nlmsg_chain ainfo = { NULL, NULL};
struct nlmsg_chain _ainfo = { NULL, NULL}, *ainfo = NULL;
struct nlmsg_list *l;
char *filter_dev = NULL;
int no_link = 0;
@ -1714,56 +1721,45 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
exit(0);
}
if (rtnl_wilddump_req_filter_fn(&rth, preferred_family, RTM_GETLINK,
iplink_filter_req) < 0) {
perror("Cannot send dump request");
exit(1);
}
if (rtnl_dump_filter(&rth, store_nlmsg, &linfo) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
}
if (filter.family != AF_PACKET) {
ainfo = &_ainfo;
if (filter.oneline)
no_link = 1;
if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) {
perror("Cannot send dump request");
exit(1);
}
if (rtnl_dump_filter(&rth, store_nlmsg, &ainfo) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
}
ipaddr_filter(&linfo, &ainfo);
}
if (ip_linkaddr_list(filter.family, iplink_filter_req,
&linfo, ainfo) != 0)
goto out;
if (filter.family != AF_PACKET)
ipaddr_filter(&linfo, ainfo);
for (l = linfo.head; l; l = l->next) {
int res = 0;
struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
if (brief) {
if (print_linkinfo_brief(NULL, &l->h, stdout) == 0)
if (print_linkinfo_brief(NULL, &l->h,
stdout, NULL) == 0)
if (filter.family != AF_PACKET)
print_selected_addrinfo(ifi,
ainfo.head,
ainfo->head,
stdout);
} else if (no_link ||
(res = print_linkinfo(NULL, &l->h, stdout)) >= 0) {
(res = print_linkinfo(NULL, &l->h, stdout)) >= 0) {
if (filter.family != AF_PACKET)
print_selected_addrinfo(ifi,
ainfo.head, stdout);
ainfo->head, stdout);
if (res > 0 && !do_link && show_stats)
print_link_stats(stdout, &l->h);
}
}
fflush(stdout);
free_nlmsg_chain(&ainfo);
out:
if (ainfo)
free_nlmsg_chain(ainfo);
free_nlmsg_chain(&linfo);
return 0;

View File

@ -1036,7 +1036,7 @@ int iplink_get(unsigned int flags, char *name, __u32 filt_mask)
return -2;
if (brief)
print_linkinfo_brief(NULL, &answer.n, stdout);
print_linkinfo_brief(NULL, &answer.n, stdout, NULL);
else
print_linkinfo(NULL, &answer.n, stdout);

View File

@ -32,9 +32,12 @@
#define CGRP_PROC_FILE "/cgroup.procs"
static struct link_filter vrf_filter;
static void usage(void)
{
fprintf(stderr, "Usage: ip vrf exec [NAME] cmd ...\n");
fprintf(stderr, "Usage: ip vrf show [NAME] ...\n");
fprintf(stderr, " ip vrf exec [NAME] cmd ...\n");
fprintf(stderr, " ip vrf identify [PID]\n");
fprintf(stderr, " ip vrf pids [NAME]\n");
@ -467,12 +470,147 @@ void vrf_reset(void)
vrf_switch("default");
}
static int ipvrf_filter_req(struct nlmsghdr *nlh, int reqlen)
{
struct rtattr *linkinfo;
int err;
if (vrf_filter.kind) {
linkinfo = addattr_nest(nlh, reqlen, IFLA_LINKINFO);
err = addattr_l(nlh, reqlen, IFLA_INFO_KIND, vrf_filter.kind,
strlen(vrf_filter.kind));
if (err)
return err;
addattr_nest_end(nlh, linkinfo);
}
return 0;
}
/* input arg is linkinfo */
static __u32 vrf_table_linkinfo(struct rtattr *li[])
{
struct rtattr *attr[IFLA_VRF_MAX + 1];
if (li[IFLA_INFO_DATA]) {
parse_rtattr_nested(attr, IFLA_VRF_MAX, li[IFLA_INFO_DATA]);
if (attr[IFLA_VRF_TABLE])
return rta_getattr_u32(attr[IFLA_VRF_TABLE]);
}
return 0;
}
static int ipvrf_print(struct nlmsghdr *n)
{
struct ifinfomsg *ifi = NLMSG_DATA(n);
struct rtattr *tb[IFLA_MAX+1];
struct rtattr *li[IFLA_INFO_MAX+1];
int len = n->nlmsg_len;
const char *name;
__u32 tb_id;
len -= NLMSG_LENGTH(sizeof(*ifi));
if (len < 0)
return 0;
if (vrf_filter.ifindex && vrf_filter.ifindex != ifi->ifi_index)
return 0;
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
/* kernel does not support filter by master device */
if (tb[IFLA_MASTER]) {
int master = *(int *)RTA_DATA(tb[IFLA_MASTER]);
if (vrf_filter.master && master != vrf_filter.master)
return 0;
}
if (!tb[IFLA_IFNAME]) {
fprintf(stderr,
"BUG: device with ifindex %d has nil ifname\n",
ifi->ifi_index);
return 0;
}
name = rta_getattr_str(tb[IFLA_IFNAME]);
/* missing LINKINFO means not VRF. e.g., kernel does not
* support filtering on kind, so userspace needs to handle
*/
if (!tb[IFLA_LINKINFO])
return 0;
parse_rtattr_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
if (!li[IFLA_INFO_KIND])
return 0;
if (strcmp(RTA_DATA(li[IFLA_INFO_KIND]), "vrf"))
return 0;
tb_id = vrf_table_linkinfo(li);
if (!tb_id) {
fprintf(stderr,
"BUG: VRF %s is missing table id\n", name);
return 0;
}
printf("%-16s %5u", name, tb_id);
printf("\n");
return 1;
}
static int ipvrf_show(int argc, char **argv)
{
struct nlmsg_chain linfo = { NULL, NULL};
int rc = 0;
vrf_filter.kind = "vrf";
if (argc > 1)
usage();
if (argc == 1) {
__u32 tb_id;
tb_id = ipvrf_get_table(argv[0]);
if (!tb_id) {
fprintf(stderr, "Invalid VRF\n");
return 1;
}
printf("%s %u\n", argv[0], tb_id);
return 0;
}
if (ip_linkaddr_list(0, ipvrf_filter_req, &linfo, NULL) == 0) {
struct nlmsg_list *l;
unsigned nvrf = 0;
int n;
n = printf("%-16s %5s\n", "Name", "Table");
printf("%.*s\n", n-1, "-----------------------");
for (l = linfo.head; l; l = l->next)
nvrf += ipvrf_print(&l->h);
if (!nvrf)
printf("No VRF has been configured\n");
} else
rc = 1;
free_nlmsg_chain(&linfo);
return rc;
}
int do_ipvrf(int argc, char **argv)
{
if (argc == 0) {
fprintf(stderr, "No command given. Try \"ip vrf help\".\n");
exit(-1);
}
if (argc == 0)
return ipvrf_show(0, NULL);
if (matches(*argv, "identify") == 0)
return ipvrf_identify(argc-1, argv+1);
@ -483,6 +621,11 @@ int do_ipvrf(int argc, char **argv)
if (matches(*argv, "exec") == 0)
return ipvrf_exec(argc-1, argv+1);
if (matches(*argv, "show") == 0 ||
matches(*argv, "lst") == 0 ||
matches(*argv, "list") == 0)
return ipvrf_show(argc-1, argv+1);
if (matches(*argv, "help") == 0)
usage();

View File

@ -12,6 +12,10 @@ ip-vrf \- run a command against a vrf
.BR help " }"
.sp
.ti -8
.BR "ip vrf show"
.RI "[ " NAME " ]"
.ti -8
.BR "ip vrf identify"
.RI "[ " PID " ]"
@ -44,6 +48,13 @@ sockets (AF_INET and AF_INET6) when the socket is created. This ip-vrf command
is a helper to run a command against a specific VRF with the VRF association
inherited parent to child.
.TP
.B ip vrf show [ NAME ] - Show all configured VRF
.sp
This command lists all VRF and their corresponding table ids. If NAME is
given, then only that VRF and table id is shown. The latter command is
useful for scripting where the table id for a VRF is needed.
.TP
.B ip vrf exec [ NAME ] cmd ... - Run cmd against the named VRF
.sp