int inet_addr_match_rta(const inet_prefix *m, const struct rtattr *rta) { inet_prefix dst; if (!rta || m->family == AF_UNSPEC || m->bitlen <= 0) return 0; if (get_addr_rta(&dst, rta, m->family)) return -1; return inet_addr_match(&dst, m, m->bitlen); }
static int vti6_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { struct ifinfomsg *ifi = NLMSG_DATA(n); 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 *vtiinfo[IFLA_VTI_MAX + 1]; __be32 ikey = 0; __be32 okey = 0; inet_prefix saddr, daddr; unsigned int link = 0; __u32 fwmark = 0; int len; inet_prefix_reset(&saddr); inet_prefix_reset(&daddr); if (!(n->nlmsg_flags & NLM_F_CREATE)) { const struct rtattr *rta; 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(vtiinfo, IFLA_VTI_MAX, linkinfo[IFLA_INFO_DATA]); rta = vtiinfo[IFLA_VTI_LOCAL]; if (rta && get_addr_rta(&saddr, rta, AF_INET6)) goto get_failed; rta = vtiinfo[IFLA_VTI_REMOTE]; if (rta && get_addr_rta(&daddr, rta, AF_INET6)) goto get_failed; if (vtiinfo[IFLA_VTI_IKEY]) ikey = rta_getattr_u32(vtiinfo[IFLA_VTI_IKEY]); if (vtiinfo[IFLA_VTI_OKEY]) okey = rta_getattr_u32(vtiinfo[IFLA_VTI_OKEY]); if (vtiinfo[IFLA_VTI_LINK]) link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]); if (vtiinfo[IFLA_VTI_FWMARK]) fwmark = rta_getattr_u32(vtiinfo[IFLA_VTI_FWMARK]); free(answer); } while (argc > 0) { if (!matches(*argv, "key")) { NEXT_ARG(); ikey = okey = tnl_parse_key("key", *argv); } else if (!matches(*argv, "ikey")) { NEXT_ARG(); ikey = tnl_parse_key("ikey", *argv); } else if (!matches(*argv, "okey")) { NEXT_ARG(); okey = tnl_parse_key("okey", *argv); } else if (!matches(*argv, "remote")) { NEXT_ARG(); get_addr(&daddr, *argv, AF_INET6); } else if (!matches(*argv, "local")) { NEXT_ARG(); get_addr(&saddr, *argv, AF_INET6); } else if (!matches(*argv, "dev")) { NEXT_ARG(); link = ll_name_to_index(*argv); if (!link) exit(nodev(*argv)); } else if (strcmp(*argv, "fwmark") == 0) { NEXT_ARG(); if (get_u32(&fwmark, *argv, 0)) invarg("invalid fwmark\n", *argv); } else { vti6_print_help(lu, argc, argv, stderr); return -1; } argc--; argv++; } addattr32(n, 1024, IFLA_VTI_IKEY, ikey); addattr32(n, 1024, IFLA_VTI_OKEY, okey); if (is_addrtype_inet_not_unspec(&saddr)) addattr_l(n, 1024, IFLA_VTI_LOCAL, saddr.data, saddr.bytelen); if (is_addrtype_inet_not_unspec(&daddr)) addattr_l(n, 1024, IFLA_VTI_REMOTE, daddr.data, daddr.bytelen); addattr32(n, 1024, IFLA_VTI_FWMARK, fwmark); if (link) addattr32(n, 1024, IFLA_VTI_LINK, link); return 0; } static void vti6_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) { char s2[64]; if (!tb) return; tnl_print_endpoint("remote", tb[IFLA_VTI_REMOTE], AF_INET6); tnl_print_endpoint("local", tb[IFLA_VTI_LOCAL], AF_INET6); if (tb[IFLA_VTI_LINK]) { __u32 link = rta_getattr_u32(tb[IFLA_VTI_LINK]); if (link) { print_string(PRINT_ANY, "link", "dev %s ", ll_index_to_name(link)); } } if (tb[IFLA_VTI_IKEY]) { struct rtattr *rta = tb[IFLA_VTI_IKEY]; __u32 key = rta_getattr_u32(rta); if (key && inet_ntop(AF_INET, RTA_DATA(rta), s2, sizeof(s2))) print_string(PRINT_ANY, "ikey", "ikey %s ", s2); } if (tb[IFLA_VTI_OKEY]) { struct rtattr *rta = tb[IFLA_VTI_OKEY]; __u32 key = rta_getattr_u32(rta); if (key && inet_ntop(AF_INET, RTA_DATA(rta), s2, sizeof(s2))) print_string(PRINT_ANY, "okey", "okey %s ", s2); } if (tb[IFLA_VTI_FWMARK]) { __u32 fwmark = rta_getattr_u32(tb[IFLA_VTI_FWMARK]); if (fwmark) { print_0xhex(PRINT_ANY, "fwmark", "fwmark %#llx ", fwmark); } } }