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];
} 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
#ifndef AF_DECnet
@ -236,7 +269,6 @@ void print_nlmsg_timestamp(FILE *fp, const struct nlmsghdr *n);
extern int cmdlineno;
ssize_t getcmdline(char **line, size_t *len, FILE *in);
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 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,
struct nlmsghdr *n)
{
inet_prefix daddr;
__u32 vni = 0;
__u32 daddr = 0;
struct in6_addr daddr6 = IN6ADDR_ANY_INIT;
__u32 label = 0;
__u8 ttl = 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 &&
!(n->nlmsg_flags & NLM_F_CREATE));
daddr.flags = 0;
while (argc > 0) {
if (!matches(*argv, "id") ||
!matches(*argv, "vni")) {
@ -84,11 +85,8 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv,
NEXT_ARG();
check_duparg(&attrs, IFLA_GENEVE_REMOTE, "remote",
*argv);
if (!inet_get_addr(*argv, &daddr, &daddr6)) {
fprintf(stderr, "Invalid address \"%s\"\n", *argv);
return -1;
}
if (IN6_IS_ADDR_MULTICAST(&daddr6) || IN_MULTICAST(ntohl(daddr)))
get_addr(&daddr, *argv, AF_UNSPEC);
if (!is_addrtype_inet_not_multi(&daddr))
invarg("invalid remote address", *argv);
} else if (!matches(*argv, "ttl") ||
!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
* 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");
return -1;
}
}
addattr32(n, 1024, IFLA_GENEVE_ID, vni);
if (daddr)
addattr_l(n, 1024, IFLA_GENEVE_REMOTE, &daddr, 4);
if (!IN6_IS_ADDR_UNSPECIFIED(&daddr6)) {
addattr_l(n, 1024, IFLA_GENEVE_REMOTE6, &daddr6,
sizeof(struct in6_addr));
if (is_addrtype_inet(&daddr)) {
int type = (daddr.family == AF_INET) ? IFLA_GENEVE_REMOTE :
IFLA_GENEVE_REMOTE6;
addattr_l(n, sizeof(1024), type, daddr.data, daddr.bytelen);
}
if (!set_op || GENEVE_ATTRSET(attrs, IFLA_GENEVE_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,
struct nlmsghdr *n)
{
inet_prefix saddr;
inet_prefix daddr;
__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;
__u16 dstport = 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 &&
!(n->nlmsg_flags & NLM_F_CREATE));
saddr.family = daddr.family = AF_UNSPEC;
saddr.flags = daddr.flags = 0;
while (argc > 0) {
if (!matches(*argv, "id") ||
!matches(*argv, "vni")) {
@ -98,54 +99,33 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
vni >= 1u << 24)
invarg("invalid id", *argv);
} 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, " cannot be specified\n");
return -1;
}
NEXT_ARG();
check_duparg(&attrs, IFLA_VXLAN_GROUP, "group", *argv);
if (!inet_get_addr(*argv, &gaddr, &gaddr6)) {
fprintf(stderr, "Invalid address \"%s\"\n", *argv);
return -1;
}
if (!IN6_IS_ADDR_MULTICAST(&gaddr6) && !IN_MULTICAST(ntohl(gaddr)))
get_addr(&daddr, *argv, saddr.family);
if (!is_addrtype_inet_multi(&daddr))
invarg("invalid group address", *argv);
} 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, " cannot be specified\n");
return -1;
}
NEXT_ARG();
check_duparg(&attrs, IFLA_VXLAN_GROUP, "remote", *argv);
if (!inet_get_addr(*argv, &daddr, &daddr6)) {
fprintf(stderr, "Invalid address \"%s\"\n", *argv);
return -1;
}
if (IN6_IS_ADDR_MULTICAST(&daddr6) || IN_MULTICAST(ntohl(daddr)))
get_addr(&daddr, *argv, saddr.family);
if (!is_addrtype_inet_not_multi(&daddr))
invarg("invalid remote address", *argv);
} else if (!matches(*argv, "local")) {
__u32 saddr = 0;
struct in6_addr saddr6 = IN6ADDR_ANY_INIT;
NEXT_ARG();
check_duparg(&attrs, IFLA_VXLAN_LOCAL, "local", *argv);
if (strcmp(*argv, "any")) {
if (!inet_get_addr(*argv, &saddr, &saddr6)) {
fprintf(stderr, "Invalid address \"%s\"\n", *argv);
return -1;
}
}
if (IN_MULTICAST(ntohl(saddr)) || IN6_IS_ADDR_MULTICAST(&saddr6))
get_addr(&saddr, *argv, daddr.family);
if (!is_addrtype_inet_not_multi(&saddr))
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")) {
unsigned int link;
@ -350,7 +330,7 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
return -1;
}
if ((gaddr || !IN6_IS_ADDR_UNSPECIFIED(&gaddr6)) &&
if (is_addrtype_inet_multi(&daddr) &&
!VXLAN_ATTRSET(attrs, IFLA_VXLAN_LINK)) {
fprintf(stderr, "vxlan: 'group' requires 'dev' to be specified\n");
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))
addattr32(n, 1024, IFLA_VXLAN_ID, vni);
if (gaddr)
addattr_l(n, 1024, IFLA_VXLAN_GROUP, &gaddr, 4);
else if (daddr)
addattr_l(n, 1024, IFLA_VXLAN_GROUP, &daddr, 4);
else if (!IN6_IS_ADDR_UNSPECIFIED(&gaddr6))
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));
else if (preferred_family == AF_INET)
addattr_l(n, 1024, IFLA_VXLAN_GROUP, &daddr, 4);
else if (preferred_family == AF_INET6)
addattr_l(n, 1024, IFLA_VXLAN_GROUP6, &daddr6, sizeof(struct in6_addr));
if (is_addrtype_inet(&saddr)) {
int type = (saddr.family == AF_INET) ? IFLA_VXLAN_LOCAL
: IFLA_VXLAN_LOCAL6;
addattr_l(n, 1024, type, saddr.data, saddr.bytelen);
}
if (is_addrtype_inet(&daddr)) {
int type = (daddr.family == AF_INET) ? IFLA_VXLAN_GROUP
: IFLA_VXLAN_GROUP6;
addattr_l(n, 1024, type, daddr.data, daddr.bytelen);
}
if (!set_op || VXLAN_ATTRSET(attrs, IFLA_VXLAN_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;
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--;
}

View File

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

View File

@ -534,7 +534,7 @@ int get_addr64(__u64 *ap, const char *cp)
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));
@ -543,9 +543,9 @@ int get_addr_1(inet_prefix *addr, const char *name, int family)
strcmp(name, "any") == 0) {
if ((family == AF_DECnet) || (family == AF_MPLS))
return -1;
addr->family = family;
addr->bytelen = (family == AF_INET6 ? 16 : 4);
addr->bitlen = -1;
addr->family = (family != AF_UNSPEC) ? family : AF_INET;
addr->bytelen = af_byte_len(addr->family);
addr->bitlen = -2;
return 0;
}
@ -619,6 +619,36 @@ int get_addr_1(inet_prefix *addr, const char *name, int family)
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)
{
switch (af) {
@ -644,46 +674,46 @@ int af_byte_len(int af)
int get_prefix_1(inet_prefix *dst, char *arg, int family)
{
int err;
unsigned int plen;
char *slash;
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;
}
int err, bitlen, flags;
slash = strchr(arg, '/');
if (slash)
*slash = 0;
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)
*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)
@ -1250,14 +1280,6 @@ int makeargs(char *line, char *argv[], int maxargs)
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)
{
char *tstr;