diff options
Diffstat (limited to 'ip/ipnetconf.c')
-rw-r--r-- | ip/ipnetconf.c | 88 |
1 files changed, 60 insertions, 28 deletions
diff --git a/ip/ipnetconf.c b/ip/ipnetconf.c index eca6eeee..696e3dd5 100644 --- a/ip/ipnetconf.c +++ b/ip/ipnetconf.c @@ -19,13 +19,13 @@ #include <sys/time.h> #include <sys/socket.h> #include <netinet/in.h> +#include <errno.h> #include "rt_names.h" #include "utils.h" #include "ip_common.h" -static struct -{ +static struct { int family; int ifindex; } filter; @@ -38,15 +38,25 @@ static void usage(void) exit(-1); } -#define NETCONF_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct netconfmsg)))) +static void print_onoff(FILE *f, const char *flag, __u32 val) +{ + fprintf(f, "%s %s ", flag, val ? "on" : "off"); +} + +static struct rtattr *netconf_rta(struct netconfmsg *ncm) +{ + return (struct rtattr *)((char *)ncm + + NLMSG_ALIGN(sizeof(struct netconfmsg))); +} int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct netconfmsg *ncm = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[NETCONFA_MAX+1]; + int ifindex = 0; if (n->nlmsg_type == NLMSG_ERROR) return -1; @@ -65,9 +75,15 @@ int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, if (filter.family && filter.family != ncm->ncm_family) return 0; - parse_rtattr(tb, NETCONFA_MAX, NETCONF_RTA(ncm), + parse_rtattr(tb, NETCONFA_MAX, netconf_rta(ncm), NLMSG_PAYLOAD(n, sizeof(*ncm))); + if (tb[NETCONFA_IFINDEX]) + ifindex = rta_getattr_u32(tb[NETCONFA_IFINDEX]); + + if (filter.ifindex && filter.ifindex != ifindex) + return 0; + switch (ncm->ncm_family) { case AF_INET: fprintf(fp, "ipv4 "); @@ -75,15 +91,16 @@ int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, case AF_INET6: fprintf(fp, "ipv6 "); break; + case AF_MPLS: + fprintf(fp, "mpls "); + break; default: fprintf(fp, "unknown "); break; } if (tb[NETCONFA_IFINDEX]) { - int *ifindex = (int *)RTA_DATA(tb[NETCONFA_IFINDEX]); - - switch (*ifindex) { + switch (ifindex) { case NETCONFA_IFINDEX_ALL: fprintf(fp, "all "); break; @@ -91,16 +108,16 @@ int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, fprintf(fp, "default "); break; default: - fprintf(fp, "dev %s ", ll_index_to_name(*ifindex)); + 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"); + print_onoff(fp, "forwarding", + rta_getattr_u32(tb[NETCONFA_FORWARDING])); if (tb[NETCONFA_RP_FILTER]) { - int rp_filter = *(int *)RTA_DATA(tb[NETCONFA_RP_FILTER]); + __u32 rp_filter = rta_getattr_u32(tb[NETCONFA_RP_FILTER]); if (rp_filter == 0) fprintf(fp, "rp_filter off "); @@ -112,12 +129,19 @@ int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, fprintf(fp, "rp_filter unknown mode "); } if (tb[NETCONFA_MC_FORWARDING]) - fprintf(fp, "mc_forwarding %d ", - *(int *)RTA_DATA(tb[NETCONFA_MC_FORWARDING])); + print_onoff(fp, "mc_forwarding", + rta_getattr_u32(tb[NETCONFA_MC_FORWARDING])); if (tb[NETCONFA_PROXY_NEIGH]) - fprintf(fp, "proxy_neigh %s ", - *(int *)RTA_DATA(tb[NETCONFA_PROXY_NEIGH])?"on":"off"); + print_onoff(fp, "proxy_neigh", + rta_getattr_u32(tb[NETCONFA_PROXY_NEIGH])); + + if (tb[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN]) + print_onoff(fp, "ignore_routes_with_linkdown", + rta_getattr_u32(tb[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN])); + + if (tb[NETCONFA_INPUT]) + print_onoff(fp, "input", rta_getattr_u32(tb[NETCONFA_INPUT])); fprintf(fp, "\n"); fflush(fp); @@ -142,12 +166,14 @@ static int do_show(int argc, char **argv) struct nlmsghdr n; struct netconfmsg ncm; char buf[1024]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct netconfmsg)), + .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, + .n.nlmsg_type = RTM_GETNETCONF, + }; ipnetconf_reset_filter(0); filter.family = preferred_family; - if (filter.family == AF_UNSPEC) - filter.family = AF_INET; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { @@ -163,15 +189,11 @@ static int do_show(int argc, char **argv) } ll_init_map(&rth); - if (filter.ifindex) { - 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; + + if (filter.ifindex && filter.family != AF_UNSPEC) { req.ncm.ncm_family = filter.family; - if (filter.ifindex) - addattr_l(&req.n, sizeof(req), NETCONFA_IFINDEX, - &filter.ifindex, sizeof(filter.ifindex)); + addattr_l(&req.n, sizeof(req), NETCONFA_IFINDEX, + &filter.ifindex, sizeof(filter.ifindex)); if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) { perror("Can not send request"); @@ -179,16 +201,26 @@ static int do_show(int argc, char **argv) } rtnl_listen(&rth, print_netconf, stdout); } else { + rth.flags = RTNL_HANDLE_F_SUPPRESS_NLERR; dump: if (rtnl_wilddump_request(&rth, filter.family, RTM_GETNETCONF) < 0) { perror("Cannot send dump request"); exit(1); } if (rtnl_dump_filter(&rth, print_netconf2, stdout) < 0) { + /* kernel does not support netconf dump on AF_UNSPEC; + * fall back to requesting by family + */ + if (errno == EOPNOTSUPP && + filter.family == AF_UNSPEC) { + filter.family = AF_INET; + goto dump; + } + perror("RTNETLINK answers"); fprintf(stderr, "Dump terminated\n"); exit(1); } - if (preferred_family == AF_UNSPEC) { + if (preferred_family == AF_UNSPEC && filter.family == AF_INET) { preferred_family = AF_INET6; filter.family = AF_INET6; goto dump; |