static void vlan_print_map(FILE *f, const char *name_json, const char *name_fp, struct rtattr *attr) { struct ifla_vlan_qos_mapping *m; struct rtattr *i; int rem; open_json_array(PRINT_JSON, name_json); print_string(PRINT_FP, NULL, "\n %s { ", name_fp); rem = RTA_PAYLOAD(attr); for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { m = RTA_DATA(i); if (is_json_context()) { open_json_object(NULL); print_uint(PRINT_JSON, "from", NULL, m->from); print_uint(PRINT_JSON, "to", NULL, m->to); close_json_object(); } else { fprintf(f, "%u:%u ", m->from, m->to); } } close_json_array(PRINT_JSON, NULL); print_string(PRINT_FP, NULL, "%s ", "}"); }
unsigned int print_name_and_link(const char *fmt, const char *name, struct rtattr *tb[]) { const char *link = NULL; unsigned int m_flag = 0; SPRINT_BUF(b1); if (tb[IFLA_LINK]) { int iflink = rta_getattr_u32(tb[IFLA_LINK]); if (iflink) { if (tb[IFLA_LINK_NETNSID]) { if (is_json_context()) { print_int(PRINT_JSON, "link_index", NULL, iflink); } else { link = ll_idx_n2a(iflink); } } else { link = ll_index_to_name(iflink); if (is_json_context()) { print_string(PRINT_JSON, "link", NULL, link); link = NULL; } m_flag = ll_index_to_flags(iflink); m_flag = !(m_flag & IFF_UP); } } else { if (is_json_context()) print_null(PRINT_JSON, "link", NULL, NULL); else link = "NONE"; } if (link) { snprintf(b1, sizeof(b1), "%s@%s", name, link); name = b1; } } print_color_string(PRINT_ANY, COLOR_IFNAME, "ifname", fmt, name); return m_flag; }
static void print_stats(const char *prefix, const char *names[], unsigned int num, struct rtattr *stats[]) { if (is_json_context()) print_json_stats(names, num, stats); else print_fp_stats(prefix, names, num, stats); }
static void vlan_print_flags(FILE *fp, __u32 flags) { open_json_array(PRINT_ANY, is_json_context() ? "flags" : "<"); #define _PF(f) if (flags & VLAN_FLAG_##f) { \ flags &= ~VLAN_FLAG_##f; \ print_string(PRINT_ANY, NULL, flags ? "%s," : "%s", #f); \ } _PF(REORDER_HDR); _PF(GVRP); _PF(MVRP); _PF(LOOSE_BINDING); #undef _PF if (flags) print_hex(PRINT_ANY, NULL, "%x", flags); close_json_array(PRINT_ANY, "> "); }
static void print_flag(struct rtattr *attrs[], const char *desc, int field) { __u8 flag; if (!attrs[field]) return; flag = rta_getattr_u8(attrs[field]); if (is_json_context()) print_bool(PRINT_JSON, desc, NULL, flag); else { print_string(PRINT_FP, NULL, "%s ", desc); print_string(PRINT_FP, NULL, "%s ", flag ? "on" : "off"); } }
static void _bridge_print_timer(FILE *f, const char *attr, struct rtattr *timer) { struct timeval tv; __jiffies_to_tv(&tv, rta_getattr_u64(timer)); if (is_json_context()) { json_writer_t *jw = get_json_writer(); jsonw_name(jw, attr); jsonw_printf(jw, "%i.%.2i", (int)tv.tv_sec, (int)tv.tv_usec / 10000); } else { fprintf(f, "%s %4i.%.2i ", attr, (int)tv.tv_sec, (int)tv.tv_usec / 10000); } }
static void link_mon_print_peer_state(const uint32_t addr, const char *status, const char *monitored, const uint32_t dom_gen) { char addr_str[16]; sprintf(addr_str, "%u.%u.%u", tipc_zone(addr), tipc_cluster(addr), tipc_node(addr)); if (is_json_context()) { print_string(PRINT_JSON, "node", NULL, addr_str); print_string(PRINT_JSON, "status", NULL, status); print_string(PRINT_JSON, "monitored", NULL, monitored); print_uint(PRINT_JSON, "generation", NULL, dom_gen); } else { printf("%-*s", MAX_NODE_WIDTH, addr_str); printf("%-*s", STATUS_WIDTH, status); printf("%-*s", DIRECTLY_MON_WIDTH, monitored); printf("%-*u", MAX_DOM_GEN_WIDTH, dom_gen); } }
int print_neigh(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]; static int logit = 1; __u8 protocol = 0; 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_flags & NTF_EXT_LEARNED) && (r->ndm_state || !(filter.state&0x100)) && (r->ndm_family != AF_DECnet)) return 0; if (filter.master && !(n->nlmsg_flags & NLM_F_DUMP_FILTERED)) { if (logit) { logit = 0; fprintf(fp, "\nWARNING: Kernel does not support filtering by master device\n\n"); } } parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); if (inet_addr_match_rta(&filter.pfx, tb[NDA_DST])) 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]) { 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; } open_json_object(NULL); if (n->nlmsg_type == RTM_DELNEIGH) print_bool(PRINT_ANY, "deleted", "Deleted ", true); else if (n->nlmsg_type == RTM_GETNEIGH) print_null(PRINT_ANY, "miss", "%s ", "miss"); if (tb[NDA_DST]) { const char *dst; int family = r->ndm_family; if (family == AF_BRIDGE) { if (RTA_PAYLOAD(tb[NDA_DST]) == sizeof(struct in6_addr)) family = AF_INET6; else family = AF_INET; } dst = format_host_rta(family, tb[NDA_DST]); print_color_string(PRINT_ANY, ifa_family_color(family), "dst", "%s ", dst); } if (!filter.index && r->ndm_ifindex) { if (!is_json_context()) fprintf(fp, "dev "); print_color_string(PRINT_ANY, COLOR_IFNAME, "dev", "%s ", ll_index_to_name(r->ndm_ifindex)); } if (tb[NDA_LLADDR]) { const char *lladdr; SPRINT_BUF(b1); lladdr = ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]), RTA_PAYLOAD(tb[NDA_LLADDR]), ll_index_to_type(r->ndm_ifindex), b1, sizeof(b1)); if (!is_json_context()) fprintf(fp, "lladdr "); print_color_string(PRINT_ANY, COLOR_MAC, "lladdr", "%s", lladdr); } if (r->ndm_flags & NTF_ROUTER) print_null(PRINT_ANY, "router", " %s", "router"); if (r->ndm_flags & NTF_PROXY) print_null(PRINT_ANY, "proxy", " %s", "proxy"); if (r->ndm_flags & NTF_EXT_LEARNED) print_null(PRINT_ANY, "extern_learn", " %s ", "extern_learn"); if (show_stats) { if (tb[NDA_CACHEINFO]) print_cacheinfo(RTA_DATA(tb[NDA_CACHEINFO])); if (tb[NDA_PROBES]) print_uint(PRINT_ANY, "probes", " probes %u", rta_getattr_u32(tb[NDA_PROBES])); } if (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", ""); close_json_object(); fflush(stdout); return 0; }
static int ipneigh_modify(int cmd, int flags, int argc, char **argv) { struct { struct nlmsghdr n; struct ndmsg ndm; char buf[256]; } req = { .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)), .n.nlmsg_flags = NLM_F_REQUEST | flags, .n.nlmsg_type = cmd, .ndm.ndm_family = preferred_family, .ndm.ndm_state = NUD_PERMANENT, }; char *dev = NULL; int dst_ok = 0; int dev_ok = 0; int lladdr_ok = 0; char *lla = NULL; inet_prefix dst; while (argc > 0) { if (matches(*argv, "lladdr") == 0) { NEXT_ARG(); if (lladdr_ok) duparg("lladdr", *argv); lla = *argv; lladdr_ok = 1; } else if (strcmp(*argv, "nud") == 0) { unsigned int state; NEXT_ARG(); if (nud_state_a2n(&state, *argv)) invarg("nud state is bad", *argv); req.ndm.ndm_state = state; } else if (matches(*argv, "proxy") == 0) { NEXT_ARG(); if (matches(*argv, "help") == 0) usage(); if (dst_ok) duparg("address", *argv); get_addr(&dst, *argv, preferred_family); dst_ok = 1; dev_ok = 1; req.ndm.ndm_flags |= NTF_PROXY; } else if (strcmp(*argv, "router") == 0) { req.ndm.ndm_flags |= NTF_ROUTER; } else if (matches(*argv, "extern_learn") == 0) { req.ndm.ndm_flags |= NTF_EXT_LEARNED; } else if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); dev = *argv; 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 { if (strcmp(*argv, "to") == 0) { NEXT_ARG(); } if (matches(*argv, "help") == 0) { NEXT_ARG(); } if (dst_ok) duparg2("to", *argv); get_addr(&dst, *argv, preferred_family); dst_ok = 1; } argc--; argv++; } if (!dev_ok || !dst_ok || dst.family == AF_UNSPEC) { fprintf(stderr, "Device and destination are required arguments.\n"); exit(-1); } req.ndm.ndm_family = dst.family; if (addattr_l(&req.n, sizeof(req), NDA_DST, &dst.data, dst.bytelen) < 0) return -1; if (lla && strcmp(lla, "null")) { char llabuf[20]; int l; l = ll_addr_a2n(llabuf, sizeof(llabuf), lla); if (l < 0) return -1; if (addattr_l(&req.n, sizeof(req), NDA_LLADDR, llabuf, l) < 0) return -1; } ll_init_map(&rth); if (dev) { req.ndm.ndm_ifindex = ll_name_to_index(dev); if (!req.ndm.ndm_ifindex) return nodev(dev); } if (rtnl_talk(&rth, &req.n, NULL) < 0) exit(2); return 0; } static void print_cacheinfo(const struct nda_cacheinfo *ci) { static int hz; if (!hz) hz = get_user_hz(); if (ci->ndm_refcnt) print_uint(PRINT_ANY, "refcnt", " ref %u", ci->ndm_refcnt); print_uint(PRINT_ANY, "used", " used %u", ci->ndm_used / hz); print_uint(PRINT_ANY, "confirmed", "/%u", ci->ndm_confirmed / hz); print_uint(PRINT_ANY, "updated", "/%u", ci->ndm_updated / hz); } static void print_neigh_state(unsigned int nud) { open_json_array(PRINT_JSON, is_json_context() ? "state" : ""); #define PRINT_FLAG(f) \ if (nud & NUD_##f) { \ nud &= ~NUD_##f; \ print_string(PRINT_ANY, NULL, " %s", #f); \ } 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 close_json_array(PRINT_JSON, NULL); }
/* device creation */ static void macsec_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) { if (!tb) return; if (tb[IFLA_MACSEC_SCI]) { if (is_json_context()) { SPRINT_BUF(b1); snprintf(b1, sizeof(b1), "%016llx", ntohll(rta_getattr_u64(tb[IFLA_MACSEC_SCI]))); print_string(PRINT_JSON, "sci", NULL, b1); } else { fprintf(f, "sci %016llx ", ntohll(rta_getattr_u64(tb[IFLA_MACSEC_SCI]))); } } print_flag(tb, "protect", IFLA_MACSEC_PROTECT); if (tb[IFLA_MACSEC_CIPHER_SUITE]) { __u64 csid = rta_getattr_u64(tb[IFLA_MACSEC_CIPHER_SUITE]); print_string(PRINT_ANY, "cipher_suite", "cipher %s ", cs_id_to_name(csid)); } if (tb[IFLA_MACSEC_ICV_LEN]) { if (is_json_context()) { char b2[4]; snprintf(b2, sizeof(b2), "%hhu", rta_getattr_u8(tb[IFLA_MACSEC_ICV_LEN])); print_uint(PRINT_JSON, "icv_len", NULL, atoi(b2)); } else { fprintf(f, "icvlen %hhu ", rta_getattr_u8(tb[IFLA_MACSEC_ICV_LEN])); } } if (tb[IFLA_MACSEC_ENCODING_SA]) { if (is_json_context()) { char b2[4]; snprintf(b2, sizeof(b2), "%hhu", rta_getattr_u8(tb[IFLA_MACSEC_ENCODING_SA])); print_uint(PRINT_JSON, "encoding_sa", NULL, atoi(b2)); } else { fprintf(f, "encodingsa %hhu ", rta_getattr_u8(tb[IFLA_MACSEC_ENCODING_SA])); } } if (tb[IFLA_MACSEC_VALIDATION]) { __u8 val = rta_getattr_u8(tb[IFLA_MACSEC_VALIDATION]); print_string(PRINT_ANY, "validation", "validate %s ", validate_str[val]); } const char *inc_sci, *es, *replay; if (is_json_context()) { inc_sci = "inc_sci"; replay = "replay_protect"; es = "es"; } else { inc_sci = "send_sci"; es = "end_station"; replay = "replay"; } print_flag(tb, "encrypt", IFLA_MACSEC_ENCRYPT); print_flag(tb, inc_sci, IFLA_MACSEC_INC_SCI); print_flag(tb, es, IFLA_MACSEC_ES); print_flag(tb, "scb", IFLA_MACSEC_SCB); print_flag(tb, replay, IFLA_MACSEC_REPLAY_PROTECT); if (tb[IFLA_MACSEC_WINDOW]) print_int(PRINT_ANY, "window", "window %d ", rta_getattr_u32(tb[IFLA_MACSEC_WINDOW])); }
static int gre_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); struct { struct nlmsghdr n; struct ifinfomsg i; } req = { .n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)), .n.nlmsg_flags = NLM_F_REQUEST, .n.nlmsg_type = RTM_GETLINK, .i.ifi_family = preferred_family, .i.ifi_index = ifi->ifi_index, }; struct nlmsghdr *answer; struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct rtattr *greinfo[IFLA_GRE_MAX + 1]; __u16 iflags = 0; __u16 oflags = 0; __be32 ikey = 0; __be32 okey = 0; struct in6_addr raddr = IN6ADDR_ANY_INIT; struct in6_addr laddr = IN6ADDR_ANY_INIT; unsigned int link = 0; unsigned int flowinfo = 0; unsigned int flags = 0; __u8 hop_limit = DEFAULT_TNL_HOP_LIMIT; __u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT; __u16 encaptype = 0; __u16 encapflags = TUNNEL_ENCAP_FLAG_CSUM6; __u16 encapsport = 0; __u16 encapdport = 0; int len; __u32 fwmark = 0; __u32 erspan_idx = 0; if (!(n->nlmsg_flags & NLM_F_CREATE)) { if (rtnl_talk(&rth, &req.n, &answer) < 0) { get_failed: fprintf(stderr, "Failed to get existing tunnel info.\n"); return -1; } len = answer->nlmsg_len; len -= NLMSG_LENGTH(sizeof(*ifi)); if (len < 0) goto get_failed; parse_rtattr(tb, IFLA_MAX, IFLA_RTA(NLMSG_DATA(answer)), len); if (!tb[IFLA_LINKINFO]) goto get_failed; parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]); if (!linkinfo[IFLA_INFO_DATA]) goto get_failed; parse_rtattr_nested(greinfo, IFLA_GRE_MAX, linkinfo[IFLA_INFO_DATA]); if (greinfo[IFLA_GRE_IKEY]) ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]); if (greinfo[IFLA_GRE_OKEY]) okey = rta_getattr_u32(greinfo[IFLA_GRE_OKEY]); if (greinfo[IFLA_GRE_IFLAGS]) iflags = rta_getattr_u16(greinfo[IFLA_GRE_IFLAGS]); if (greinfo[IFLA_GRE_OFLAGS]) oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]); if (greinfo[IFLA_GRE_LOCAL]) memcpy(&laddr, RTA_DATA(greinfo[IFLA_GRE_LOCAL]), sizeof(laddr)); if (greinfo[IFLA_GRE_REMOTE]) memcpy(&raddr, RTA_DATA(greinfo[IFLA_GRE_REMOTE]), sizeof(raddr)); if (greinfo[IFLA_GRE_TTL]) hop_limit = rta_getattr_u8(greinfo[IFLA_GRE_TTL]); if (greinfo[IFLA_GRE_LINK]) link = rta_getattr_u32(greinfo[IFLA_GRE_LINK]); if (greinfo[IFLA_GRE_ENCAP_LIMIT]) encap_limit = rta_getattr_u8(greinfo[IFLA_GRE_ENCAP_LIMIT]); if (greinfo[IFLA_GRE_FLOWINFO]) flowinfo = rta_getattr_u32(greinfo[IFLA_GRE_FLOWINFO]); if (greinfo[IFLA_GRE_FLAGS]) flags = rta_getattr_u32(greinfo[IFLA_GRE_FLAGS]); if (greinfo[IFLA_GRE_ENCAP_TYPE]) encaptype = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_TYPE]); if (greinfo[IFLA_GRE_ENCAP_FLAGS]) encapflags = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_FLAGS]); if (greinfo[IFLA_GRE_ENCAP_SPORT]) encapsport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_SPORT]); if (greinfo[IFLA_GRE_ENCAP_DPORT]) encapdport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_DPORT]); if (greinfo[IFLA_GRE_FWMARK]) fwmark = rta_getattr_u32(greinfo[IFLA_GRE_FWMARK]); if (greinfo[IFLA_GRE_ERSPAN_INDEX]) erspan_idx = rta_getattr_u32(greinfo[IFLA_GRE_ERSPAN_INDEX]); free(answer); } while (argc > 0) { if (!matches(*argv, "key")) { NEXT_ARG(); iflags |= GRE_KEY; oflags |= GRE_KEY; ikey = okey = tnl_parse_key("key", *argv); } else if (!matches(*argv, "ikey")) { NEXT_ARG(); iflags |= GRE_KEY; ikey = tnl_parse_key("ikey", *argv); } else if (!matches(*argv, "okey")) { NEXT_ARG(); oflags |= GRE_KEY; okey = tnl_parse_key("okey", *argv); } else if (!matches(*argv, "seq")) { iflags |= GRE_SEQ; oflags |= GRE_SEQ; } else if (!matches(*argv, "iseq")) { iflags |= GRE_SEQ; } else if (!matches(*argv, "oseq")) { oflags |= GRE_SEQ; } else if (!matches(*argv, "csum")) { iflags |= GRE_CSUM; oflags |= GRE_CSUM; } else if (!matches(*argv, "icsum")) { iflags |= GRE_CSUM; } else if (!matches(*argv, "ocsum")) { oflags |= GRE_CSUM; } else if (!matches(*argv, "remote")) { inet_prefix addr; NEXT_ARG(); get_addr(&addr, *argv, AF_INET6); memcpy(&raddr, &addr.data, sizeof(raddr)); } else if (!matches(*argv, "local")) { inet_prefix addr; NEXT_ARG(); get_addr(&addr, *argv, AF_INET6); memcpy(&laddr, &addr.data, sizeof(laddr)); } else if (!matches(*argv, "dev")) { NEXT_ARG(); link = if_nametoindex(*argv); if (link == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", *argv); exit(-1); } } else if (!matches(*argv, "ttl") || !matches(*argv, "hoplimit")) { __u8 uval; NEXT_ARG(); if (get_u8(&uval, *argv, 0)) invarg("invalid TTL", *argv); hop_limit = uval; } else if (!matches(*argv, "tos") || !matches(*argv, "tclass") || !matches(*argv, "dsfield")) { __u8 uval; NEXT_ARG(); flowinfo &= ~IP6_FLOWINFO_TCLASS; if (strcmp(*argv, "inherit") == 0) flags |= IP6_TNL_F_USE_ORIG_TCLASS; else { if (get_u8(&uval, *argv, 16)) invarg("invalid TClass", *argv); flowinfo |= htonl((__u32)uval << 20) & IP6_FLOWINFO_TCLASS; flags &= ~IP6_TNL_F_USE_ORIG_TCLASS; } } else if (strcmp(*argv, "flowlabel") == 0 || strcmp(*argv, "fl") == 0) { __u32 uval; NEXT_ARG(); flowinfo &= ~IP6_FLOWINFO_FLOWLABEL; if (strcmp(*argv, "inherit") == 0) flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL; else { if (get_u32(&uval, *argv, 16)) invarg("invalid Flowlabel", *argv); if (uval > 0xFFFFF) invarg("invalid Flowlabel", *argv); flowinfo |= htonl(uval) & IP6_FLOWINFO_FLOWLABEL; flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL; } } else if (strcmp(*argv, "dscp") == 0) { NEXT_ARG(); if (strcmp(*argv, "inherit") != 0) invarg("not inherit", *argv); flags |= IP6_TNL_F_RCV_DSCP_COPY; } else if (strcmp(*argv, "noencap") == 0) { encaptype = TUNNEL_ENCAP_NONE; } else if (strcmp(*argv, "encap") == 0) { NEXT_ARG(); if (strcmp(*argv, "fou") == 0) encaptype = TUNNEL_ENCAP_FOU; else if (strcmp(*argv, "gue") == 0) encaptype = TUNNEL_ENCAP_GUE; else if (strcmp(*argv, "none") == 0) encaptype = TUNNEL_ENCAP_NONE; else invarg("Invalid encap type.", *argv); } else if (strcmp(*argv, "encap-sport") == 0) { NEXT_ARG(); if (strcmp(*argv, "auto") == 0) encapsport = 0; else if (get_u16(&encapsport, *argv, 0)) invarg("Invalid source port.", *argv); } else if (strcmp(*argv, "encap-dport") == 0) { NEXT_ARG(); if (get_u16(&encapdport, *argv, 0)) invarg("Invalid destination port.", *argv); } else if (strcmp(*argv, "encap-csum") == 0) { encapflags |= TUNNEL_ENCAP_FLAG_CSUM; } else if (strcmp(*argv, "noencap-csum") == 0) { encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM; } else if (strcmp(*argv, "encap-udp6-csum") == 0) { encapflags |= TUNNEL_ENCAP_FLAG_CSUM6; } else if (strcmp(*argv, "noencap-udp6-csum") == 0) { encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM6; } else if (strcmp(*argv, "encap-remcsum") == 0) { encapflags |= TUNNEL_ENCAP_FLAG_REMCSUM; } else if (strcmp(*argv, "noencap-remcsum") == 0) { encapflags &= ~TUNNEL_ENCAP_FLAG_REMCSUM; } else if (strcmp(*argv, "fwmark") == 0) { NEXT_ARG(); if (strcmp(*argv, "inherit") == 0) { flags |= IP6_TNL_F_USE_ORIG_FWMARK; fwmark = 0; } else { if (get_u32(&fwmark, *argv, 0)) invarg("invalid fwmark\n", *argv); flags &= ~IP6_TNL_F_USE_ORIG_FWMARK; } } else if (strcmp(*argv, "encaplimit") == 0) { NEXT_ARG(); if (strcmp(*argv, "none") == 0) { flags |= IP6_TNL_F_IGN_ENCAP_LIMIT; } else { __u8 uval; if (get_u8(&uval, *argv, 0)) invarg("invalid ELIM", *argv); encap_limit = uval; flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT; } } else if (strcmp(*argv, "erspan") == 0) { NEXT_ARG(); if (get_u32(&erspan_idx, *argv, 0)) invarg("invalid erspan index\n", *argv); if (erspan_idx & ~((1<<20) - 1) || erspan_idx == 0) invarg("erspan index must be > 0 and <= 20-bit\n", *argv); } else usage(); argc--; argv++; } addattr32(n, 1024, IFLA_GRE_IKEY, ikey); addattr32(n, 1024, IFLA_GRE_OKEY, okey); addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2); addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2); addattr_l(n, 1024, IFLA_GRE_LOCAL, &laddr, sizeof(laddr)); addattr_l(n, 1024, IFLA_GRE_REMOTE, &raddr, sizeof(raddr)); if (link) addattr32(n, 1024, IFLA_GRE_LINK, link); addattr_l(n, 1024, IFLA_GRE_TTL, &hop_limit, 1); addattr_l(n, 1024, IFLA_GRE_ENCAP_LIMIT, &encap_limit, 1); addattr_l(n, 1024, IFLA_GRE_FLOWINFO, &flowinfo, 4); addattr32(n, 1024, IFLA_GRE_FLAGS, flags); addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark); if (erspan_idx != 0) addattr32(n, 1024, IFLA_GRE_ERSPAN_INDEX, erspan_idx); addattr16(n, 1024, IFLA_GRE_ENCAP_TYPE, encaptype); addattr16(n, 1024, IFLA_GRE_ENCAP_FLAGS, encapflags); addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport)); addattr16(n, 1024, IFLA_GRE_ENCAP_DPORT, htons(encapdport)); return 0; } static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) { char s2[64]; const char *local = "any"; const char *remote = "any"; unsigned int iflags = 0; unsigned int oflags = 0; unsigned int flags = 0; unsigned int flowinfo = 0; struct in6_addr in6_addr_any = IN6ADDR_ANY_INIT; if (!tb) return; if (tb[IFLA_GRE_FLAGS]) flags = rta_getattr_u32(tb[IFLA_GRE_FLAGS]); if (tb[IFLA_GRE_FLOWINFO]) flowinfo = rta_getattr_u32(tb[IFLA_GRE_FLOWINFO]); if (tb[IFLA_GRE_REMOTE]) { struct in6_addr addr; memcpy(&addr, RTA_DATA(tb[IFLA_GRE_REMOTE]), sizeof(addr)); if (memcmp(&addr, &in6_addr_any, sizeof(addr))) remote = format_host(AF_INET6, sizeof(addr), &addr); } print_string(PRINT_ANY, "remote", "remote %s ", remote); if (tb[IFLA_GRE_LOCAL]) { struct in6_addr addr; memcpy(&addr, RTA_DATA(tb[IFLA_GRE_LOCAL]), sizeof(addr)); if (memcmp(&addr, &in6_addr_any, sizeof(addr))) local = format_host(AF_INET6, sizeof(addr), &addr); } print_string(PRINT_ANY, "local", "local %s ", local); if (tb[IFLA_GRE_LINK] && rta_getattr_u32(tb[IFLA_GRE_LINK])) { unsigned int link = rta_getattr_u32(tb[IFLA_GRE_LINK]); const char *n = if_indextoname(link, s2); if (n) print_string(PRINT_ANY, "link", "dev %s ", n); else print_uint(PRINT_ANY, "link_index", "dev %u ", link); } if (tb[IFLA_GRE_TTL]) { __u8 ttl = rta_getattr_u8(tb[IFLA_GRE_TTL]); if (ttl) print_int(PRINT_ANY, "ttl", "hoplimit %d ", ttl); else print_int(PRINT_JSON, "ttl", NULL, ttl); } if (flags & IP6_TNL_F_IGN_ENCAP_LIMIT) print_bool(PRINT_ANY, "ip6_tnl_f_ign_encap_limit", "encaplimit none ", true); else if (tb[IFLA_GRE_ENCAP_LIMIT]) { int encap_limit = rta_getattr_u8(tb[IFLA_GRE_ENCAP_LIMIT]); print_int(PRINT_ANY, "encap_limit", "encaplimit %d ", encap_limit); } if (flags & IP6_TNL_F_USE_ORIG_FLOWLABEL) { print_bool(PRINT_ANY, "ip6_tnl_f_use_orig_flowlabel", "flowlabel inherit ", true); } else { if (is_json_context()) { SPRINT_BUF(b1); snprintf(b1, sizeof(b1), "0x%05x", ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL)); print_string(PRINT_JSON, "flowlabel", NULL, b1); } else { fprintf(f, "flowlabel 0x%05x ", ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL)); } } if (flags & IP6_TNL_F_USE_ORIG_TCLASS) { print_bool(PRINT_ANY, "ip6_tnl_f_use_orig_tclass", "tclass inherit ", true); } else { if (is_json_context()) { SPRINT_BUF(b1); snprintf(b1, sizeof(b1), "0x%05x", ntohl(flowinfo & IP6_FLOWINFO_TCLASS) >> 20); print_string(PRINT_JSON, "tclass", NULL, b1); } else { fprintf(f, "tclass 0x%02x ", ntohl(flowinfo & IP6_FLOWINFO_TCLASS) >> 20); } }
static int gre_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); struct { struct nlmsghdr n; struct ifinfomsg i; char buf[16384]; } req = { .n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)), .n.nlmsg_flags = NLM_F_REQUEST, .n.nlmsg_type = RTM_GETLINK, .i.ifi_family = preferred_family, .i.ifi_index = ifi->ifi_index, }; struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct rtattr *greinfo[IFLA_GRE_MAX + 1]; __u16 iflags = 0; __u16 oflags = 0; unsigned int ikey = 0; unsigned int okey = 0; unsigned int saddr = 0; unsigned int daddr = 0; unsigned int link = 0; __u8 pmtudisc = 1; __u8 ttl = 0; __u8 tos = 0; int len; __u16 encaptype = 0; __u16 encapflags = 0; __u16 encapsport = 0; __u16 encapdport = 0; __u8 metadata = 0; __u8 ignore_df = 0; __u32 fwmark = 0; __u32 erspan_idx = 0; __u8 keepalive_ret = 0; __u32 keepalive_interv = 0; if (!(n->nlmsg_flags & NLM_F_CREATE)) { if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) { get_failed: fprintf(stderr, "Failed to get existing tunnel info.\n"); return -1; } len = req.n.nlmsg_len; len -= NLMSG_LENGTH(sizeof(*ifi)); if (len < 0) goto get_failed; parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len); if (!tb[IFLA_LINKINFO]) goto get_failed; parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]); if (!linkinfo[IFLA_INFO_DATA]) goto get_failed; parse_rtattr_nested(greinfo, IFLA_GRE_MAX, linkinfo[IFLA_INFO_DATA]); if (greinfo[IFLA_GRE_IKEY]) ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]); if (greinfo[IFLA_GRE_OKEY]) okey = rta_getattr_u32(greinfo[IFLA_GRE_OKEY]); if (greinfo[IFLA_GRE_IFLAGS]) iflags = rta_getattr_u16(greinfo[IFLA_GRE_IFLAGS]); if (greinfo[IFLA_GRE_OFLAGS]) oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]); if (greinfo[IFLA_GRE_LOCAL]) saddr = rta_getattr_u32(greinfo[IFLA_GRE_LOCAL]); if (greinfo[IFLA_GRE_REMOTE]) daddr = rta_getattr_u32(greinfo[IFLA_GRE_REMOTE]); if (greinfo[IFLA_GRE_PMTUDISC]) pmtudisc = rta_getattr_u8( greinfo[IFLA_GRE_PMTUDISC]); if (greinfo[IFLA_GRE_TTL]) ttl = rta_getattr_u8(greinfo[IFLA_GRE_TTL]); if (greinfo[IFLA_GRE_TOS]) tos = rta_getattr_u8(greinfo[IFLA_GRE_TOS]); if (greinfo[IFLA_GRE_LINK]) link = rta_getattr_u8(greinfo[IFLA_GRE_LINK]); if (greinfo[IFLA_GRE_ENCAP_TYPE]) encaptype = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_TYPE]); if (greinfo[IFLA_GRE_ENCAP_FLAGS]) encapflags = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_FLAGS]); if (greinfo[IFLA_GRE_ENCAP_SPORT]) encapsport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_SPORT]); if (greinfo[IFLA_GRE_ENCAP_DPORT]) encapdport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_DPORT]); if (greinfo[IFLA_GRE_COLLECT_METADATA]) metadata = 1; if (greinfo[IFLA_GRE_IGNORE_DF]) ignore_df = !!rta_getattr_u8(greinfo[IFLA_GRE_IGNORE_DF]); if (greinfo[IFLA_GRE_FWMARK]) fwmark = rta_getattr_u32(greinfo[IFLA_GRE_FWMARK]); if (greinfo[IFLA_GRE_ERSPAN_INDEX]) erspan_idx = rta_getattr_u32(greinfo[IFLA_GRE_ERSPAN_INDEX]); } while (argc > 0) { if (!matches(*argv, "key")) { unsigned int uval; NEXT_ARG(); iflags |= GRE_KEY; oflags |= GRE_KEY; if (strchr(*argv, '.')) uval = get_addr32(*argv); else { if (get_unsigned(&uval, *argv, 0) < 0) { fprintf(stderr, "Invalid value for \"key\": \"%s\"; it should be an unsigned integer\n", *argv); exit(-1); } uval = htonl(uval); } ikey = okey = uval; } else if (!matches(*argv, "ikey")) { unsigned int uval; NEXT_ARG(); iflags |= GRE_KEY; if (strchr(*argv, '.')) uval = get_addr32(*argv); else { if (get_unsigned(&uval, *argv, 0) < 0) { fprintf(stderr, "invalid value for \"ikey\": \"%s\"; it should be an unsigned integer\n", *argv); exit(-1); } uval = htonl(uval); } ikey = uval; } else if (!matches(*argv, "okey")) { unsigned int uval; NEXT_ARG(); oflags |= GRE_KEY; if (strchr(*argv, '.')) uval = get_addr32(*argv); else { if (get_unsigned(&uval, *argv, 0) < 0) { fprintf(stderr, "invalid value for \"okey\": \"%s\"; it should be an unsigned integer\n", *argv); exit(-1); } uval = htonl(uval); } okey = uval; } else if (!matches(*argv, "seq")) { iflags |= GRE_SEQ; oflags |= GRE_SEQ; } else if (!matches(*argv, "iseq")) { iflags |= GRE_SEQ; } else if (!matches(*argv, "oseq")) { oflags |= GRE_SEQ; } else if (!matches(*argv, "csum")) { iflags |= GRE_CSUM; oflags |= GRE_CSUM; } else if (!matches(*argv, "icsum")) { iflags |= GRE_CSUM; } else if (!matches(*argv, "ocsum")) { oflags |= GRE_CSUM; } else if (!matches(*argv, "nopmtudisc")) { pmtudisc = 0; } else if (!matches(*argv, "pmtudisc")) { pmtudisc = 1; } else if (!matches(*argv, "remote")) { NEXT_ARG(); if (strcmp(*argv, "any")) daddr = get_addr32(*argv); } else if (!matches(*argv, "local")) { NEXT_ARG(); if (strcmp(*argv, "any")) saddr = get_addr32(*argv); } else if (!matches(*argv, "dev")) { NEXT_ARG(); link = if_nametoindex(*argv); if (link == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", *argv); exit(-1); } } else if (!matches(*argv, "ttl") || !matches(*argv, "hoplimit")) { unsigned int uval; NEXT_ARG(); if (strcmp(*argv, "inherit") != 0) { if (get_unsigned(&uval, *argv, 0)) invarg("invalid TTL\n", *argv); if (uval > 255) invarg("TTL must be <= 255\n", *argv); ttl = uval; } } else if (!matches(*argv, "tos") || !matches(*argv, "tclass") || !matches(*argv, "dsfield")) { __u32 uval; NEXT_ARG(); if (strcmp(*argv, "inherit") != 0) { if (rtnl_dsfield_a2n(&uval, *argv)) invarg("bad TOS value", *argv); tos = uval; } else tos = 1; } else if (strcmp(*argv, "noencap") == 0) { encaptype = TUNNEL_ENCAP_NONE; } else if (strcmp(*argv, "encap") == 0) { NEXT_ARG(); if (strcmp(*argv, "fou") == 0) encaptype = TUNNEL_ENCAP_FOU; else if (strcmp(*argv, "gue") == 0) encaptype = TUNNEL_ENCAP_GUE; else if (strcmp(*argv, "none") == 0) encaptype = TUNNEL_ENCAP_NONE; else invarg("Invalid encap type.", *argv); } else if (strcmp(*argv, "encap-sport") == 0) { NEXT_ARG(); if (strcmp(*argv, "auto") == 0) encapsport = 0; else if (get_u16(&encapsport, *argv, 0)) invarg("Invalid source port.", *argv); } else if (strcmp(*argv, "encap-dport") == 0) { NEXT_ARG(); if (get_u16(&encapdport, *argv, 0)) invarg("Invalid destination port.", *argv); } else if (strcmp(*argv, "encap-csum") == 0) { encapflags |= TUNNEL_ENCAP_FLAG_CSUM; } else if (strcmp(*argv, "noencap-csum") == 0) { encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM; } else if (strcmp(*argv, "encap-udp6-csum") == 0) { encapflags |= TUNNEL_ENCAP_FLAG_CSUM6; } else if (strcmp(*argv, "noencap-udp6-csum") == 0) { encapflags |= ~TUNNEL_ENCAP_FLAG_CSUM6; } else if (strcmp(*argv, "encap-remcsum") == 0) { encapflags |= TUNNEL_ENCAP_FLAG_REMCSUM; } else if (strcmp(*argv, "noencap-remcsum") == 0) { encapflags |= ~TUNNEL_ENCAP_FLAG_REMCSUM; } else if (strcmp(*argv, "external") == 0) { metadata = 1; } else if (strcmp(*argv, "ignore-df") == 0) { ignore_df = 1; } else if (strcmp(*argv, "noignore-df") == 0) { /* *only the lsb is significant, use 2 for presence */ ignore_df = 2; } else if (strcmp(*argv, "fwmark") == 0) { NEXT_ARG(); if (get_u32(&fwmark, *argv, 0)) invarg("invalid fwmark\n", *argv); } else if (strcmp(*argv, "erspan") == 0) { NEXT_ARG(); if (get_u32(&erspan_idx, *argv, 0)) invarg("invalid erspan index\n", *argv); if (erspan_idx & ~((1<<20) - 1) || erspan_idx == 0) invarg("erspan index must be > 0 and <= 20-bit\n", *argv); } else if (!matches(*argv, "keepalive")) { __u64 interv; __u32 ret; NEXT_ARG(); if (strcmp(*argv, "auto") != 0) { if (get_u32(&interv, *argv, 0)) invarg("invalid KeepAlive time interval\n", *argv); keepalive_interv = interv; } NEXT_ARG(); if (strcmp(*argv, "auto") != 0) { if (get_unsigned(&ret, *argv, 0)) invarg("invalid KeepAlive retries\n", *argv); if (ret > 255) invarg("KeepAlive retries must be <= 255\n", *argv); keepalive_ret = ret; } } else usage(); argc--; argv++; } if (!ikey && IN_MULTICAST(ntohl(daddr))) { ikey = daddr; iflags |= GRE_KEY; } if (!okey && IN_MULTICAST(ntohl(daddr))) { okey = daddr; oflags |= GRE_KEY; } if (IN_MULTICAST(ntohl(daddr)) && !saddr) { fprintf(stderr, "A broadcast tunnel requires a source address.\n"); return -1; } if (!metadata) { addattr32(n, 1024, IFLA_GRE_IKEY, ikey); addattr32(n, 1024, IFLA_GRE_OKEY, okey); addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2); addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2); addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4); addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4); addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1); if (link) addattr32(n, 1024, IFLA_GRE_LINK, link); addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1); addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1); addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark); if (erspan_idx != 0) addattr32(n, 1024, IFLA_GRE_ERSPAN_INDEX, erspan_idx); if (keepalive_interv) { addattr32(n, 1024, IFLA_GRE_KEEPALIVE_INTERVAL, keepalive_interv); addattr8(n, 1024, IFLA_GRE_KEEPALIVE_RETRIES, keepalive_ret); } } else { addattr_l(n, 1024, IFLA_GRE_COLLECT_METADATA, NULL, 0); } addattr16(n, 1024, IFLA_GRE_ENCAP_TYPE, encaptype); addattr16(n, 1024, IFLA_GRE_ENCAP_FLAGS, encapflags); addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport)); addattr16(n, 1024, IFLA_GRE_ENCAP_DPORT, htons(encapdport)); if (ignore_df) addattr8(n, 1024, IFLA_GRE_IGNORE_DF, ignore_df & 1); return 0; } static void gre_print_direct_opt(FILE *f, struct rtattr *tb[]) { char s2[64]; const char *local = "any"; const char *remote = "any"; unsigned int iflags = 0; unsigned int oflags = 0; if (tb[IFLA_GRE_REMOTE]) { unsigned int addr = rta_getattr_u32(tb[IFLA_GRE_REMOTE]); if (addr) remote = format_host(AF_INET, 4, &addr); } print_string(PRINT_ANY, "remote", "remote %s ", remote); if (tb[IFLA_GRE_LOCAL]) { unsigned int addr = rta_getattr_u32(tb[IFLA_GRE_LOCAL]); if (addr) local = format_host(AF_INET, 4, &addr); } print_string(PRINT_ANY, "local", "local %s ", local); if (tb[IFLA_GRE_LINK] && rta_getattr_u32(tb[IFLA_GRE_LINK])) { unsigned int link = rta_getattr_u32(tb[IFLA_GRE_LINK]); const char *n = if_indextoname(link, s2); if (n) print_string(PRINT_ANY, "link", "dev %s ", n); else print_uint(PRINT_ANY, "link_index", "dev %u ", link); } if (tb[IFLA_GRE_TTL]) { __u8 ttl = rta_getattr_u8(tb[IFLA_GRE_TTL]); if (ttl) print_int(PRINT_ANY, "ttl", "ttl %d ", ttl); else print_int(PRINT_JSON, "ttl", NULL, ttl); } else { print_string(PRINT_FP, NULL, "ttl %s ", "inherit"); } if (tb[IFLA_GRE_TOS] && rta_getattr_u8(tb[IFLA_GRE_TOS])) { int tos = rta_getattr_u8(tb[IFLA_GRE_TOS]); if (is_json_context()) { SPRINT_BUF(b1); snprintf(b1, sizeof(b1), "0x%x", tos); print_string(PRINT_JSON, "tos", NULL, b1); } else { fputs("tos ", f); if (tos == 1) fputs("inherit ", f); else fprintf(f, "0x%x ", tos); } } if (tb[IFLA_GRE_KEEPALIVE_INTERVAL]) { unsigned long interval; unsigned int retries; interval = rta_getattr_u64(tb[IFLA_GRE_KEEPALIVE_INTERVAL]); retries = rta_getattr_u8(tb[IFLA_GRE_KEEPALIVE_RETRIES]); if (interval) { print_int(PRINT_ANY, "keepalive", "keepalive interval %d ", interval); print_int(PRINT_ANY, "keepalive", "retries %d ", retries); } else { print_int(PRINT_JSON, "keepalive", NULL, interval); } } else { print_string(PRINT_FP, NULL, "keepalive %s ", "auto"); } if (tb[IFLA_GRE_PMTUDISC]) { if (!rta_getattr_u8(tb[IFLA_GRE_PMTUDISC])) print_bool(PRINT_ANY, "pmtudisc", "nopmtudisc ", false); else print_bool(PRINT_JSON, "pmtudisc", NULL, true); } if (tb[IFLA_GRE_IFLAGS]) iflags = rta_getattr_u16(tb[IFLA_GRE_IFLAGS]); if (tb[IFLA_GRE_OFLAGS]) oflags = rta_getattr_u16(tb[IFLA_GRE_OFLAGS]); if ((iflags & GRE_KEY) && tb[IFLA_GRE_IKEY]) { inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2)); print_string(PRINT_ANY, "ikey", "ikey %s ", s2); } if ((oflags & GRE_KEY) && tb[IFLA_GRE_OKEY]) { inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2)); print_string(PRINT_ANY, "okey", "okey %s ", s2); } if (iflags & GRE_SEQ) print_bool(PRINT_ANY, "iseq", "iseq ", true); if (oflags & GRE_SEQ) print_bool(PRINT_ANY, "oseq", "oseq ", true); if (iflags & GRE_CSUM) print_bool(PRINT_ANY, "icsum", "icsum ", true); if (oflags & GRE_CSUM) print_bool(PRINT_ANY, "ocsum", "ocsum ", true); if (tb[IFLA_GRE_FWMARK]) { __u32 fwmark = rta_getattr_u32(tb[IFLA_GRE_FWMARK]); if (fwmark) { snprintf(s2, sizeof(s2), "0x%x", fwmark); print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2); } } }
static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) { if (!tb) return; if (!tb[IFLA_GRE_COLLECT_METADATA]) gre_print_direct_opt(f, tb); else print_bool(PRINT_ANY, "external", "external ", true); if (tb[IFLA_GRE_IGNORE_DF] && rta_getattr_u8(tb[IFLA_GRE_IGNORE_DF])) print_bool(PRINT_ANY, "ignore_df", "ignore-df ", true); if (tb[IFLA_GRE_ERSPAN_INDEX]) { __u32 erspan_idx = rta_getattr_u32(tb[IFLA_GRE_ERSPAN_INDEX]); fprintf(f, "erspan_index %u ", erspan_idx); } if (tb[IFLA_GRE_ENCAP_TYPE] && rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) { __u16 type = rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]); __u16 flags = rta_getattr_u16(tb[IFLA_GRE_ENCAP_FLAGS]); __u16 sport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_SPORT]); __u16 dport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_DPORT]); open_json_object("encap"); print_string(PRINT_FP, NULL, "encap ", NULL); switch (type) { case TUNNEL_ENCAP_FOU: print_string(PRINT_ANY, "type", "%s ", "fou"); break; case TUNNEL_ENCAP_GUE: print_string(PRINT_ANY, "type", "%s ", "gue"); break; default: print_null(PRINT_ANY, "type", "%s ", "unknown"); break; } if (is_json_context()) { print_uint(PRINT_JSON, "sport", NULL, sport ? ntohs(sport) : 0); print_uint(PRINT_JSON, "dport", NULL, ntohs(dport)); print_bool(PRINT_JSON, "csum", NULL, flags & TUNNEL_ENCAP_FLAG_CSUM); print_bool(PRINT_JSON, "csum6", NULL, flags & TUNNEL_ENCAP_FLAG_CSUM6); print_bool(PRINT_JSON, "remcsum", NULL, flags & TUNNEL_ENCAP_FLAG_REMCSUM); close_json_object(); } else { if (sport == 0) fputs("encap-sport auto ", f); else fprintf(f, "encap-sport %u", ntohs(sport)); fprintf(f, "encap-dport %u ", ntohs(dport)); if (flags & TUNNEL_ENCAP_FLAG_CSUM) fputs("encap-csum ", f); else fputs("noencap-csum ", f); if (flags & TUNNEL_ENCAP_FLAG_CSUM6) fputs("encap-csum6 ", f); else fputs("noencap-csum6 ", f); if (flags & TUNNEL_ENCAP_FLAG_REMCSUM) fputs("encap-remcsum ", f); else fputs("noencap-remcsum ", f); } } }