From 9cc173d4855a279631f91736d83a6005dd4ee5f3 Mon Sep 17 00:00:00 2001 From: Serhey Popovych Date: Mon, 12 Feb 2018 22:17:56 +0200 Subject: [PATCH 1/4] utils: Introduce and use inet_prefix_reset() Initializing @inet_prefix using C initializers or memset() seems inefficient and unnecessary: only small part of ->data[] field will be used to store address corresponding to ->family. Instead initialize ->flags with zero and assume no other fields accessed before checking corresponding bits in ->flags. For example special helpers (e.g. is_addrtype_*()) can be used to ensure that @inet_prefix contains valid ip or ipv6 address. Signed-off-by: Serhey Popovych Signed-off-by: David Ahern --- include/utils.h | 5 +++++ ip/iplink_geneve.c | 2 +- ip/iplink_vxlan.c | 7 ++++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/include/utils.h b/include/utils.h index 4dc514d6..867e5404 100644 --- a/include/utils.h +++ b/include/utils.h @@ -65,6 +65,11 @@ enum { ADDRTYPE_INET_MULTI = ADDRTYPE_INET | ADDRTYPE_MULTI }; +static inline void inet_prefix_reset(inet_prefix *p) +{ + p->flags = 0; +} + static inline bool is_addrtype_inet(const inet_prefix *p) { return p->flags & ADDRTYPE_INET; diff --git a/ip/iplink_geneve.c b/ip/iplink_geneve.c index c6660726..1fcdd83a 100644 --- a/ip/iplink_geneve.c +++ b/ip/iplink_geneve.c @@ -71,7 +71,7 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, bool set_op = (n->nlmsg_type == RTM_NEWLINK && !(n->nlmsg_flags & NLM_F_CREATE)); - daddr.flags = 0; + inet_prefix_reset(&daddr); while (argc > 0) { if (!matches(*argv, "id") || diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c index 00875ba7..d768c07e 100644 --- a/ip/iplink_vxlan.c +++ b/ip/iplink_vxlan.c @@ -74,8 +74,7 @@ static void check_duparg(__u64 *attrs, int type, const char *key, static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { - inet_prefix saddr; - inet_prefix daddr; + inet_prefix saddr, daddr; __u32 vni = 0; __u8 learning = 1; __u16 dstport = 0; @@ -85,7 +84,9 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, !(n->nlmsg_flags & NLM_F_CREATE)); saddr.family = daddr.family = AF_UNSPEC; - saddr.flags = daddr.flags = 0; + + inet_prefix_reset(&saddr); + inet_prefix_reset(&daddr); while (argc > 0) { if (!matches(*argv, "id") || From 3d4e0db65ccd5de32b0ff1354fca7dc92842f353 Mon Sep 17 00:00:00 2001 From: Serhey Popovych Date: Mon, 12 Feb 2018 22:17:57 +0200 Subject: [PATCH 2/4] vti/vti6: Unify local/remote endpoint address parsing We are going to merge link_vti.c and link_vti6.c and this is final step to make their diffs clear and show what needs to be changed during merge. Note that it is safe to omit endpoint address(es) from netlink create request as kernel is aware of such case and will use zero for that endpoint(s). Signed-off-by: Serhey Popovych Signed-off-by: David Ahern --- ip/link_vti.c | 32 ++++++++++++++++++++------------ ip/link_vti6.c | 38 ++++++++++++++++++++------------------ 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/ip/link_vti.c b/ip/link_vti.c index edd17fe2..99e10e8a 100644 --- a/ip/link_vti.c +++ b/ip/link_vti.c @@ -64,13 +64,17 @@ static int vti_parse_opt(struct link_util *lu, int argc, char **argv, struct rtattr *vtiinfo[IFLA_VTI_MAX + 1]; __be32 ikey = 0; __be32 okey = 0; - unsigned int saddr = 0; - unsigned int daddr = 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, @@ -96,18 +100,20 @@ 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_INET)) + goto get_failed; + + rta = vtiinfo[IFLA_VTI_REMOTE]; + if (rta && get_addr_rta(&daddr, rta, AF_INET)) + 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_LOCAL]) - saddr = rta_getattr_u32(vtiinfo[IFLA_VTI_LOCAL]); - - if (vtiinfo[IFLA_VTI_REMOTE]) - daddr = rta_getattr_u32(vtiinfo[IFLA_VTI_REMOTE]); - if (vtiinfo[IFLA_VTI_LINK]) link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]); @@ -129,10 +135,10 @@ get_failed: okey = tnl_parse_key("okey", *argv); } else if (!matches(*argv, "remote")) { NEXT_ARG(); - daddr = get_addr32(*argv); + get_addr(&daddr, *argv, AF_INET); } else if (!matches(*argv, "local")) { NEXT_ARG(); - saddr = get_addr32(*argv); + get_addr(&saddr, *argv, AF_INET); } else if (!matches(*argv, "dev")) { NEXT_ARG(); link = ll_name_to_index(*argv); @@ -154,8 +160,10 @@ get_failed: addattr32(n, 1024, IFLA_VTI_IKEY, ikey); addattr32(n, 1024, IFLA_VTI_OKEY, okey); - addattr_l(n, 1024, IFLA_VTI_LOCAL, &saddr, 4); - addattr_l(n, 1024, IFLA_VTI_REMOTE, &daddr, 4); + if (is_addrtype_inet(&saddr)) + addattr_l(n, 1024, IFLA_VTI_LOCAL, saddr.data, saddr.bytelen); + if (is_addrtype_inet(&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); diff --git a/ip/link_vti6.c b/ip/link_vti6.c index 1276ebd0..1df6579b 100644 --- a/ip/link_vti6.c +++ b/ip/link_vti6.c @@ -64,15 +64,19 @@ static int vti6_parse_opt(struct link_util *lu, int argc, char **argv, struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct rtattr *vtiinfo[IFLA_VTI_MAX + 1]; - struct in6_addr saddr = IN6ADDR_ANY_INIT; - struct in6_addr daddr = IN6ADDR_ANY_INIT; __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, @@ -98,18 +102,20 @@ 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_LOCAL]) - memcpy(&saddr, RTA_DATA(vtiinfo[IFLA_VTI_LOCAL]), sizeof(saddr)); - - if (vtiinfo[IFLA_VTI_REMOTE]) - memcpy(&daddr, RTA_DATA(vtiinfo[IFLA_VTI_REMOTE]), sizeof(daddr)); - if (vtiinfo[IFLA_VTI_LINK]) link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]); @@ -130,17 +136,11 @@ get_failed: NEXT_ARG(); okey = tnl_parse_key("okey", *argv); } else if (!matches(*argv, "remote")) { - inet_prefix addr; - NEXT_ARG(); - get_addr(&addr, *argv, AF_INET6); - memcpy(&daddr, addr.data, sizeof(daddr)); + get_addr(&daddr, *argv, AF_INET6); } else if (!matches(*argv, "local")) { - inet_prefix addr; - NEXT_ARG(); - get_addr(&addr, *argv, AF_INET6); - memcpy(&saddr, addr.data, sizeof(saddr)); + get_addr(&saddr, *argv, AF_INET6); } else if (!matches(*argv, "dev")) { NEXT_ARG(); link = ll_name_to_index(*argv); @@ -162,8 +162,10 @@ get_failed: addattr32(n, 1024, IFLA_VTI_IKEY, ikey); addattr32(n, 1024, IFLA_VTI_OKEY, okey); - addattr_l(n, 1024, IFLA_VTI_LOCAL, &saddr, sizeof(saddr)); - addattr_l(n, 1024, IFLA_VTI_REMOTE, &daddr, sizeof(daddr)); + if (is_addrtype_inet(&saddr)) + addattr_l(n, 1024, IFLA_VTI_LOCAL, saddr.data, saddr.bytelen); + if (is_addrtype_inet(&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); From a066cc6623e1e93fec38f10299d4cad4526471b2 Mon Sep 17 00:00:00 2001 From: Serhey Popovych Date: Mon, 12 Feb 2018 22:17:58 +0200 Subject: [PATCH 3/4] gre/gre6: Unify local/remote endpoint address parsing We are going to merge link_gre.c and link_gre6.c and this is final step to make their diffs clear and show what needs to be changed during merge. Note that it is safe to omit endpoint address(es) from netlink create request as kernel is aware of such case and will use zero for that endpoint(s). Signed-off-by: Serhey Popovych Signed-off-by: David Ahern --- ip/link_gre.c | 57 ++++++++++++++++++++++++++++++-------------------- ip/link_gre6.c | 38 +++++++++++++++++---------------- 2 files changed, 54 insertions(+), 41 deletions(-) diff --git a/ip/link_gre.c b/ip/link_gre.c index e3e53239..64588d75 100644 --- a/ip/link_gre.c +++ b/ip/link_gre.c @@ -86,8 +86,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, __u16 oflags = 0; __be32 ikey = 0; __be32 okey = 0; - unsigned int saddr = 0; - unsigned int daddr = 0; + inet_prefix saddr, daddr; __u8 pmtudisc = 1; __u8 ignore_df = 0; __u8 tos = 0; @@ -104,7 +103,12 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, __u8 erspan_dir = 0; __u16 erspan_hwid = 0; + 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, @@ -130,6 +134,14 @@ get_failed: parse_rtattr_nested(greinfo, IFLA_GRE_MAX, linkinfo[IFLA_INFO_DATA]); + rta = greinfo[IFLA_GRE_LOCAL]; + if (rta && get_addr_rta(&saddr, rta, AF_INET)) + goto get_failed; + + rta = greinfo[IFLA_GRE_REMOTE]; + if (rta && get_addr_rta(&daddr, rta, AF_INET)) + goto get_failed; + if (greinfo[IFLA_GRE_IKEY]) ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]); @@ -142,12 +154,6 @@ get_failed: 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]); @@ -232,10 +238,10 @@ get_failed: pmtudisc = 1; } else if (!matches(*argv, "remote")) { NEXT_ARG(); - daddr = get_addr32(*argv); + get_addr(&daddr, *argv, AF_INET); } else if (!matches(*argv, "local")) { NEXT_ARG(); - saddr = get_addr32(*argv); + get_addr(&saddr, *argv, AF_INET); } else if (!matches(*argv, "dev")) { NEXT_ARG(); link = ll_name_to_index(*argv); @@ -343,17 +349,20 @@ get_failed: 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 (is_addrtype_inet_multi(&daddr)) { + if (!ikey) { + ikey = daddr.data[0]; + iflags |= GRE_KEY; + } + if (!okey) { + okey = daddr.data[0]; + oflags |= GRE_KEY; + } + if (!is_addrtype_inet_not_unspec(&saddr)) { + fprintf(stderr, + "A broadcast tunnel requires a source address.\n"); + return -1; + } } if (metadata) { @@ -365,8 +374,10 @@ get_failed: 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); + if (is_addrtype_inet(&saddr)) + addattr_l(n, 1024, IFLA_GRE_LOCAL, saddr.data, saddr.bytelen); + if (is_addrtype_inet(&daddr)) + addattr_l(n, 1024, IFLA_GRE_REMOTE, daddr.data, daddr.bytelen); addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1); if (ignore_df) addattr8(n, 1024, IFLA_GRE_IGNORE_DF, ignore_df & 1); diff --git a/ip/link_gre6.c b/ip/link_gre6.c index 251ae0e3..6c77038a 100644 --- a/ip/link_gre6.c +++ b/ip/link_gre6.c @@ -97,8 +97,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, __u16 oflags = 0; __be32 ikey = 0; __be32 okey = 0; - struct in6_addr raddr = IN6ADDR_ANY_INIT; - struct in6_addr laddr = IN6ADDR_ANY_INIT; + inet_prefix saddr, daddr; __u8 hop_limit = DEFAULT_TNL_HOP_LIMIT; __u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT; __u32 flowinfo = 0; @@ -115,7 +114,12 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, __u8 erspan_dir = 0; __u16 erspan_hwid = 0; + 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, @@ -141,6 +145,14 @@ get_failed: parse_rtattr_nested(greinfo, IFLA_GRE_MAX, linkinfo[IFLA_INFO_DATA]); + rta = greinfo[IFLA_GRE_LOCAL]; + if (rta && get_addr_rta(&saddr, rta, AF_INET6)) + goto get_failed; + + rta = greinfo[IFLA_GRE_REMOTE]; + if (rta && get_addr_rta(&daddr, rta, AF_INET6)) + goto get_failed; + if (greinfo[IFLA_GRE_IKEY]) ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]); @@ -153,12 +165,6 @@ get_failed: 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]); @@ -236,17 +242,11 @@ get_failed: } 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)); + get_addr(&daddr, *argv, AF_INET6); } else if (!matches(*argv, "local")) { - inet_prefix addr; - NEXT_ARG(); - get_addr(&addr, *argv, AF_INET6); - memcpy(&laddr, &addr.data, sizeof(laddr)); + get_addr(&saddr, *argv, AF_INET6); } else if (!matches(*argv, "dev")) { NEXT_ARG(); link = ll_name_to_index(*argv); @@ -398,8 +398,10 @@ get_failed: 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 (is_addrtype_inet(&saddr)) + addattr_l(n, 1024, IFLA_GRE_LOCAL, saddr.data, saddr.bytelen); + if (is_addrtype_inet(&daddr)) + addattr_l(n, 1024, IFLA_GRE_REMOTE, daddr.data, daddr.bytelen); if (link) addattr32(n, 1024, IFLA_GRE_LINK, link); addattr_l(n, 1024, IFLA_GRE_TTL, &hop_limit, 1); From 7bda9fd37ab1f16c29e8c486be99ca4568982246 Mon Sep 17 00:00:00 2001 From: Serhey Popovych Date: Mon, 12 Feb 2018 22:17:59 +0200 Subject: [PATCH 4/4] iptnl/ip6tnl: Unify local/remote endpoint and 6rd address parsing We are going to merge link_iptnl.c and link_ip6tnl.c and this is final step to make their diffs clear and show what needs to be changed during merge. Note that it is safe to omit endpoint address(es) from netlink create request as kernel is aware of such case and will use zero for that endpoint(s). Make sure we initialize ip6rdprefix and ip6rdrelayprefix bitlen in link_iptnl.c only when configuring existing tunnel: if kernel does not submit prefixlen in corresponding attributes preceeding get_addr_rta() will set bitlen to -1 which is incorrect value. Signed-off-by: Serhey Popovych Signed-off-by: David Ahern --- ip/link_ip6tnl.c | 40 ++++++++++--------- ip/link_iptnl.c | 101 +++++++++++++++++++++++------------------------ 2 files changed, 72 insertions(+), 69 deletions(-) diff --git a/ip/link_ip6tnl.c b/ip/link_ip6tnl.c index 8a45d42b..77a90900 100644 --- a/ip/link_ip6tnl.c +++ b/ip/link_ip6tnl.c @@ -93,8 +93,7 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1]; int len; - struct in6_addr laddr = IN6ADDR_ANY_INIT; - struct in6_addr raddr = IN6ADDR_ANY_INIT; + inet_prefix saddr, daddr; __u8 hop_limit = DEFAULT_TNL_HOP_LIMIT; __u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT; __u32 flowinfo = 0; @@ -108,7 +107,12 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, __u8 metadata = 0; __u32 fwmark = 0; + 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, @@ -134,13 +138,13 @@ get_failed: parse_rtattr_nested(iptuninfo, IFLA_IPTUN_MAX, linkinfo[IFLA_INFO_DATA]); - if (iptuninfo[IFLA_IPTUN_LOCAL]) - memcpy(&laddr, RTA_DATA(iptuninfo[IFLA_IPTUN_LOCAL]), - sizeof(laddr)); + rta = iptuninfo[IFLA_IPTUN_LOCAL]; + if (rta && get_addr_rta(&saddr, rta, AF_INET6)) + goto get_failed; - if (iptuninfo[IFLA_IPTUN_REMOTE]) - memcpy(&raddr, RTA_DATA(iptuninfo[IFLA_IPTUN_REMOTE]), - sizeof(raddr)); + rta = iptuninfo[IFLA_IPTUN_REMOTE]; + if (rta && get_addr_rta(&daddr, rta, AF_INET6)) + goto get_failed; if (iptuninfo[IFLA_IPTUN_TTL]) hop_limit = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TTL]); @@ -185,17 +189,11 @@ get_failed: else invarg("Cannot guess tunnel mode.", *argv); } else if (strcmp(*argv, "remote") == 0) { - inet_prefix addr; - NEXT_ARG(); - get_addr(&addr, *argv, AF_INET6); - memcpy(&raddr, addr.data, sizeof(raddr)); + get_addr(&daddr, *argv, AF_INET6); } else if (strcmp(*argv, "local") == 0) { - inet_prefix addr; - NEXT_ARG(); - get_addr(&addr, *argv, AF_INET6); - memcpy(&laddr, addr.data, sizeof(laddr)); + get_addr(&saddr, *argv, AF_INET6); } else if (matches(*argv, "dev") == 0) { NEXT_ARG(); link = ll_name_to_index(*argv); @@ -322,8 +320,14 @@ get_failed: return 0; } - addattr_l(n, 1024, IFLA_IPTUN_LOCAL, &laddr, sizeof(laddr)); - addattr_l(n, 1024, IFLA_IPTUN_REMOTE, &raddr, sizeof(raddr)); + if (is_addrtype_inet(&saddr)) { + addattr_l(n, 1024, IFLA_IPTUN_LOCAL, + saddr.data, saddr.bytelen); + } + if (is_addrtype_inet(&daddr)) { + addattr_l(n, 1024, IFLA_IPTUN_REMOTE, + daddr.data, daddr.bytelen); + } addattr8(n, 1024, IFLA_IPTUN_TTL, hop_limit); addattr8(n, 1024, IFLA_IPTUN_ENCAP_LIMIT, encap_limit); addattr32(n, 1024, IFLA_IPTUN_FLOWINFO, flowinfo); diff --git a/ip/link_iptnl.c b/ip/link_iptnl.c index bc1074e9..acd9f45b 100644 --- a/ip/link_iptnl.c +++ b/ip/link_iptnl.c @@ -90,16 +90,11 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1]; int len; - __u32 laddr = 0; - __u32 raddr = 0; + inet_prefix saddr, daddr, ip6rdprefix, ip6rdrelayprefix; __u8 pmtudisc = 1; __u8 tos = 0; __u16 iflags = 0; __u8 ttl = 0; - struct in6_addr ip6rdprefix = {}; - __u16 ip6rdprefixlen = 0; - __u32 ip6rdrelayprefix = 0; - __u16 ip6rdrelayprefixlen = 0; __u8 proto = 0; __u32 link = 0; __u16 encaptype = 0; @@ -109,7 +104,15 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, __u8 metadata = 0; __u32 fwmark = 0; + inet_prefix_reset(&saddr); + inet_prefix_reset(&daddr); + + inet_prefix_reset(&ip6rdprefix); + inet_prefix_reset(&ip6rdrelayprefix); + if (!(n->nlmsg_flags & NLM_F_CREATE)) { + const struct rtattr *rta; + if (rtnl_talk(&rth, &req.n, &answer) < 0) { get_failed: fprintf(stderr, @@ -135,11 +138,27 @@ get_failed: parse_rtattr_nested(iptuninfo, IFLA_IPTUN_MAX, linkinfo[IFLA_INFO_DATA]); - if (iptuninfo[IFLA_IPTUN_LOCAL]) - laddr = rta_getattr_u32(iptuninfo[IFLA_IPTUN_LOCAL]); + rta = iptuninfo[IFLA_IPTUN_LOCAL]; + if (rta && get_addr_rta(&saddr, rta, AF_INET)) + goto get_failed; - if (iptuninfo[IFLA_IPTUN_REMOTE]) - raddr = rta_getattr_u32(iptuninfo[IFLA_IPTUN_REMOTE]); + rta = iptuninfo[IFLA_IPTUN_REMOTE]; + if (rta && get_addr_rta(&daddr, rta, AF_INET)) + goto get_failed; + + rta = iptuninfo[IFLA_IPTUN_6RD_PREFIX]; + if (rta && get_addr_rta(&ip6rdprefix, rta, AF_INET6)) + goto get_failed; + + rta = iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX]; + if (rta && get_addr_rta(&ip6rdrelayprefix, rta, AF_INET)) + goto get_failed; + + rta = iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN]; + ip6rdprefix.bitlen = rta ? rta_getattr_u16(rta) : 0; + + rta = iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]; + ip6rdrelayprefix.bitlen = rta ? rta_getattr_u16(rta) : 0; if (iptuninfo[IFLA_IPTUN_TTL]) ttl = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TTL]); @@ -168,22 +187,7 @@ get_failed: encapsport = rta_getattr_u16(iptuninfo[IFLA_IPTUN_ENCAP_SPORT]); if (iptuninfo[IFLA_IPTUN_ENCAP_DPORT]) encapdport = rta_getattr_u16(iptuninfo[IFLA_IPTUN_ENCAP_DPORT]); - if (iptuninfo[IFLA_IPTUN_6RD_PREFIX]) - memcpy(&ip6rdprefix, - RTA_DATA(iptuninfo[IFLA_IPTUN_6RD_PREFIX]), - sizeof(laddr)); - if (iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN]) - ip6rdprefixlen = - rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN]); - - if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX]) - ip6rdrelayprefix = - rta_getattr_u32(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX]); - - if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]) - ip6rdrelayprefixlen = - rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]); if (iptuninfo[IFLA_IPTUN_COLLECT_METADATA]) metadata = 1; @@ -214,10 +218,10 @@ get_failed: invarg("Cannot guess tunnel mode.", *argv); } else if (strcmp(*argv, "remote") == 0) { NEXT_ARG(); - raddr = get_addr32(*argv); + get_addr(&daddr, *argv, AF_INET); } else if (strcmp(*argv, "local") == 0) { NEXT_ARG(); - laddr = get_addr32(*argv); + get_addr(&saddr, *argv, AF_INET); } else if (matches(*argv, "dev") == 0) { NEXT_ARG(); link = ll_name_to_index(*argv); @@ -289,29 +293,16 @@ get_failed: } else if (strcmp(*argv, "external") == 0) { metadata = 1; } else if (strcmp(*argv, "6rd-prefix") == 0) { - inet_prefix prefix; - NEXT_ARG(); - if (get_prefix(&prefix, *argv, AF_INET6)) + if (get_prefix(&ip6rdprefix, *argv, AF_INET6)) invarg("invalid 6rd_prefix\n", *argv); - memcpy(&ip6rdprefix, prefix.data, 16); - ip6rdprefixlen = prefix.bitlen; } else if (strcmp(*argv, "6rd-relay_prefix") == 0) { - inet_prefix prefix; - NEXT_ARG(); - if (get_prefix(&prefix, *argv, AF_INET)) + if (get_prefix(&ip6rdrelayprefix, *argv, AF_INET)) invarg("invalid 6rd-relay_prefix\n", *argv); - memcpy(&ip6rdrelayprefix, prefix.data, 4); - ip6rdrelayprefixlen = prefix.bitlen; } else if (strcmp(*argv, "6rd-reset") == 0) { - inet_prefix prefix; - - get_prefix(&prefix, "2002::", AF_INET6); - memcpy(&ip6rdprefix, prefix.data, 16); - ip6rdprefixlen = 16; - ip6rdrelayprefix = 0; - ip6rdrelayprefixlen = 0; + get_prefix(&ip6rdprefix, "2002::/16", AF_INET6); + inet_prefix_reset(&ip6rdrelayprefix); } else if (strcmp(*argv, "fwmark") == 0) { NEXT_ARG(); if (get_u32(&fwmark, *argv, 0)) @@ -334,8 +325,14 @@ get_failed: return 0; } - addattr32(n, 1024, IFLA_IPTUN_LOCAL, laddr); - addattr32(n, 1024, IFLA_IPTUN_REMOTE, raddr); + if (is_addrtype_inet(&saddr)) { + addattr_l(n, 1024, IFLA_IPTUN_LOCAL, + saddr.data, saddr.bytelen); + } + if (is_addrtype_inet(&daddr)) { + addattr_l(n, 1024, IFLA_IPTUN_REMOTE, + daddr.data, daddr.bytelen); + } addattr8(n, 1024, IFLA_IPTUN_PMTUDISC, pmtudisc); addattr8(n, 1024, IFLA_IPTUN_TOS, tos); addattr8(n, 1024, IFLA_IPTUN_TTL, ttl); @@ -349,15 +346,17 @@ get_failed: if (strcmp(lu->id, "sit") == 0) { addattr16(n, 1024, IFLA_IPTUN_FLAGS, iflags); - if (ip6rdprefixlen) { + if (is_addrtype_inet(&ip6rdprefix)) { addattr_l(n, 1024, IFLA_IPTUN_6RD_PREFIX, - &ip6rdprefix, sizeof(ip6rdprefix)); + ip6rdprefix.data, ip6rdprefix.bytelen); addattr16(n, 1024, IFLA_IPTUN_6RD_PREFIXLEN, - ip6rdprefixlen); + ip6rdprefix.bitlen); + } + if (is_addrtype_inet(&ip6rdrelayprefix)) { addattr32(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIX, - ip6rdrelayprefix); + ip6rdrelayprefix.data[0]); addattr16(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIXLEN, - ip6rdrelayprefixlen); + ip6rdrelayprefix.bitlen); } }