From: Nicolas Dichtel Date: Wed, 12 Dec 2012 17:05:51 +0000 (-0800) Subject: ip: add support of netconf messages X-Git-Tag: v3.8.0~3^2~53 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4852ba750a2cc122e5b933b1ce852c60ef1471fc;p=thirdparty%2Fiproute2.git ip: add support of netconf messages Example of the output: $ ip monitor netconf& [1] 24901 $ echo 0 > /proc/sys/net/ipv6/conf/all/forwarding ipv6 dev lo forwarding off ipv6 dev eth0 forwarding off ipv6 all forwarding off $ echo 1 > /proc/sys/net/ipv4/conf/eth0/forwarding ipv4 dev eth0 forwarding on $ ip -6 netconf ipv6 all forwarding on mc_forwarding 0 $ ip netconf show dev eth0 ipv4 dev eth0 forwarding on rp_filter off mc_forwarding 1 Signed-off-by: Nicolas Dichtel Minor cleanup of original patch, made sure netconf.h matched result of santized kernel headers --- diff --git a/include/linux/netconf.h b/include/linux/netconf.h new file mode 100644 index 000000000..52c44244e --- /dev/null +++ b/include/linux/netconf.h @@ -0,0 +1,24 @@ +#ifndef _LINUX_NETCONF_H_ +#define _LINUX_NETCONF_H_ + +#include +#include + +struct netconfmsg { + __u8 ncm_family; +}; + +enum { + NETCONFA_UNSPEC, + NETCONFA_IFINDEX, + NETCONFA_FORWARDING, + NETCONFA_RP_FILTER, + NETCONFA_MC_FORWARDING, + __NETCONFA_MAX +}; +#define NETCONFA_MAX (__NETCONFA_MAX - 1) + +#define NETCONFA_IFINDEX_ALL -1 +#define NETCONFA_IFINDEX_DEFAULT -2 + +#endif /* _LINUX_NETCONF_H_ */ diff --git a/ip/ipnetconf.c b/ip/ipnetconf.c new file mode 100644 index 000000000..66d667bcd --- /dev/null +++ b/ip/ipnetconf.c @@ -0,0 +1,183 @@ +/* + * ipnetconf.c "ip netconf". + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Nicolas Dichtel, + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt_names.h" +#include "utils.h" +#include "ip_common.h" + +static struct +{ + int family; + int ifindex; +} filter; + +static void usage(void) __attribute__((noreturn)); + +static void usage(void) +{ + fprintf(stderr, "Usage: ip netconf show [ dev STRING ]\n"); + exit(-1); +} + +#define NETCONF_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct netconfmsg)))) + +int print_netconf(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) +{ + FILE *fp = (FILE*)arg; + struct netconfmsg *ncm = NLMSG_DATA(n); + int len = n->nlmsg_len; + struct rtattr *tb[NETCONFA_MAX+1]; + + if (n->nlmsg_type == NLMSG_ERROR) + return -1; + if (n->nlmsg_type != RTM_NEWNETCONF) { + fprintf(stderr, "Not RTM_NEWNETCONF: %08x %08x %08x\n", + n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); + + return -1; + } + len -= NLMSG_SPACE(sizeof(*ncm)); + if (len < 0) { + fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); + return -1; + } + + if (filter.family && filter.family != ncm->ncm_family) + return 0; + + parse_rtattr(tb, NETCONFA_MAX, NETCONF_RTA(ncm), + NLMSG_PAYLOAD(n, sizeof(*ncm))); + + switch (ncm->ncm_family) { + case AF_INET: + fprintf(fp, "ipv4 "); + break; + case AF_INET6: + fprintf(fp, "ipv6 "); + break; + default: + fprintf(fp, "unknown "); + break; + } + + if (tb[NETCONFA_IFINDEX]) { + int *ifindex = (int *)RTA_DATA(tb[NETCONFA_IFINDEX]); + + switch (*ifindex) { + case NETCONFA_IFINDEX_ALL: + fprintf(fp, "all "); + break; + case NETCONFA_IFINDEX_DEFAULT: + fprintf(fp, "default "); + break; + default: + fprintf(fp, "dev %s ", ll_index_to_name(*ifindex)); + break; + } + } + + if (tb[NETCONFA_FORWARDING]) + fprintf(fp, "forwarding %s ", + *(int *)RTA_DATA(tb[NETCONFA_FORWARDING])?"on":"off"); + if (tb[NETCONFA_RP_FILTER]) { + int rp_filter = *(int *)RTA_DATA(tb[NETCONFA_RP_FILTER]); + + if (rp_filter == 0) + fprintf(fp, "rp_filter off "); + else if (rp_filter == 1) + fprintf(fp, "rp_filter strict "); + else if (rp_filter == 2) + fprintf(fp, "rp_filter loose "); + else + fprintf(fp, "rp_filter unknown mode "); + } + if (tb[NETCONFA_MC_FORWARDING]) + fprintf(fp, "mc_forwarding %d ", + *(int *)RTA_DATA(tb[NETCONFA_MC_FORWARDING])); + + fprintf(fp, "\n"); + fflush(fp); + return 0; +} + +void ipnetconf_reset_filter(void) +{ + memset(&filter, 0, sizeof(filter)); +} + +int do_show(int argc, char **argv) +{ + struct { + struct nlmsghdr n; + struct netconfmsg ncm; + char buf[1024]; + } req; + + ipnetconf_reset_filter(); + filter.family = preferred_family; + if (filter.family == AF_UNSPEC) + filter.family = AF_INET; + filter.ifindex = NETCONFA_IFINDEX_ALL; + + while (argc > 0) { + if (strcmp(*argv, "dev") == 0) { + NEXT_ARG(); + filter.ifindex = ll_name_to_index(*argv); + if (filter.ifindex <= 0) { + fprintf(stderr, "Device \"%s\" does not exist.\n", + *argv); + return -1; + } + } + argv++; argc--; + } + + ll_init_map(&rth); + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct netconfmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; + req.n.nlmsg_type = RTM_GETNETCONF; + req.ncm.ncm_family = filter.family; + addattr_l(&req.n, sizeof(req), NETCONFA_IFINDEX, &filter.ifindex, + sizeof(filter.ifindex)); + + rtnl_send(&rth, &req.n, req.n.nlmsg_len); + rtnl_listen(&rth, print_netconf, stdout); + + return 0; +} + +int do_ipnetconf(int argc, char **argv) +{ + if (argc > 0) { + if (matches(*argv, "show") == 0 || + matches(*argv, "lst") == 0 || + matches(*argv, "list") == 0) + return do_show(argc-1, argv+1); + if (matches(*argv, "help") == 0) + usage(); + } else + return do_show(0, NULL); + + fprintf(stderr, "Command \"%s\" is unknown, try \"ip netconf help\".\n", *argv); + exit(-1); +}