Merge branch 'inet_get_addr' into net-next

Serhey Popovych  says:

====================

It looks confusing to have multiple independent
routines to get internet address from it's string
representation: get_addr() and inet_get_addr().

Most complicated users of inet_get_addr() is
iplink_geneve.c and iplink_vxlan.c because they
required to handle both AF_INET and AF_INET6
for their local/remote endpoints.

On the other hand get_addr() does not provide
additional information like address type: need
to address this. to get rid of current and
possible future code duplications. Note that
this functionality is first step to make proto
independent handling of local/remote endpoints
in ip/tunnel code (there will be additional
series based on this one).

Also fix get_addr_1() and get_prefix() to make
sure it always provide correct ->family and
->bitlen.

As always comments, suggestions and criticism
are welcome.

====================

Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
David Ahern 2018-01-21 10:11:07 -08:00
commit 40cf5b0959
6 changed files with 141 additions and 109 deletions

View File

@ -54,7 +54,40 @@ typedef struct
__u32 data[64]; __u32 data[64];
} inet_prefix; } inet_prefix;
#define PREFIXLEN_SPECIFIED 1 enum {
PREFIXLEN_SPECIFIED = (1 << 0),
ADDRTYPE_INET = (1 << 1),
ADDRTYPE_UNSPEC = (1 << 2),
ADDRTYPE_MULTI = (1 << 3),
ADDRTYPE_INET_UNSPEC = ADDRTYPE_INET | ADDRTYPE_UNSPEC,
ADDRTYPE_INET_MULTI = ADDRTYPE_INET | ADDRTYPE_MULTI
};
static inline bool is_addrtype_inet(const inet_prefix *p)
{
return p->flags & ADDRTYPE_INET;
}
static inline bool is_addrtype_inet_unspec(const inet_prefix *p)
{
return (p->flags & ADDRTYPE_INET_UNSPEC) == ADDRTYPE_INET_UNSPEC;
}
static inline bool is_addrtype_inet_multi(const inet_prefix *p)
{
return (p->flags & ADDRTYPE_INET_MULTI) == ADDRTYPE_INET_MULTI;
}
static inline bool is_addrtype_inet_not_unspec(const inet_prefix *p)
{
return (p->flags & ADDRTYPE_INET_UNSPEC) == ADDRTYPE_INET;
}
static inline bool is_addrtype_inet_not_multi(const inet_prefix *p)
{
return (p->flags & ADDRTYPE_INET_MULTI) == ADDRTYPE_INET;
}
#define DN_MAXADDL 20 #define DN_MAXADDL 20
#ifndef AF_DECnet #ifndef AF_DECnet
@ -236,7 +269,6 @@ void print_nlmsg_timestamp(FILE *fp, const struct nlmsghdr *n);
extern int cmdlineno; extern int cmdlineno;
ssize_t getcmdline(char **line, size_t *len, FILE *in); ssize_t getcmdline(char **line, size_t *len, FILE *in);
int makeargs(char *line, char *argv[], int maxargs); int makeargs(char *line, char *argv[], int maxargs);
int inet_get_addr(const char *src, __u32 *dst, struct in6_addr *dst6);
struct iplink_req { struct iplink_req {
struct nlmsghdr n; struct nlmsghdr n;

View File

@ -57,9 +57,8 @@ static void check_duparg(__u64 *attrs, int type, const char *key,
static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, static int geneve_parse_opt(struct link_util *lu, int argc, char **argv,
struct nlmsghdr *n) struct nlmsghdr *n)
{ {
inet_prefix daddr;
__u32 vni = 0; __u32 vni = 0;
__u32 daddr = 0;
struct in6_addr daddr6 = IN6ADDR_ANY_INIT;
__u32 label = 0; __u32 label = 0;
__u8 ttl = 0; __u8 ttl = 0;
__u8 tos = 0; __u8 tos = 0;
@ -72,6 +71,8 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv,
bool set_op = (n->nlmsg_type == RTM_NEWLINK && bool set_op = (n->nlmsg_type == RTM_NEWLINK &&
!(n->nlmsg_flags & NLM_F_CREATE)); !(n->nlmsg_flags & NLM_F_CREATE));
daddr.flags = 0;
while (argc > 0) { while (argc > 0) {
if (!matches(*argv, "id") || if (!matches(*argv, "id") ||
!matches(*argv, "vni")) { !matches(*argv, "vni")) {
@ -84,11 +85,8 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv,
NEXT_ARG(); NEXT_ARG();
check_duparg(&attrs, IFLA_GENEVE_REMOTE, "remote", check_duparg(&attrs, IFLA_GENEVE_REMOTE, "remote",
*argv); *argv);
if (!inet_get_addr(*argv, &daddr, &daddr6)) { get_addr(&daddr, *argv, AF_UNSPEC);
fprintf(stderr, "Invalid address \"%s\"\n", *argv); if (!is_addrtype_inet_not_multi(&daddr))
return -1;
}
if (IN6_IS_ADDR_MULTICAST(&daddr6) || IN_MULTICAST(ntohl(daddr)))
invarg("invalid remote address", *argv); invarg("invalid remote address", *argv);
} else if (!matches(*argv, "ttl") || } else if (!matches(*argv, "ttl") ||
!matches(*argv, "hoplimit")) { !matches(*argv, "hoplimit")) {
@ -191,18 +189,17 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv,
* ID (VNI) to identify the geneve device, and we do not need * ID (VNI) to identify the geneve device, and we do not need
* the remote IP. * the remote IP.
*/ */
if (!set_op && !daddr && IN6_IS_ADDR_UNSPECIFIED(&daddr6)) { if (!set_op && !is_addrtype_inet(&daddr)) {
fprintf(stderr, "geneve: remote link partner not specified\n"); fprintf(stderr, "geneve: remote link partner not specified\n");
return -1; return -1;
} }
} }
addattr32(n, 1024, IFLA_GENEVE_ID, vni); addattr32(n, 1024, IFLA_GENEVE_ID, vni);
if (daddr) if (is_addrtype_inet(&daddr)) {
addattr_l(n, 1024, IFLA_GENEVE_REMOTE, &daddr, 4); int type = (daddr.family == AF_INET) ? IFLA_GENEVE_REMOTE :
if (!IN6_IS_ADDR_UNSPECIFIED(&daddr6)) { IFLA_GENEVE_REMOTE6;
addattr_l(n, 1024, IFLA_GENEVE_REMOTE6, &daddr6, addattr_l(n, sizeof(1024), type, daddr.data, daddr.bytelen);
sizeof(struct in6_addr));
} }
if (!set_op || GENEVE_ATTRSET(attrs, IFLA_GENEVE_LABEL)) if (!set_op || GENEVE_ATTRSET(attrs, IFLA_GENEVE_LABEL))
addattr32(n, 1024, IFLA_GENEVE_LABEL, label); addattr32(n, 1024, IFLA_GENEVE_LABEL, label);

View File

@ -74,11 +74,9 @@ static void check_duparg(__u64 *attrs, int type, const char *key,
static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
struct nlmsghdr *n) struct nlmsghdr *n)
{ {
inet_prefix saddr;
inet_prefix daddr;
__u32 vni = 0; __u32 vni = 0;
__u32 gaddr = 0;
__u32 daddr = 0;
struct in6_addr gaddr6 = IN6ADDR_ANY_INIT;
struct in6_addr daddr6 = IN6ADDR_ANY_INIT;
__u8 learning = 1; __u8 learning = 1;
__u16 dstport = 0; __u16 dstport = 0;
__u8 metadata = 0; __u8 metadata = 0;
@ -86,6 +84,9 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
bool set_op = (n->nlmsg_type == RTM_NEWLINK && bool set_op = (n->nlmsg_type == RTM_NEWLINK &&
!(n->nlmsg_flags & NLM_F_CREATE)); !(n->nlmsg_flags & NLM_F_CREATE));
saddr.family = daddr.family = AF_UNSPEC;
saddr.flags = daddr.flags = 0;
while (argc > 0) { while (argc > 0) {
if (!matches(*argv, "id") || if (!matches(*argv, "id") ||
!matches(*argv, "vni")) { !matches(*argv, "vni")) {
@ -98,54 +99,33 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
vni >= 1u << 24) vni >= 1u << 24)
invarg("invalid id", *argv); invarg("invalid id", *argv);
} else if (!matches(*argv, "group")) { } else if (!matches(*argv, "group")) {
if (daddr || !IN6_IS_ADDR_UNSPECIFIED(&daddr6)) { if (is_addrtype_inet_not_multi(&daddr)) {
fprintf(stderr, "vxlan: both group and remote"); fprintf(stderr, "vxlan: both group and remote");
fprintf(stderr, " cannot be specified\n"); fprintf(stderr, " cannot be specified\n");
return -1; return -1;
} }
NEXT_ARG(); NEXT_ARG();
check_duparg(&attrs, IFLA_VXLAN_GROUP, "group", *argv); check_duparg(&attrs, IFLA_VXLAN_GROUP, "group", *argv);
if (!inet_get_addr(*argv, &gaddr, &gaddr6)) { get_addr(&daddr, *argv, saddr.family);
fprintf(stderr, "Invalid address \"%s\"\n", *argv); if (!is_addrtype_inet_multi(&daddr))
return -1;
}
if (!IN6_IS_ADDR_MULTICAST(&gaddr6) && !IN_MULTICAST(ntohl(gaddr)))
invarg("invalid group address", *argv); invarg("invalid group address", *argv);
} else if (!matches(*argv, "remote")) { } else if (!matches(*argv, "remote")) {
if (gaddr || !IN6_IS_ADDR_UNSPECIFIED(&gaddr6)) { if (is_addrtype_inet_multi(&daddr)) {
fprintf(stderr, "vxlan: both group and remote"); fprintf(stderr, "vxlan: both group and remote");
fprintf(stderr, " cannot be specified\n"); fprintf(stderr, " cannot be specified\n");
return -1; return -1;
} }
NEXT_ARG(); NEXT_ARG();
check_duparg(&attrs, IFLA_VXLAN_GROUP, "remote", *argv); check_duparg(&attrs, IFLA_VXLAN_GROUP, "remote", *argv);
if (!inet_get_addr(*argv, &daddr, &daddr6)) { get_addr(&daddr, *argv, saddr.family);
fprintf(stderr, "Invalid address \"%s\"\n", *argv); if (!is_addrtype_inet_not_multi(&daddr))
return -1;
}
if (IN6_IS_ADDR_MULTICAST(&daddr6) || IN_MULTICAST(ntohl(daddr)))
invarg("invalid remote address", *argv); invarg("invalid remote address", *argv);
} else if (!matches(*argv, "local")) { } else if (!matches(*argv, "local")) {
__u32 saddr = 0;
struct in6_addr saddr6 = IN6ADDR_ANY_INIT;
NEXT_ARG(); NEXT_ARG();
check_duparg(&attrs, IFLA_VXLAN_LOCAL, "local", *argv); check_duparg(&attrs, IFLA_VXLAN_LOCAL, "local", *argv);
if (strcmp(*argv, "any")) { get_addr(&saddr, *argv, daddr.family);
if (!inet_get_addr(*argv, &saddr, &saddr6)) { if (!is_addrtype_inet_not_multi(&saddr))
fprintf(stderr, "Invalid address \"%s\"\n", *argv);
return -1;
}
}
if (IN_MULTICAST(ntohl(saddr)) || IN6_IS_ADDR_MULTICAST(&saddr6))
invarg("invalid local address", *argv); invarg("invalid local address", *argv);
if (saddr)
addattr_l(n, 1024, IFLA_VXLAN_LOCAL, &saddr, 4);
else if (!IN6_IS_ADDR_UNSPECIFIED(&saddr6))
addattr_l(n, 1024, IFLA_VXLAN_LOCAL6, &saddr6,
sizeof(struct in6_addr));
} else if (!matches(*argv, "dev")) { } else if (!matches(*argv, "dev")) {
unsigned int link; unsigned int link;
@ -350,7 +330,7 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
return -1; return -1;
} }
if ((gaddr || !IN6_IS_ADDR_UNSPECIFIED(&gaddr6)) && if (is_addrtype_inet_multi(&daddr) &&
!VXLAN_ATTRSET(attrs, IFLA_VXLAN_LINK)) { !VXLAN_ATTRSET(attrs, IFLA_VXLAN_LINK)) {
fprintf(stderr, "vxlan: 'group' requires 'dev' to be specified\n"); fprintf(stderr, "vxlan: 'group' requires 'dev' to be specified\n");
return -1; return -1;
@ -369,18 +349,18 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
if (VXLAN_ATTRSET(attrs, IFLA_VXLAN_ID)) if (VXLAN_ATTRSET(attrs, IFLA_VXLAN_ID))
addattr32(n, 1024, IFLA_VXLAN_ID, vni); addattr32(n, 1024, IFLA_VXLAN_ID, vni);
if (gaddr)
addattr_l(n, 1024, IFLA_VXLAN_GROUP, &gaddr, 4); if (is_addrtype_inet(&saddr)) {
else if (daddr) int type = (saddr.family == AF_INET) ? IFLA_VXLAN_LOCAL
addattr_l(n, 1024, IFLA_VXLAN_GROUP, &daddr, 4); : IFLA_VXLAN_LOCAL6;
else if (!IN6_IS_ADDR_UNSPECIFIED(&gaddr6)) addattr_l(n, 1024, type, saddr.data, saddr.bytelen);
addattr_l(n, 1024, IFLA_VXLAN_GROUP6, &gaddr6, sizeof(struct in6_addr)); }
else if (!IN6_IS_ADDR_UNSPECIFIED(&daddr6))
addattr_l(n, 1024, IFLA_VXLAN_GROUP6, &daddr6, sizeof(struct in6_addr)); if (is_addrtype_inet(&daddr)) {
else if (preferred_family == AF_INET) int type = (daddr.family == AF_INET) ? IFLA_VXLAN_GROUP
addattr_l(n, 1024, IFLA_VXLAN_GROUP, &daddr, 4); : IFLA_VXLAN_GROUP6;
else if (preferred_family == AF_INET6) addattr_l(n, 1024, type, daddr.data, daddr.bytelen);
addattr_l(n, 1024, IFLA_VXLAN_GROUP6, &daddr6, sizeof(struct in6_addr)); }
if (!set_op || VXLAN_ATTRSET(attrs, IFLA_VXLAN_LEARNING)) if (!set_op || VXLAN_ATTRSET(attrs, IFLA_VXLAN_LEARNING))
addattr8(n, 1024, IFLA_VXLAN_LEARNING, learning); addattr8(n, 1024, IFLA_VXLAN_LEARNING, learning);

View File

@ -431,7 +431,10 @@ static struct ipv6_sr_hdr *parse_srh(char *segbuf, int hmac, bool encap)
i = srh->first_segment; i = srh->first_segment;
for (s = strtok(segbuf, ","); s; s = strtok(NULL, ",")) { for (s = strtok(segbuf, ","); s; s = strtok(NULL, ",")) {
inet_get_addr(s, NULL, &srh->segments[i]); inet_prefix addr;
get_addr(&addr, s, AF_INET6);
memcpy(&srh->segments[i], addr.data, sizeof(struct in6_addr));
i--; i--;
} }

View File

@ -49,7 +49,7 @@ static int genl_family = -1;
static struct { static struct {
unsigned int cmd; unsigned int cmd;
struct in6_addr addr; inet_prefix addr;
__u32 keyid; __u32 keyid;
const char *pass; const char *pass;
__u8 alg_id; __u8 alg_id;
@ -152,7 +152,7 @@ static int seg6_do_cmd(void)
break; break;
} }
case SEG6_CMD_SET_TUNSRC: case SEG6_CMD_SET_TUNSRC:
addattr_l(&req.n, sizeof(req), SEG6_ATTR_DST, &opts.addr, addattr_l(&req.n, sizeof(req), SEG6_ATTR_DST, opts.addr.data,
sizeof(struct in6_addr)); sizeof(struct in6_addr));
break; break;
case SEG6_CMD_DUMPHMAC: case SEG6_CMD_DUMPHMAC:
@ -226,9 +226,7 @@ int do_seg6(int argc, char **argv)
} else if (matches(*argv, "set") == 0) { } else if (matches(*argv, "set") == 0) {
NEXT_ARG(); NEXT_ARG();
opts.cmd = SEG6_CMD_SET_TUNSRC; opts.cmd = SEG6_CMD_SET_TUNSRC;
if (!inet_get_addr(*argv, NULL, &opts.addr)) get_addr(&opts.addr, *argv, AF_INET6);
invarg("tunsrc ADDRESS value is invalid",
*argv);
} else { } else {
invarg("unknown", *argv); invarg("unknown", *argv);
} }

View File

@ -534,7 +534,7 @@ int get_addr64(__u64 *ap, const char *cp)
return 1; return 1;
} }
int get_addr_1(inet_prefix *addr, const char *name, int family) static int __get_addr_1(inet_prefix *addr, const char *name, int family)
{ {
memset(addr, 0, sizeof(*addr)); memset(addr, 0, sizeof(*addr));
@ -543,9 +543,9 @@ int get_addr_1(inet_prefix *addr, const char *name, int family)
strcmp(name, "any") == 0) { strcmp(name, "any") == 0) {
if ((family == AF_DECnet) || (family == AF_MPLS)) if ((family == AF_DECnet) || (family == AF_MPLS))
return -1; return -1;
addr->family = family; addr->family = (family != AF_UNSPEC) ? family : AF_INET;
addr->bytelen = (family == AF_INET6 ? 16 : 4); addr->bytelen = af_byte_len(addr->family);
addr->bitlen = -1; addr->bitlen = -2;
return 0; return 0;
} }
@ -619,6 +619,36 @@ int get_addr_1(inet_prefix *addr, const char *name, int family)
return 0; return 0;
} }
int get_addr_1(inet_prefix *addr, const char *name, int family)
{
int ret;
ret = __get_addr_1(addr, name, family);
if (ret)
return ret;
switch (addr->family) {
case AF_INET:
if (!addr->data[0])
addr->flags |= ADDRTYPE_INET_UNSPEC;
else if (IN_MULTICAST(ntohl(addr->data[0])))
addr->flags |= ADDRTYPE_INET_MULTI;
else
addr->flags |= ADDRTYPE_INET;
break;
case AF_INET6:
if (IN6_IS_ADDR_UNSPECIFIED(addr->data))
addr->flags |= ADDRTYPE_INET_UNSPEC;
else if (IN6_IS_ADDR_MULTICAST(addr->data))
addr->flags |= ADDRTYPE_INET_MULTI;
else
addr->flags |= ADDRTYPE_INET;
break;
}
return 0;
}
int af_bit_len(int af) int af_bit_len(int af)
{ {
switch (af) { switch (af) {
@ -644,46 +674,46 @@ int af_byte_len(int af)
int get_prefix_1(inet_prefix *dst, char *arg, int family) int get_prefix_1(inet_prefix *dst, char *arg, int family)
{ {
int err;
unsigned int plen;
char *slash; char *slash;
int err, bitlen, flags;
memset(dst, 0, sizeof(*dst));
if (strcmp(arg, "default") == 0 ||
strcmp(arg, "any") == 0 ||
strcmp(arg, "all") == 0) {
if ((family == AF_DECnet) || (family == AF_MPLS))
return -1;
dst->family = family;
dst->bytelen = 0;
dst->bitlen = 0;
dst->flags |= PREFIXLEN_SPECIFIED;
return 0;
}
slash = strchr(arg, '/'); slash = strchr(arg, '/');
if (slash) if (slash)
*slash = 0; *slash = 0;
err = get_addr_1(dst, arg, family); err = get_addr_1(dst, arg, family);
if (err == 0) {
dst->bitlen = af_bit_len(dst->family);
if (slash) {
if (get_netmask(&plen, slash+1, 0)
|| plen > dst->bitlen) {
err = -1;
goto done;
}
dst->flags |= PREFIXLEN_SPECIFIED;
dst->bitlen = plen;
}
}
done:
if (slash) if (slash)
*slash = '/'; *slash = '/';
return err;
if (err)
return err;
bitlen = af_bit_len(dst->family);
flags = PREFIXLEN_SPECIFIED;
if (slash) {
unsigned int plen;
if (dst->bitlen == -2)
return -1;
if (get_netmask(&plen, slash + 1, 0))
return -1;
if (plen > bitlen)
return -1;
bitlen = plen;
} else {
if (dst->bitlen == -2)
bitlen = 0;
else
flags = 0;
}
dst->flags |= flags;
dst->bitlen = bitlen;
return 0;
} }
static const char *family_name_verbose(int family) static const char *family_name_verbose(int family)
@ -1250,14 +1280,6 @@ int makeargs(char *line, char *argv[], int maxargs)
return argc; return argc;
} }
int inet_get_addr(const char *src, __u32 *dst, struct in6_addr *dst6)
{
if (strchr(src, ':'))
return inet_pton(AF_INET6, src, dst6);
else
return inet_pton(AF_INET, src, dst);
}
void print_nlmsg_timestamp(FILE *fp, const struct nlmsghdr *n) void print_nlmsg_timestamp(FILE *fp, const struct nlmsghdr *n)
{ {
char *tstr; char *tstr;