int print_qdisc(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; struct tcmsg *t = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr * tb[TCA_MAX+1]; struct qdisc_util *q; char abuf[256]; if (n->nlmsg_type != RTM_NEWQDISC && n->nlmsg_type != RTM_DELQDISC) { fprintf(stderr, "Not a qdisc\n"); return 0; } len -= NLMSG_LENGTH(sizeof(*t)); if (len < 0) { fprintf(stderr, "Wrong len %d\n", len); return -1; } if (filter_ifindex && filter_ifindex != t->tcm_ifindex) return 0; memset(tb, 0, sizeof(tb)); parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len); if (tb[TCA_KIND] == NULL) { fprintf(stderr, "print_qdisc: NULL kind\n"); return -1; } if (n->nlmsg_type == RTM_DELQDISC) fprintf(fp, "deleted "); fprintf(fp, "qdisc %s %x: ", rta_getattr_str(tb[TCA_KIND]), t->tcm_handle>>16); if (filter_ifindex == 0) fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex)); if (t->tcm_parent == TC_H_ROOT) fprintf(fp, "root "); else if (t->tcm_parent) { print_tc_classid(abuf, sizeof(abuf), t->tcm_parent); fprintf(fp, "parent %s ", abuf); } if (t->tcm_info != 1) { fprintf(fp, "refcnt %d ", t->tcm_info); } /* pfifo_fast is generic enough to warrant the hardcoding --JHS */ if (0 == strcmp("pfifo_fast", RTA_DATA(tb[TCA_KIND]))) q = get_qdisc_kind("prio"); else q = get_qdisc_kind(RTA_DATA(tb[TCA_KIND])); if (tb[TCA_OPTIONS]) { if (q) q->print_qopt(q, fp, tb[TCA_OPTIONS]); else fprintf(fp, "[cannot parse qdisc parameters]"); } fprintf(fp, "\n"); if (show_details && tb[TCA_STAB]) { print_size_table(fp, " ", tb[TCA_STAB]); fprintf(fp, "\n"); } if (show_stats) { struct rtattr *xstats = NULL; if (tb[TCA_STATS] || tb[TCA_STATS2] || tb[TCA_XSTATS]) { print_tcstats_attr(fp, tb, " ", &xstats); fprintf(fp, "\n"); } if (q && xstats && q->print_xstats) { q->print_xstats(q, fp, xstats); fprintf(fp, "\n"); } } fflush(fp); return 0; }
int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; struct ndmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr * tb[NDA_MAX+1]; char abuf[256]; if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH && n->nlmsg_type != RTM_GETNEIGH) { fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return 0; } len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } if (filter.flushb && n->nlmsg_type != RTM_NEWNEIGH) return 0; if (filter.family && filter.family != r->ndm_family) return 0; if (filter.index && filter.index != r->ndm_ifindex) return 0; if (!(filter.state&r->ndm_state) && !(r->ndm_flags & NTF_PROXY) && (r->ndm_state || !(filter.state&0x100)) && (r->ndm_family != AF_DECnet)) return 0; parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); if (tb[NDA_DST]) { if (filter.pfx.family) { inet_prefix dst; memset(&dst, 0, sizeof(dst)); dst.family = r->ndm_family; memcpy(&dst.data, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST])); if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) return 0; } } if (filter.unused_only && tb[NDA_CACHEINFO]) { struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]); if (ci->ndm_refcnt) return 0; } if (filter.flushb) { struct nlmsghdr *fn; if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) { if (flush_update()) return -1; } fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp)); memcpy(fn, n, n->nlmsg_len); fn->nlmsg_type = RTM_DELNEIGH; fn->nlmsg_flags = NLM_F_REQUEST; fn->nlmsg_seq = ++rth.seq; filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb; filter.flushed++; if (show_stats < 2) return 0; } if (n->nlmsg_type == RTM_DELNEIGH) fprintf(fp, "delete "); else if (n->nlmsg_type == RTM_GETNEIGH) fprintf(fp, "miss "); if (tb[NDA_DST]) { fprintf(fp, "%s ", format_host(r->ndm_family, RTA_PAYLOAD(tb[NDA_DST]), RTA_DATA(tb[NDA_DST]), abuf, sizeof(abuf))); } if (!filter.index && r->ndm_ifindex) fprintf(fp, "dev %s ", ll_index_to_name(r->ndm_ifindex)); if (tb[NDA_LLADDR]) { SPRINT_BUF(b1); fprintf(fp, "lladdr %s", ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]), RTA_PAYLOAD(tb[NDA_LLADDR]), ll_index_to_type(r->ndm_ifindex), b1, sizeof(b1))); } if (r->ndm_flags & NTF_ROUTER) { fprintf(fp, " router"); } if (r->ndm_flags & NTF_PROXY) { fprintf(fp, " proxy"); } if (tb[NDA_CACHEINFO] && show_stats) { struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]); int hz = get_user_hz(); if (ci->ndm_refcnt) printf(" ref %d", ci->ndm_refcnt); fprintf(fp, " used %d/%d/%d", ci->ndm_used/hz, ci->ndm_confirmed/hz, ci->ndm_updated/hz); } if (tb[NDA_PROBES] && show_stats) { __u32 p = rta_getattr_u32(tb[NDA_PROBES]); fprintf(fp, " probes %u", p); } if (r->ndm_state) { int nud = r->ndm_state; fprintf(fp, " "); #define PRINT_FLAG(f) if (nud & NUD_##f) { \ nud &= ~NUD_##f; fprintf(fp, #f "%s", nud ? "," : ""); } PRINT_FLAG(INCOMPLETE); PRINT_FLAG(REACHABLE); PRINT_FLAG(STALE); PRINT_FLAG(DELAY); PRINT_FLAG(PROBE); PRINT_FLAG(FAILED); PRINT_FLAG(NOARP); PRINT_FLAG(PERMANENT); #undef PRINT_FLAG } fprintf(fp, "\n"); fflush(fp); return 0; }
int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr * tb[RTA_MAX+1]; char abuf[256]; int host_len; __u32 table; SPRINT_BUF(b1); static int hz; if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) { fprintf(stderr, "Not a route: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return 0; } if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE) return 0; len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } host_len = af_bit_len(r->rtm_family); parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); table = rtm_get_table(r, tb); if (!filter_nlmsg(n, tb, host_len)) return 0; if (filter.flushb) { struct nlmsghdr *fn; if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) { if (flush_update()) return -1; } fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp)); memcpy(fn, n, n->nlmsg_len); fn->nlmsg_type = RTM_DELROUTE; fn->nlmsg_flags = NLM_F_REQUEST; fn->nlmsg_seq = ++rth.seq; filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb; filter.flushed++; if (show_stats < 2) return 0; } if (n->nlmsg_type == RTM_DELROUTE) fprintf(fp, "Deleted "); if ((r->rtm_type != RTN_UNICAST || show_details > 0) && !filter.type) fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1))); if (tb[RTA_DST]) { if (r->rtm_dst_len != host_len) { fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_DST]), RTA_DATA(tb[RTA_DST]), abuf, sizeof(abuf)), r->rtm_dst_len ); } else { fprintf(fp, "%s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_DST]), RTA_DATA(tb[RTA_DST]), abuf, sizeof(abuf)) ); } } else if (r->rtm_dst_len) { fprintf(fp, "0/%d ", r->rtm_dst_len); } else { fprintf(fp, "default "); } if (tb[RTA_SRC]) { if (r->rtm_src_len != host_len) { fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_SRC]), RTA_DATA(tb[RTA_SRC]), abuf, sizeof(abuf)), r->rtm_src_len ); } else { fprintf(fp, "from %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_SRC]), RTA_DATA(tb[RTA_SRC]), abuf, sizeof(abuf)) ); } } else if (r->rtm_src_len) { fprintf(fp, "from 0/%u ", r->rtm_src_len); } if (tb[RTA_NEWDST]) { fprintf(fp, "as to %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_NEWDST]), RTA_DATA(tb[RTA_NEWDST]), abuf, sizeof(abuf)) ); } if (tb[RTA_ENCAP]) lwt_print_encap(fp, tb[RTA_ENCAP_TYPE], tb[RTA_ENCAP]); if (r->rtm_tos && filter.tosmask != -1) { SPRINT_BUF(b1); fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1))); } if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) { fprintf(fp, "via %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_GATEWAY]), RTA_DATA(tb[RTA_GATEWAY]), abuf, sizeof(abuf))); } if (tb[RTA_VIA]) { size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2; struct rtvia *via = RTA_DATA(tb[RTA_VIA]); fprintf(fp, "via %s %s ", family_name(via->rtvia_family), format_host(via->rtvia_family, len, via->rtvia_addr, abuf, sizeof(abuf))); } if (tb[RTA_OIF] && filter.oifmask != -1) fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF]))); if (table && (table != RT_TABLE_MAIN || show_details > 0) && !filter.tb) fprintf(fp, " table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1))); if (!(r->rtm_flags&RTM_F_CLONED)) { if ((r->rtm_protocol != RTPROT_BOOT || show_details > 0) && filter.protocolmask != -1) fprintf(fp, " proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1))); if ((r->rtm_scope != RT_SCOPE_UNIVERSE || show_details > 0) && filter.scopemask != -1) fprintf(fp, " scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1))); } if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) { /* Do not use format_host(). It is our local addr and symbolic name will not be useful. */ fprintf(fp, " src %s ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_PREFSRC]), RTA_DATA(tb[RTA_PREFSRC]), abuf, sizeof(abuf))); } if (tb[RTA_PRIORITY]) fprintf(fp, " metric %u ", rta_getattr_u32(tb[RTA_PRIORITY])); if (r->rtm_flags & RTNH_F_DEAD) fprintf(fp, "dead "); if (r->rtm_flags & RTNH_F_ONLINK) fprintf(fp, "onlink "); if (r->rtm_flags & RTNH_F_PERVASIVE) fprintf(fp, "pervasive "); if (r->rtm_flags & RTNH_F_OFFLOAD) fprintf(fp, "offload "); if (r->rtm_flags & RTM_F_NOTIFY) fprintf(fp, "notify "); if (r->rtm_flags & RTNH_F_LINKDOWN) fprintf(fp, "linkdown "); if (tb[RTA_MARK]) { unsigned int mark = *(unsigned int*)RTA_DATA(tb[RTA_MARK]); if (mark) { if (mark >= 16) fprintf(fp, " mark 0x%x", mark); else fprintf(fp, " mark %u", mark); } } if (tb[RTA_FLOW] && filter.realmmask != ~0U) { __u32 to = rta_getattr_u32(tb[RTA_FLOW]); __u32 from = to>>16; to &= 0xFFFF; fprintf(fp, "realm%s ", from ? "s" : ""); if (from) { fprintf(fp, "%s/", rtnl_rtrealm_n2a(from, b1, sizeof(b1))); } fprintf(fp, "%s ", rtnl_rtrealm_n2a(to, b1, sizeof(b1))); }
int print_qdisc(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; struct tcmsg *t = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr * tb[TCA_MAX+1]; struct qdisc_util *q; char abuf[256]; if (n->nlmsg_type != RTM_NEWQDISC && n->nlmsg_type != RTM_DELQDISC) { fprintf(stderr, "Not a qdisc\n"); return 0; } len -= NLMSG_LENGTH(sizeof(*t)); if (len < 0) { fprintf(stderr, "Wrong len %d\n", len); return -1; } if (filter_ifindex && filter_ifindex != t->tcm_ifindex) return 0; memset(tb, 0, sizeof(tb)); parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len); if (tb[TCA_KIND] == NULL) { fprintf(stderr, "NULL kind\n"); return -1; } if (n->nlmsg_type == RTM_DELQDISC) fprintf(fp, "deleted "); fprintf(fp, "qdisc %s %x: ", (char*)RTA_DATA(tb[TCA_KIND]), t->tcm_handle>>16); if (filter_ifindex == 0) fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex)); if (t->tcm_parent == TC_H_ROOT) fprintf(fp, "root "); else if (t->tcm_parent) { print_tc_classid(abuf, sizeof(abuf), t->tcm_parent); fprintf(fp, "parent %s ", abuf); } if (t->tcm_info != 1) { fprintf(fp, "refcnt %d ", t->tcm_info); } if ((q = get_qdisc_kind(RTA_DATA(tb[TCA_KIND]))) != NULL) q->print_qopt(q, fp, tb[TCA_OPTIONS]); else fprintf(fp, "[UNKNOWN]"); fprintf(fp, "\n"); if (show_stats) { if (tb[TCA_STATS]) { if (RTA_PAYLOAD(tb[TCA_STATS]) < sizeof(struct tc_stats)) fprintf(fp, "statistics truncated"); else { struct tc_stats st; memcpy(&st, RTA_DATA(tb[TCA_STATS]), sizeof(st)); print_tcstats(fp, &st); fprintf(fp, "\n"); } } if (q && tb[TCA_XSTATS]) { q->print_xstats(q, fp, tb[TCA_XSTATS]); fprintf(fp, "\n"); } fprintf(fp, "\n "); } fflush(fp); return 0; }
static int print_route(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr * tb[RTA_MAX+1]; char abuf[256]; inet_prefix dst; inet_prefix src; int host_len = -1; SPRINT_BUF(b1); if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) { fprintf(stderr, "Not a route: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return 0; } if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE) return 0; len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) { bb_error_msg("wrong nlmsg len %d", len); return -1; } if (r->rtm_family == AF_INET6) host_len = 128; else if (r->rtm_family == AF_INET) host_len = 32; if (r->rtm_family == AF_INET6) { if (filter.tb) { if (filter.tb < 0) { if (!(r->rtm_flags&RTM_F_CLONED)) { return 0; } } else { if (r->rtm_flags&RTM_F_CLONED) { return 0; } if (filter.tb == RT_TABLE_LOCAL) { if (r->rtm_type != RTN_LOCAL) { return 0; } } else if (filter.tb == RT_TABLE_MAIN) { if (r->rtm_type == RTN_LOCAL) { return 0; } } else { return 0; } } } } else { if (filter.tb > 0 && filter.tb != r->rtm_table) { return 0; } } if (filter.rdst.family && (r->rtm_family != filter.rdst.family || filter.rdst.bitlen > r->rtm_dst_len)) { return 0; } if (filter.mdst.family && (r->rtm_family != filter.mdst.family || (filter.mdst.bitlen >= 0 && filter.mdst.bitlen < r->rtm_dst_len))) { return 0; } if (filter.rsrc.family && (r->rtm_family != filter.rsrc.family || filter.rsrc.bitlen > r->rtm_src_len)) { return 0; } if (filter.msrc.family && (r->rtm_family != filter.msrc.family || (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len))) { return 0; } memset(tb, 0, sizeof(tb)); parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); if (filter.rdst.family && inet_addr_match(&dst, &filter.rdst, filter.rdst.bitlen)) return 0; if (filter.mdst.family && filter.mdst.bitlen >= 0 && inet_addr_match(&dst, &filter.mdst, r->rtm_dst_len)) return 0; if (filter.rsrc.family && inet_addr_match(&src, &filter.rsrc, filter.rsrc.bitlen)) return 0; if (filter.msrc.family && filter.msrc.bitlen >= 0 && inet_addr_match(&src, &filter.msrc, r->rtm_src_len)) return 0; if (filter.flushb && r->rtm_family == AF_INET6 && r->rtm_dst_len == 0 && r->rtm_type == RTN_UNREACHABLE && tb[RTA_PRIORITY] && *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1) return 0; if (filter.flushb) { struct nlmsghdr *fn; if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) { if (flush_update()) return -1; } fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp)); memcpy(fn, n, n->nlmsg_len); fn->nlmsg_type = RTM_DELROUTE; fn->nlmsg_flags = NLM_F_REQUEST; fn->nlmsg_seq = ++filter.rth->seq; filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb; filter.flushed++; return 0; } if (n->nlmsg_type == RTM_DELROUTE) { fprintf(fp, "Deleted "); } if (r->rtm_type != RTN_UNICAST && !filter.type) { fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1))); } if (tb[RTA_DST]) { if (r->rtm_dst_len != host_len) { fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_DST]), RTA_DATA(tb[RTA_DST]), abuf, sizeof(abuf)), r->rtm_dst_len ); } else { fprintf(fp, "%s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_DST]), RTA_DATA(tb[RTA_DST]), abuf, sizeof(abuf)) ); } } else if (r->rtm_dst_len) { fprintf(fp, "0/%d ", r->rtm_dst_len); } else { fprintf(fp, "default "); } if (tb[RTA_SRC]) { if (r->rtm_src_len != host_len) { fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_SRC]), RTA_DATA(tb[RTA_SRC]), abuf, sizeof(abuf)), r->rtm_src_len ); } else { fprintf(fp, "from %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_SRC]), RTA_DATA(tb[RTA_SRC]), abuf, sizeof(abuf)) ); } } else if (r->rtm_src_len) { fprintf(fp, "from 0/%u ", r->rtm_src_len); } if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) { fprintf(fp, "via %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_GATEWAY]), RTA_DATA(tb[RTA_GATEWAY]), abuf, sizeof(abuf))); } if (tb[RTA_OIF] && filter.oifmask != -1) { fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF]))); } if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) { /* Do not use format_host(). It is our local addr and symbolic name will not be useful. */ fprintf(fp, " src %s ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_PREFSRC]), RTA_DATA(tb[RTA_PREFSRC]), abuf, sizeof(abuf))); } if (tb[RTA_PRIORITY]) { fprintf(fp, " metric %d ", *(__u32*)RTA_DATA(tb[RTA_PRIORITY])); } if (r->rtm_family == AF_INET6) { struct rta_cacheinfo *ci = NULL; if (tb[RTA_CACHEINFO]) { ci = RTA_DATA(tb[RTA_CACHEINFO]); } if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) { static int hz; if (!hz) { hz = get_hz(); } if (r->rtm_flags & RTM_F_CLONED) { fprintf(fp, "%s cache ", _SL_); } if (ci->rta_expires) { fprintf(fp, " expires %dsec", ci->rta_expires/hz); } if (ci->rta_error != 0) { fprintf(fp, " error %d", ci->rta_error); } } else if (ci) { if (ci->rta_error != 0) fprintf(fp, " error %d", ci->rta_error); } } if (tb[RTA_IIF] && filter.iifmask != -1) { fprintf(fp, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF]))); } fprintf(fp, "\n"); fflush(fp); return 0; }
int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; struct ifaddrmsg *ifa = NLMSG_DATA(n); int len = n->nlmsg_len; int deprecated = 0; /* Use local copy of ifa_flags to not interfere with filtering code */ unsigned int ifa_flags; struct rtattr * rta_tb[IFA_MAX+1]; char abuf[256]; SPRINT_BUF(b1); if (n->nlmsg_type != RTM_NEWADDR && n->nlmsg_type != RTM_DELADDR) return 0; len -= NLMSG_LENGTH(sizeof(*ifa)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } if (filter.flushb && n->nlmsg_type != RTM_NEWADDR) return 0; parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))); if (!rta_tb[IFA_LOCAL]) rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; if (!rta_tb[IFA_ADDRESS]) rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL]; if (filter.ifindex && filter.ifindex != ifa->ifa_index) return 0; if ((filter.scope^ifa->ifa_scope)&filter.scopemask) return 0; if ((filter.flags^ifa->ifa_flags)&filter.flagmask) return 0; if (filter.label) { SPRINT_BUF(b1); const char *label; if (rta_tb[IFA_LABEL]) label = RTA_DATA(rta_tb[IFA_LABEL]); else label = ll_idx_n2a(ifa->ifa_index, b1); if (fnmatch(filter.label, label, 0) != 0) return 0; } if (filter.pfx.family) { if (rta_tb[IFA_LOCAL]) { inet_prefix dst; memset(&dst, 0, sizeof(dst)); dst.family = ifa->ifa_family; memcpy(&dst.data, RTA_DATA(rta_tb[IFA_LOCAL]), RTA_PAYLOAD(rta_tb[IFA_LOCAL])); if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) return 0; } } if (filter.family && filter.family != ifa->ifa_family) return 0; if (filter.flushb) { struct nlmsghdr *fn; if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) { if (flush_update()) return -1; } fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp)); memcpy(fn, n, n->nlmsg_len); fn->nlmsg_type = RTM_DELADDR; fn->nlmsg_flags = NLM_F_REQUEST; fn->nlmsg_seq = ++rth.seq; filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb; filter.flushed++; if (show_stats < 2) return 0; } if (n->nlmsg_type == RTM_DELADDR) fprintf(fp, "Deleted "); if (filter.oneline || filter.flushb) fprintf(fp, "%u: %s", ifa->ifa_index, ll_index_to_name(ifa->ifa_index)); if (ifa->ifa_family == AF_INET) fprintf(fp, " inet "); else if (ifa->ifa_family == AF_INET6) fprintf(fp, " inet6 "); else if (ifa->ifa_family == AF_DECnet) fprintf(fp, " dnet "); else if (ifa->ifa_family == AF_IPX) fprintf(fp, " ipx "); else fprintf(fp, " family %d ", ifa->ifa_family); if (rta_tb[IFA_LOCAL]) { fprintf(fp, "%s", rt_addr_n2a(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_LOCAL]), RTA_DATA(rta_tb[IFA_LOCAL]), abuf, sizeof(abuf))); if (rta_tb[IFA_ADDRESS] == NULL || memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), ifa->ifa_family == AF_INET ? 4 : 16) == 0) { fprintf(fp, "/%d ", ifa->ifa_prefixlen); } else { fprintf(fp, " peer %s/%d ", rt_addr_n2a(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_ADDRESS]), abuf, sizeof(abuf)), ifa->ifa_prefixlen); } } if (rta_tb[IFA_BROADCAST]) { fprintf(fp, "brd %s ", rt_addr_n2a(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_BROADCAST]), RTA_DATA(rta_tb[IFA_BROADCAST]), abuf, sizeof(abuf))); } if (rta_tb[IFA_ANYCAST]) { fprintf(fp, "any %s ", rt_addr_n2a(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_ANYCAST]), RTA_DATA(rta_tb[IFA_ANYCAST]), abuf, sizeof(abuf))); } fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1))); ifa_flags = ifa->ifa_flags; if (ifa->ifa_flags&IFA_F_SECONDARY) { ifa_flags &= ~IFA_F_SECONDARY; if (ifa->ifa_family == AF_INET6) fprintf(fp, "temporary "); else fprintf(fp, "secondary "); } if (ifa->ifa_flags&IFA_F_TENTATIVE) { ifa_flags &= ~IFA_F_TENTATIVE; fprintf(fp, "tentative "); } if (ifa->ifa_flags&IFA_F_DEPRECATED) { ifa_flags &= ~IFA_F_DEPRECATED; deprecated = 1; fprintf(fp, "deprecated "); } if (ifa->ifa_flags&IFA_F_HOMEADDRESS) { ifa_flags &= ~IFA_F_HOMEADDRESS; fprintf(fp, "home "); } if (ifa->ifa_flags&IFA_F_NODAD) { ifa_flags &= ~IFA_F_NODAD; fprintf(fp, "nodad "); } if (!(ifa->ifa_flags&IFA_F_PERMANENT)) { fprintf(fp, "dynamic "); } else ifa_flags &= ~IFA_F_PERMANENT; if (ifa->ifa_flags&IFA_F_DADFAILED) { ifa_flags &= ~IFA_F_DADFAILED; fprintf(fp, "dadfailed "); } if (ifa_flags) fprintf(fp, "flags %02x ", ifa_flags); if (rta_tb[IFA_LABEL]) fprintf(fp, "%s", rta_getattr_str(rta_tb[IFA_LABEL])); if (rta_tb[IFA_CACHEINFO]) { struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]); fprintf(fp, "%s", _SL_); fprintf(fp, " valid_lft "); if (ci->ifa_valid == INFINITY_LIFE_TIME) fprintf(fp, "forever"); else fprintf(fp, "%usec", ci->ifa_valid); fprintf(fp, " preferred_lft "); if (ci->ifa_prefered == INFINITY_LIFE_TIME) fprintf(fp, "forever"); else { if (deprecated) fprintf(fp, "%dsec", ci->ifa_prefered); else fprintf(fp, "%usec", ci->ifa_prefered); } } fprintf(fp, "\n"); fflush(fp); return 0; }
int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr * tb[RTA_MAX+1]; char abuf[256]; inet_prefix dst; inet_prefix src; inet_prefix prefsrc; inet_prefix via; int host_len = -1; static int ip6_multiple_tables; __u32 table; SPRINT_BUF(b1); static int hz; if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) { fprintf(stderr, "Not a route: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return 0; } if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE) return 0; len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } if (r->rtm_family == AF_INET6) host_len = 128; else if (r->rtm_family == AF_INET) host_len = 32; else if (r->rtm_family == AF_DECnet) host_len = 16; else if (r->rtm_family == AF_IPX) host_len = 80; parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); table = rtm_get_table(r, tb); if (r->rtm_family == AF_INET6 && table != RT_TABLE_MAIN) ip6_multiple_tables = 1; if (filter.cloned == !(r->rtm_flags&RTM_F_CLONED)) return 0; if (r->rtm_family == AF_INET6 && !ip6_multiple_tables) { if (filter.tb) { if (filter.tb == RT_TABLE_LOCAL) { if (r->rtm_type != RTN_LOCAL) return 0; } else if (filter.tb == RT_TABLE_MAIN) { if (r->rtm_type == RTN_LOCAL) return 0; } else { return 0; } } } else { if (filter.tb > 0 && filter.tb != table) return 0; } if ((filter.protocol^r->rtm_protocol)&filter.protocolmask) return 0; if ((filter.scope^r->rtm_scope)&filter.scopemask) return 0; if ((filter.type^r->rtm_type)&filter.typemask) return 0; if ((filter.tos^r->rtm_tos)&filter.tosmask) return 0; if (filter.rdst.family && (r->rtm_family != filter.rdst.family || filter.rdst.bitlen > r->rtm_dst_len)) return 0; if (filter.mdst.family && (r->rtm_family != filter.mdst.family || (filter.mdst.bitlen >= 0 && filter.mdst.bitlen < r->rtm_dst_len))) return 0; if (filter.rsrc.family && (r->rtm_family != filter.rsrc.family || filter.rsrc.bitlen > r->rtm_src_len)) return 0; if (filter.msrc.family && (r->rtm_family != filter.msrc.family || (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len))) return 0; if (filter.rvia.family && r->rtm_family != filter.rvia.family) return 0; if (filter.rprefsrc.family && r->rtm_family != filter.rprefsrc.family) return 0; memset(&dst, 0, sizeof(dst)); dst.family = r->rtm_family; if (tb[RTA_DST]) memcpy(&dst.data, RTA_DATA(tb[RTA_DST]), (r->rtm_dst_len+7)/8); if (filter.rsrc.family || filter.msrc.family) { memset(&src, 0, sizeof(src)); src.family = r->rtm_family; if (tb[RTA_SRC]) memcpy(&src.data, RTA_DATA(tb[RTA_SRC]), (r->rtm_src_len+7)/8); } if (filter.rvia.bitlen>0) { memset(&via, 0, sizeof(via)); via.family = r->rtm_family; if (tb[RTA_GATEWAY]) memcpy(&via.data, RTA_DATA(tb[RTA_GATEWAY]), host_len/8); } if (filter.rprefsrc.bitlen>0) { memset(&prefsrc, 0, sizeof(prefsrc)); prefsrc.family = r->rtm_family; if (tb[RTA_PREFSRC]) memcpy(&prefsrc.data, RTA_DATA(tb[RTA_PREFSRC]), host_len/8); } if (filter.rdst.family && inet_addr_match(&dst, &filter.rdst, filter.rdst.bitlen)) return 0; if (filter.mdst.family && filter.mdst.bitlen >= 0 && inet_addr_match(&dst, &filter.mdst, r->rtm_dst_len)) return 0; if (filter.rsrc.family && inet_addr_match(&src, &filter.rsrc, filter.rsrc.bitlen)) return 0; if (filter.msrc.family && filter.msrc.bitlen >= 0 && inet_addr_match(&src, &filter.msrc, r->rtm_src_len)) return 0; if (filter.rvia.family && inet_addr_match(&via, &filter.rvia, filter.rvia.bitlen)) return 0; if (filter.rprefsrc.family && inet_addr_match(&prefsrc, &filter.rprefsrc, filter.rprefsrc.bitlen)) return 0; if (filter.realmmask) { __u32 realms = 0; if (tb[RTA_FLOW]) realms = *(__u32*)RTA_DATA(tb[RTA_FLOW]); if ((realms^filter.realm)&filter.realmmask) return 0; } if (filter.iifmask) { int iif = 0; if (tb[RTA_IIF]) iif = *(int*)RTA_DATA(tb[RTA_IIF]); if ((iif^filter.iif)&filter.iifmask) return 0; } if (filter.oifmask) { int oif = 0; if (tb[RTA_OIF]) oif = *(int*)RTA_DATA(tb[RTA_OIF]); if ((oif^filter.oif)&filter.oifmask) return 0; } if (filter.flushb && r->rtm_family == AF_INET6 && r->rtm_dst_len == 0 && r->rtm_type == RTN_UNREACHABLE && tb[RTA_PRIORITY] && *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1) return 0; if (filter.flushb) { struct nlmsghdr *fn; if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) { if (flush_update()) return -1; } fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp)); memcpy(fn, n, n->nlmsg_len); fn->nlmsg_type = RTM_DELROUTE; fn->nlmsg_flags = NLM_F_REQUEST; fn->nlmsg_seq = ++rth.seq; filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb; filter.flushed++; if (show_stats < 2) return 0; } if (n->nlmsg_type == RTM_DELROUTE) fprintf(fp, "Deleted "); if (r->rtm_type != RTN_UNICAST && !filter.type) fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1))); if (tb[RTA_DST]) { if (r->rtm_dst_len != host_len) { fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_DST]), RTA_DATA(tb[RTA_DST]), abuf, sizeof(abuf)), r->rtm_dst_len ); } else { fprintf(fp, "%s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_DST]), RTA_DATA(tb[RTA_DST]), abuf, sizeof(abuf)) ); } } else if (r->rtm_dst_len) { fprintf(fp, "0/%d ", r->rtm_dst_len); } else { fprintf(fp, "default "); } if (tb[RTA_SRC]) { if (r->rtm_src_len != host_len) { fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_SRC]), RTA_DATA(tb[RTA_SRC]), abuf, sizeof(abuf)), r->rtm_src_len ); } else { fprintf(fp, "from %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_SRC]), RTA_DATA(tb[RTA_SRC]), abuf, sizeof(abuf)) ); } } else if (r->rtm_src_len) { fprintf(fp, "from 0/%u ", r->rtm_src_len); } if (r->rtm_tos && filter.tosmask != -1) { SPRINT_BUF(b1); fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1))); } if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) { fprintf(fp, "via %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_GATEWAY]), RTA_DATA(tb[RTA_GATEWAY]), abuf, sizeof(abuf))); } if (tb[RTA_OIF] && filter.oifmask != -1) fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF]))); if (!(r->rtm_flags&RTM_F_CLONED)) { if (table != RT_TABLE_MAIN && !filter.tb) fprintf(fp, " table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1))); if (r->rtm_protocol != RTPROT_BOOT && filter.protocolmask != -1) fprintf(fp, " proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1))); if (r->rtm_scope != RT_SCOPE_UNIVERSE && filter.scopemask != -1) fprintf(fp, " scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1))); } if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) { /* Do not use format_host(). It is our local addr and symbolic name will not be useful. */ fprintf(fp, " src %s ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_PREFSRC]), RTA_DATA(tb[RTA_PREFSRC]), abuf, sizeof(abuf))); } if (tb[RTA_PRIORITY]) fprintf(fp, " metric %d ", *(__u32*)RTA_DATA(tb[RTA_PRIORITY])); if (r->rtm_flags & RTNH_F_DEAD) fprintf(fp, "dead "); if (r->rtm_flags & RTNH_F_ONLINK) fprintf(fp, "onlink "); if (r->rtm_flags & RTNH_F_PERVASIVE) fprintf(fp, "pervasive "); if (r->rtm_flags & RTM_F_NOTIFY) fprintf(fp, "notify "); if (tb[RTA_FLOW] && filter.realmmask != ~0U) { __u32 to = *(__u32*)RTA_DATA(tb[RTA_FLOW]); __u32 from = to>>16; to &= 0xFFFF; fprintf(fp, "realm%s ", from ? "s" : ""); if (from) { fprintf(fp, "%s/", rtnl_rtrealm_n2a(from, b1, sizeof(b1))); } fprintf(fp, "%s ", rtnl_rtrealm_n2a(to, b1, sizeof(b1))); }
int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, 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])); if (tb[NETCONFA_PROXY_NEIGH]) fprintf(fp, "proxy_neigh %s ", *(int *)RTA_DATA(tb[NETCONFA_PROXY_NEIGH])?"on":"off"); fprintf(fp, "\n"); fflush(fp); return 0; }
static int print_ntable(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; struct ndtmsg *ndtm = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[NDTA_MAX+1]; struct rtattr *tpb[NDTPA_MAX+1]; int ret; if (n->nlmsg_type != RTM_NEWNEIGHTBL) { fprintf(stderr, "Not NEIGHTBL: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return 0; } len -= NLMSG_LENGTH(sizeof(*ndtm)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } if (preferred_family && preferred_family != ndtm->ndtm_family) return 0; parse_rtattr(tb, NDTA_MAX, NDTA_RTA(ndtm), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ndtm))); if (tb[NDTA_NAME]) { const char *name = rta_getattr_str(tb[NDTA_NAME]); if (strlen(filter.name) > 0 && strcmp(filter.name, name)) return 0; } if (tb[NDTA_PARMS]) { parse_rtattr(tpb, NDTPA_MAX, RTA_DATA(tb[NDTA_PARMS]), RTA_PAYLOAD(tb[NDTA_PARMS])); if (tpb[NDTPA_IFINDEX]) { __u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]); if (filter.index && filter.index != ifindex) return 0; } else { if (filter.index && filter.index != NONE_DEV) return 0; } } if (ndtm->ndtm_family == AF_INET) fprintf(fp, "inet "); else if (ndtm->ndtm_family == AF_INET6) fprintf(fp, "inet6 "); else if (ndtm->ndtm_family == AF_DECnet) fprintf(fp, "dnet "); else fprintf(fp, "(%d) ", ndtm->ndtm_family); if (tb[NDTA_NAME]) { const char *name = rta_getattr_str(tb[NDTA_NAME]); fprintf(fp, "%s ", name); } fprintf(fp, "%s", _SL_); ret = (tb[NDTA_THRESH1] || tb[NDTA_THRESH2] || tb[NDTA_THRESH3] || tb[NDTA_GC_INTERVAL]); if (ret) fprintf(fp, " "); if (tb[NDTA_THRESH1]) { __u32 thresh1 = rta_getattr_u32(tb[NDTA_THRESH1]); fprintf(fp, "thresh1 %u ", thresh1); } if (tb[NDTA_THRESH2]) { __u32 thresh2 = rta_getattr_u32(tb[NDTA_THRESH2]); fprintf(fp, "thresh2 %u ", thresh2); } if (tb[NDTA_THRESH3]) { __u32 thresh3 = rta_getattr_u32(tb[NDTA_THRESH3]); fprintf(fp, "thresh3 %u ", thresh3); } if (tb[NDTA_GC_INTERVAL]) { unsigned long long gc_int = rta_getattr_u64(tb[NDTA_GC_INTERVAL]); fprintf(fp, "gc_int %llu ", gc_int); } if (ret) fprintf(fp, "%s", _SL_); if (tb[NDTA_CONFIG] && show_stats) { struct ndt_config *ndtc = RTA_DATA(tb[NDTA_CONFIG]); fprintf(fp, " "); fprintf(fp, "config "); fprintf(fp, "key_len %u ", ndtc->ndtc_key_len); fprintf(fp, "entry_size %u ", ndtc->ndtc_entry_size); fprintf(fp, "entries %u ", ndtc->ndtc_entries); fprintf(fp, "%s", _SL_); fprintf(fp, " "); fprintf(fp, "last_flush %s ", ntable_strtime_delta(ndtc->ndtc_last_flush)); fprintf(fp, "last_rand %s ", ntable_strtime_delta(ndtc->ndtc_last_rand)); fprintf(fp, "%s", _SL_); fprintf(fp, " "); fprintf(fp, "hash_rnd %u ", ndtc->ndtc_hash_rnd); fprintf(fp, "hash_mask %08x ", ndtc->ndtc_hash_mask); fprintf(fp, "hash_chain_gc %u ", ndtc->ndtc_hash_chain_gc); fprintf(fp, "proxy_qlen %u ", ndtc->ndtc_proxy_qlen); fprintf(fp, "%s", _SL_); } if (tb[NDTA_PARMS]) { if (tpb[NDTPA_IFINDEX]) { __u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]); fprintf(fp, " "); fprintf(fp, "dev %s ", ll_index_to_name(ifindex)); fprintf(fp, "%s", _SL_); } fprintf(fp, " "); if (tpb[NDTPA_REFCNT]) { __u32 refcnt = rta_getattr_u32(tpb[NDTPA_REFCNT]); fprintf(fp, "refcnt %u ", refcnt); } if (tpb[NDTPA_REACHABLE_TIME]) { unsigned long long reachable = rta_getattr_u64(tpb[NDTPA_REACHABLE_TIME]); fprintf(fp, "reachable %llu ", reachable); } if (tpb[NDTPA_BASE_REACHABLE_TIME]) { unsigned long long breachable = rta_getattr_u64(tpb[NDTPA_BASE_REACHABLE_TIME]); fprintf(fp, "base_reachable %llu ", breachable); } if (tpb[NDTPA_RETRANS_TIME]) { unsigned long long retrans = rta_getattr_u64(tpb[NDTPA_RETRANS_TIME]); fprintf(fp, "retrans %llu ", retrans); } fprintf(fp, "%s", _SL_); fprintf(fp, " "); if (tpb[NDTPA_GC_STALETIME]) { unsigned long long gc_stale = rta_getattr_u64(tpb[NDTPA_GC_STALETIME]); fprintf(fp, "gc_stale %llu ", gc_stale); } if (tpb[NDTPA_DELAY_PROBE_TIME]) { unsigned long long delay_probe = rta_getattr_u64(tpb[NDTPA_DELAY_PROBE_TIME]); fprintf(fp, "delay_probe %llu ", delay_probe); } if (tpb[NDTPA_QUEUE_LEN]) { __u32 queue = rta_getattr_u32(tpb[NDTPA_QUEUE_LEN]); fprintf(fp, "queue %u ", queue); } fprintf(fp, "%s", _SL_); fprintf(fp, " "); if (tpb[NDTPA_APP_PROBES]) { __u32 aprobe = rta_getattr_u32(tpb[NDTPA_APP_PROBES]); fprintf(fp, "app_probes %u ", aprobe); } if (tpb[NDTPA_UCAST_PROBES]) { __u32 uprobe = rta_getattr_u32(tpb[NDTPA_UCAST_PROBES]); fprintf(fp, "ucast_probes %u ", uprobe); } if (tpb[NDTPA_MCAST_PROBES]) { __u32 mprobe = rta_getattr_u32(tpb[NDTPA_MCAST_PROBES]); fprintf(fp, "mcast_probes %u ", mprobe); } fprintf(fp, "%s", _SL_); fprintf(fp, " "); if (tpb[NDTPA_ANYCAST_DELAY]) { unsigned long long anycast_delay = rta_getattr_u64(tpb[NDTPA_ANYCAST_DELAY]); fprintf(fp, "anycast_delay %llu ", anycast_delay); } if (tpb[NDTPA_PROXY_DELAY]) { unsigned long long proxy_delay = rta_getattr_u64(tpb[NDTPA_PROXY_DELAY]); fprintf(fp, "proxy_delay %llu ", proxy_delay); } if (tpb[NDTPA_PROXY_QLEN]) { __u32 pqueue = rta_getattr_u32(tpb[NDTPA_PROXY_QLEN]); fprintf(fp, "proxy_queue %u ", pqueue); } if (tpb[NDTPA_LOCKTIME]) { unsigned long long locktime = rta_getattr_u64(tpb[NDTPA_LOCKTIME]); fprintf(fp, "locktime %llu ", locktime); } fprintf(fp, "%s", _SL_); } if (tb[NDTA_STATS] && show_stats) { struct ndt_stats *ndts = RTA_DATA(tb[NDTA_STATS]); fprintf(fp, " "); fprintf(fp, "stats "); fprintf(fp, "allocs %llu ", (unsigned long long) ndts->ndts_allocs); fprintf(fp, "destroys %llu ", (unsigned long long) ndts->ndts_destroys); fprintf(fp, "hash_grows %llu ", (unsigned long long) ndts->ndts_hash_grows); fprintf(fp, "%s", _SL_); fprintf(fp, " "); fprintf(fp, "res_failed %llu ", (unsigned long long) ndts->ndts_res_failed); fprintf(fp, "lookups %llu ", (unsigned long long) ndts->ndts_lookups); fprintf(fp, "hits %llu ", (unsigned long long) ndts->ndts_hits); fprintf(fp, "%s", _SL_); fprintf(fp, " "); fprintf(fp, "rcv_probes_mcast %llu ", (unsigned long long) ndts->ndts_rcv_probes_mcast); fprintf(fp, "rcv_probes_ucast %llu ", (unsigned long long) ndts->ndts_rcv_probes_ucast); fprintf(fp, "%s", _SL_); fprintf(fp, " "); fprintf(fp, "periodic_gc_runs %llu ", (unsigned long long) ndts->ndts_periodic_gc_runs); fprintf(fp, "forced_gc_runs %llu ", (unsigned long long) ndts->ndts_forced_gc_runs); fprintf(fp, "%s", _SL_); } fprintf(fp, "\n"); fflush(fp); return 0; }
static void print_tunnel(struct ip_tunnel_parm *p) { struct ip_tunnel_6rd ip6rd; char s1[1024]; char s2[1024]; memset(&ip6rd, 0, sizeof(ip6rd)); /* Do not use format_host() for local addr, * symbolic name will not be useful. */ printf("%s: %s/ip remote %s local %s", p->name, tnl_strproto(p->iph.protocol), p->iph.daddr ? format_host_r(AF_INET, 4, &p->iph.daddr, s1, sizeof(s1)) : "any", p->iph.saddr ? rt_addr_n2a_r(AF_INET, 4, &p->iph.saddr, s2, sizeof(s2)) : "any"); if (p->iph.protocol == IPPROTO_IPV6 && (p->i_flags & SIT_ISATAP)) { struct ip_tunnel_prl prl[16]; int i; memset(prl, 0, sizeof(prl)); prl[0].datalen = sizeof(prl) - sizeof(prl[0]); prl[0].addr = htonl(INADDR_ANY); if (!tnl_prl_ioctl(SIOCGETPRL, p->name, prl)) for (i = 1; i < ARRAY_SIZE(prl); i++) { if (prl[i].addr != htonl(INADDR_ANY)) { printf(" %s %s ", (prl[i].flags & PRL_DEFAULT) ? "pdr" : "pr", format_host(AF_INET, 4, &prl[i].addr)); } } } if (p->link) { const char *n = ll_index_to_name(p->link); if (n) printf(" dev %s", n); } if (p->iph.ttl) printf(" ttl %d", p->iph.ttl); else printf(" ttl inherit"); if (p->iph.tos) { SPRINT_BUF(b1); printf(" tos"); if (p->iph.tos & 1) printf(" inherit"); if (p->iph.tos & ~1) printf("%c%s ", p->iph.tos & 1 ? '/' : ' ', rtnl_dsfield_n2a(p->iph.tos & ~1, b1, sizeof(b1))); } if (!(p->iph.frag_off & htons(IP_DF))) printf(" nopmtudisc"); if (p->iph.protocol == IPPROTO_IPV6 && !tnl_ioctl_get_6rd(p->name, &ip6rd) && ip6rd.prefixlen) { printf(" 6rd-prefix %s/%u", inet_ntop(AF_INET6, &ip6rd.prefix, s1, sizeof(s1)), ip6rd.prefixlen); if (ip6rd.relay_prefix) { printf(" 6rd-relay_prefix %s/%u", format_host(AF_INET, 4, &ip6rd.relay_prefix), ip6rd.relay_prefixlen); } } if ((p->i_flags & GRE_KEY) && (p->o_flags & GRE_KEY) && p->o_key == p->i_key) printf(" key %u", ntohl(p->i_key)); else if ((p->i_flags | p->o_flags) & GRE_KEY) { if (p->i_flags & GRE_KEY) printf(" ikey %u", ntohl(p->i_key)); if (p->o_flags & GRE_KEY) printf(" okey %u", ntohl(p->o_key)); } if (p->i_flags & GRE_SEQ) printf("%s Drop packets out of sequence.", _SL_); if (p->i_flags & GRE_CSUM) printf("%s Checksum in received packet is required.", _SL_); if (p->o_flags & GRE_SEQ) printf("%s Sequence packets on output.", _SL_); if (p->o_flags & GRE_CSUM) printf("%s Checksum output packets.", _SL_); }
static int vlan_modify(int cmd, int argc, char **argv) { struct { struct nlmsghdr n; struct ifinfomsg ifm; char buf[1024]; } req = { .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), .n.nlmsg_flags = NLM_F_REQUEST, .n.nlmsg_type = cmd, .ifm.ifi_family = PF_BRIDGE, }; char *d = NULL; short vid = -1; short vid_end = -1; struct rtattr *afspec; struct bridge_vlan_info vinfo = {}; unsigned short flags = 0; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); d = *argv; } else if (strcmp(*argv, "vid") == 0) { char *p; NEXT_ARG(); p = strchr(*argv, '-'); if (p) { *p = '\0'; p++; vid = atoi(*argv); vid_end = atoi(p); vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN; } else { vid = atoi(*argv); } } else if (strcmp(*argv, "self") == 0) { flags |= BRIDGE_FLAGS_SELF; } else if (strcmp(*argv, "master") == 0) { flags |= BRIDGE_FLAGS_MASTER; } else if (strcmp(*argv, "pvid") == 0) { vinfo.flags |= BRIDGE_VLAN_INFO_PVID; } else if (strcmp(*argv, "untagged") == 0) { vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED; } else { if (matches(*argv, "help") == 0) { NEXT_ARG(); } } argc--; argv++; } if (d == NULL || vid == -1) { fprintf(stderr, "Device and VLAN ID are required arguments.\n"); return -1; } req.ifm.ifi_index = ll_name_to_index(d); if (req.ifm.ifi_index == 0) { fprintf(stderr, "Cannot find bridge device \"%s\"\n", d); return -1; } if (vid >= 4096) { fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid); return -1; } if (vinfo.flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) { if (vid_end == -1 || vid_end >= 4096 || vid >= vid_end) { fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n", vid, vid_end); return -1; } if (vinfo.flags & BRIDGE_VLAN_INFO_PVID) { fprintf(stderr, "pvid cannot be configured for a vlan range\n"); return -1; } } afspec = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC); if (flags) addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags); vinfo.vid = vid; if (vid_end != -1) { /* send vlan range start */ addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo, sizeof(vinfo)); vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN; /* Now send the vlan range end */ vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_END; vinfo.vid = vid_end; addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo, sizeof(vinfo)); } else { addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo, sizeof(vinfo)); } addattr_nest_end(&req.n, afspec); if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) return -1; return 0; } /* In order to use this function for both filtering and non-filtering cases * we need to make it a tristate: * return -1 - if filtering we've gone over so don't continue * return 0 - skip entry and continue (applies to range start or to entries * which are less than filter_vlan) * return 1 - print the entry and continue */ static int filter_vlan_check(struct bridge_vlan_info *vinfo) { /* if we're filtering we should stop on the first greater entry */ if (filter_vlan && vinfo->vid > filter_vlan && !(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END)) return -1; if ((vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) || vinfo->vid < filter_vlan) return 0; return 1; } static void print_vlan_port(FILE *fp, int ifi_index) { if (jw_global) { jsonw_pretty(jw_global, 1); jsonw_name(jw_global, ll_index_to_name(ifi_index)); jsonw_start_array(jw_global); } else { fprintf(fp, "%s", ll_index_to_name(ifi_index)); } } static void start_json_vlan_flags_array(bool *vlan_flags) { if (*vlan_flags) return; jsonw_name(jw_global, "flags"); jsonw_start_array(jw_global); *vlan_flags = true; } static int print_vlan(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = arg; struct ifinfomsg *ifm = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[IFLA_MAX+1]; bool vlan_flags; if (n->nlmsg_type != RTM_NEWLINK) { fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return 0; } len -= NLMSG_LENGTH(sizeof(*ifm)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } if (ifm->ifi_family != AF_BRIDGE) return 0; if (filter_index && filter_index != ifm->ifi_index) return 0; parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifm), len); /* if AF_SPEC isn't there, vlan table is not preset for this port */ if (!tb[IFLA_AF_SPEC]) { if (!filter_vlan) fprintf(fp, "%s\tNone\n", ll_index_to_name(ifm->ifi_index)); return 0; } else { struct rtattr *i, *list = tb[IFLA_AF_SPEC]; int rem = RTA_PAYLOAD(list); __u16 last_vid_start = 0; if (!filter_vlan) print_vlan_port(fp, ifm->ifi_index); for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { struct bridge_vlan_info *vinfo; int vcheck_ret; if (i->rta_type != IFLA_BRIDGE_VLAN_INFO) continue; vinfo = RTA_DATA(i); if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END)) last_vid_start = vinfo->vid; vcheck_ret = filter_vlan_check(vinfo); if (vcheck_ret == -1) break; else if (vcheck_ret == 0) continue; if (filter_vlan) print_vlan_port(fp, ifm->ifi_index); if (jw_global) { jsonw_start_object(jw_global); jsonw_uint_field(jw_global, "vlan", last_vid_start); if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) continue; } else { fprintf(fp, "\t %hu", last_vid_start); } if (last_vid_start != vinfo->vid) { if (jw_global) jsonw_uint_field(jw_global, "vlanEnd", vinfo->vid); else fprintf(fp, "-%hu", vinfo->vid); } if (vinfo->flags & BRIDGE_VLAN_INFO_PVID) { if (jw_global) { start_json_vlan_flags_array(&vlan_flags); jsonw_string(jw_global, "PVID"); } else { fprintf(fp, " PVID"); } } if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED) { if (jw_global) { start_json_vlan_flags_array(&vlan_flags); jsonw_string(jw_global, "Egress Untagged"); } else { fprintf(fp, " Egress Untagged"); } } if (vlan_flags) { jsonw_end_array(jw_global); vlan_flags = false; } if (jw_global) jsonw_end_object(jw_global); else fprintf(fp, "\n"); } } if (!filter_vlan) { if (jw_global) jsonw_end_array(jw_global); else fprintf(fp, "\n"); } fflush(fp); return 0; }