Skip to content

Commit

Permalink
lkl-tools: add API to add/del ip addresses
Browse files Browse the repository at this point in the history
Helper functions to add/del ip addresses on a nic so LKL network stack
can have multiple ips.

Signed-off-by: Yuan Liu <liuyuan@google.com>
  • Loading branch information
liuyuan10 committed Oct 24, 2016
1 parent 4b77c32 commit 44c9b9b
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 97 deletions.
29 changes: 28 additions & 1 deletion tools/lkl/include/lkl.h
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ void lkl_register_dbg_handler();
/**
* lkl_add_neighbor - add a permanent arp entry
* @ifindex - the ifindex of the interface
* @af - adress family of the ip address. Must be LKL_AF_INET or LKL_AF_INET6
* @af - address family of the ip address. Must be LKL_AF_INET or LKL_AF_INET6
* @ip - ip address of the entry in network byte order
* @mac - mac address of the entry
*/
Expand All @@ -428,6 +428,33 @@ int lkl_add_neighbor(int ifindex, int af, void* addr, void* mac);
*/
int lkl_mount_fs(char *fstype);

/**
* lkl_if_add_ip - add an ip address
* @ifindex - the ifindex of the interface
* @af - address family of the ip address. Must be LKL_AF_INET or LKL_AF_INET6
* @addr - ip address of the entry in network byte order
* @netprefix_len - prefix length of the @addr
*/
int lkl_if_add_ip(int ifindex, int af, void *addr, unsigned int netprefix_len);

/**
* lkl_if_del_ip - add an ip address
* @ifindex - the ifindex of the interface
* @af - address family of the ip address. Must be LKL_AF_INET or LKL_AF_INET6
* @addr - ip address of the entry in network byte order
* @netprefix_len - prefix length of the @addr
*/
int lkl_if_del_ip(int ifindex, int af, void *addr, unsigned int netprefix_len);

/**
* lkl_if_wait_ipv6_dad - wait for DAD to be done for a ipv6 address
* must be called after interface is up
*
* @ifindex - the ifindex of the interface
* @addr - ip address of the entry in network byte order
*/
int lkl_if_wait_ipv6_dad(int ifindex, void *addr);

#ifdef __cplusplus
}
#endif
Expand Down
198 changes: 102 additions & 96 deletions tools/lkl/lib/net.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,41 +87,7 @@ int lkl_if_set_mtu(int ifindex, int mtu)

int lkl_if_set_ipv4(int ifindex, unsigned int addr, unsigned int netmask_len)
{
struct lkl_ifreq ifr;
struct lkl_sockaddr_in *sin;
int err, sock;


sock = lkl_sys_socket(LKL_AF_INET, LKL_SOCK_DGRAM, 0);
if (sock < 0)
return sock;

err = ifindex_to_name(sock, &ifr, ifindex);
if (err < 0)
return err;

if (netmask_len >= 31)
return -LKL_EINVAL;

sin = (struct lkl_sockaddr_in *)&ifr.lkl_ifr_addr;
set_sockaddr(sin, addr, 0);

err = lkl_sys_ioctl(sock, LKL_SIOCSIFADDR, (long)&ifr);
if (!err) {
int netmask = (((1<<netmask_len)-1))<<(32-netmask_len);

sin = (struct lkl_sockaddr_in *)&ifr.lkl_ifr_netmask;
set_sockaddr(sin, htonl(netmask), 0);
err = lkl_sys_ioctl(sock, LKL_SIOCSIFNETMASK, (long)&ifr);
if (!err) {
set_sockaddr(sin, htonl(ntohl(addr)|~netmask), 0);
err = lkl_sys_ioctl(sock, LKL_SIOCSIFBRDADDR, (long)&ifr);
}
}

lkl_sys_close(sock);

return err;
return lkl_if_add_ip(ifindex, LKL_AF_INET, &addr, netmask_len);
}

int lkl_set_ipv4_gateway(unsigned int addr)
Expand Down Expand Up @@ -208,7 +174,7 @@ static int parse_rtattr(struct lkl_rtattr *tb[], int max,
rta = LKL_RTA_NEXT(rta, len);
}
if (len)
lkl_printf( "!!!Deficit %d, rta_len=%d\n", len,
lkl_printf("!!!Deficit %d, rta_len=%d\n", len,
rta->rta_len);
return 0;
}
Expand Down Expand Up @@ -244,7 +210,7 @@ static int check_ipv6_dad(struct lkl_sockaddr_nl *nladdr,

len -= LKL_NLMSG_LENGTH(sizeof(*ifa));
if (len < 0) {
lkl_printf( "BUG: wrong nlmsg len %d\n", len);
lkl_printf("BUG: wrong nlmsg len %d\n", len);
return -1;
}

Expand All @@ -267,7 +233,7 @@ static int check_ipv6_dad(struct lkl_sockaddr_nl *nladdr,
return 1;
}
if (ifa_flags & LKL_IFA_F_DADFAILED) {
lkl_printf( "IPV6 DAD failed.\n");
lkl_printf("IPV6 DAD failed.\n");
return -1;
}
if (!(ifa_flags & LKL_IFA_F_TENTATIVE))
Expand Down Expand Up @@ -300,18 +266,18 @@ static int rtnl_listen(int fd, int (*handler)(struct lkl_sockaddr_nl *nladdr,
if (status < 0) {
if (status == -LKL_EINTR || status == -LKL_EAGAIN)
continue;
lkl_printf( "netlink receive error %s (%d)\n",
lkl_printf("netlink receive error %s (%d)\n",
lkl_strerror(status), status);
if (status == -LKL_ENOBUFS)
continue;
return status;
}
if (status == 0) {
lkl_printf( "EOF on netlink\n");
lkl_printf("EOF on netlink\n");
return -1;
}
if (msg.msg_namelen != sizeof(nladdr)) {
lkl_printf( "Sender address length == %d\n",
lkl_printf("Sender address length == %d\n",
msg.msg_namelen);
return -1;
}
Expand All @@ -324,10 +290,10 @@ static int rtnl_listen(int fd, int (*handler)(struct lkl_sockaddr_nl *nladdr,

if (l < 0 || len > status) {
if (msg.msg_flags & LKL_MSG_TRUNC) {
lkl_printf( "Truncated message\n");
lkl_printf("Truncated message\n");
return -1;
}
lkl_printf( "!!!malformed message: len=%d\n",
lkl_printf("!!!malformed message: len=%d\n",
len);
return -1;
}
Expand All @@ -341,17 +307,17 @@ static int rtnl_listen(int fd, int (*handler)(struct lkl_sockaddr_nl *nladdr,
LKL_NLMSG_ALIGN(len));
}
if (msg.msg_flags & LKL_MSG_TRUNC) {
lkl_printf( "Message truncated\n");
lkl_printf("Message truncated\n");
continue;
}
if (status) {
lkl_printf( "!!!Remnant of size %d\n", status);
lkl_printf("!!!Remnant of size %d\n", status);
return -1;
}
}
}

static int wait_ipv6(int ifindex, void *addr)
int lkl_if_wait_ipv6_dad(int ifindex, void *addr)
{
struct addr_filter filter = {.ifindex = ifindex, .addr = addr};
int fd, ret;
Expand Down Expand Up @@ -383,32 +349,15 @@ static int wait_ipv6(int ifindex, void *addr)

int lkl_if_set_ipv6(int ifindex, void *addr, unsigned int netprefix_len)
{
struct lkl_in6_ifreq ifr6;
int err, sock;

if (netprefix_len >= 128)
return -LKL_EINVAL;

sock = lkl_sys_socket(LKL_AF_INET6, LKL_SOCK_DGRAM, 0);
if (sock < 0)
return sock;

memcpy(&ifr6.ifr6_addr.lkl_s6_addr, addr, sizeof(struct lkl_in6_addr));
ifr6.ifr6_ifindex = ifindex;
ifr6.ifr6_prefixlen = netprefix_len;

err = lkl_sys_ioctl(sock, LKL_SIOCSIFADDR, (long)&ifr6);
lkl_sys_close(sock);
int err = lkl_if_add_ip(ifindex, LKL_AF_INET6, addr, netprefix_len);
if (err)
return err;

err = wait_ipv6(ifindex, addr);
return err;
return lkl_if_wait_ipv6_dad(ifindex, addr);
}

/* returns:
* 0 - succeed.
* -1 - error.
* < 0 - error number.
* 1 - should wait for new msg.
*/
static int check_error(struct lkl_sockaddr_nl *nladdr, struct lkl_nlmsghdr *n,
Expand All @@ -427,15 +376,15 @@ static int check_error(struct lkl_sockaddr_nl *nladdr, struct lkl_nlmsghdr *n,
int l = n->nlmsg_len - sizeof(*n);

if (l < (int)sizeof(struct lkl_nlmsgerr))
lkl_printf( "ERROR truncated\n");
lkl_printf("ERROR truncated\n");
else if (!err->error)
return 0;

lkl_printf( "RTNETLINK answers: %s\n",
lkl_printf("RTNETLINK answers: %s\n",
strerror(-err->error));
return -1;
return err->error;
}
lkl_printf( "Unexpected reply!!!\n");
lkl_printf("Unexpected reply!!!\n");
return -1;
}

Expand Down Expand Up @@ -466,60 +415,117 @@ static int rtnl_talk(int fd, struct lkl_nlmsghdr *n)
return status;
}

static int addattr_l(struct lkl_nlmsghdr *n, unsigned int maxlen,
int type, const void *data, int alen)
{
int len = LKL_RTA_LENGTH(alen);
struct lkl_rtattr *rta;

if (LKL_NLMSG_ALIGN(n->nlmsg_len) + LKL_RTA_ALIGN(len) > maxlen) {
lkl_printf("addattr_l ERROR: message exceeded bound of %d\n",
maxlen);
return -1;
}
rta = ((struct lkl_rtattr *) (((void *) (n)) +
LKL_NLMSG_ALIGN(n->nlmsg_len)));
rta->rta_type = type;
rta->rta_len = len;
memcpy(LKL_RTA_DATA(rta), data, alen);
n->nlmsg_len = LKL_NLMSG_ALIGN(n->nlmsg_len) + LKL_RTA_ALIGN(len);
return 0;
}

int lkl_add_neighbor(int ifindex, int af, void* ip, void* mac)
{
struct {
struct lkl_nlmsghdr n;
struct lkl_ndmsg r;
char buf[1024];
} req2;
} req = {
.n.nlmsg_len = LKL_NLMSG_LENGTH(sizeof(struct lkl_ndmsg)),
.n.nlmsg_type = LKL_RTM_NEWNEIGH,
.n.nlmsg_flags = LKL_NLM_F_REQUEST |
LKL_NLM_F_CREATE | LKL_NLM_F_REPLACE,
.r.ndm_family = af,
.r.ndm_ifindex = ifindex,
.r.ndm_state = LKL_NUD_PERMANENT,

};
int err, addr_sz;
int ndmsglen = LKL_NLMSG_LENGTH(sizeof(struct lkl_ndmsg));
struct lkl_rtattr *dstattr;
int fd;

if (af == LKL_AF_INET)
addr_sz = 4;
else if (af == LKL_AF_INET6)
addr_sz = 16;
else {
lkl_printf( "Bad address family: %d\n", af);
lkl_printf("Bad address family: %d\n", af);
return -1;
}

fd = netlink_sock(0);
if (fd < 0)
return fd;

memset(&req2, 0, sizeof(req2));

// create the IP attribute
dstattr = (struct lkl_rtattr *)req2.buf;
dstattr->rta_type = LKL_NDA_DST;
dstattr->rta_len = sizeof(struct lkl_rtattr) + addr_sz;
memcpy(((char *)dstattr) + sizeof(struct lkl_rtattr), ip, addr_sz);
ndmsglen += dstattr->rta_len;
addattr_l(&req.n, sizeof(req), LKL_NDA_DST, ip, addr_sz);

// create the MAC attribute
dstattr = (struct lkl_rtattr *)(req2.buf + dstattr->rta_len);
dstattr->rta_type = LKL_NDA_LLADDR;
dstattr->rta_len = sizeof(struct lkl_rtattr) + 6;
memcpy(((char *)dstattr) + sizeof(struct lkl_rtattr), mac, 6);
ndmsglen += dstattr->rta_len;
addattr_l(&req.n, sizeof(req), LKL_NDA_LLADDR, mac, 6);

err = rtnl_talk(fd, &req.n);
lkl_sys_close(fd);
return err;
}

static int ipaddr_modify(int cmd, int flags, int ifindex, int af, void *addr,
unsigned int netprefix_len)
{
struct {
struct lkl_nlmsghdr n;
struct lkl_ifaddrmsg ifa;
char buf[256];
} req = {
.n.nlmsg_len = LKL_NLMSG_LENGTH(sizeof(struct lkl_ifaddrmsg)),
.n.nlmsg_flags = LKL_NLM_F_REQUEST | flags,
.n.nlmsg_type = cmd,
.ifa.ifa_family = af,
.ifa.ifa_prefixlen = netprefix_len,
.ifa.ifa_index = ifindex,
};
int err, addr_sz;
int fd;

// fill in the netlink message header
req2.n.nlmsg_len = ndmsglen;
req2.n.nlmsg_type = LKL_RTM_NEWNEIGH;
req2.n.nlmsg_flags =
LKL_NLM_F_REQUEST | LKL_NLM_F_CREATE | LKL_NLM_F_REPLACE;
if (af == LKL_AF_INET)
addr_sz = 4;
else if (af == LKL_AF_INET6)
addr_sz = 16;
else {
lkl_printf("Bad address family: %d\n", af);
return -1;
}

fd = netlink_sock(0);
if (fd < 0)
return fd;

// fill in the netlink message NEWNEIGH
req2.r.ndm_family = af;
req2.r.ndm_ifindex = ifindex;
req2.r.ndm_state = LKL_NUD_PERMANENT;
// create the IP attribute
addattr_l(&req.n, sizeof(req), LKL_IFA_LOCAL, addr, addr_sz);

err = rtnl_talk(fd, &req2.n);
err = rtnl_talk(fd, &req.n);

lkl_sys_close(fd);
return err;
}

int lkl_if_add_ip(int ifindex, int af, void *addr, unsigned int netprefix_len)
{
return ipaddr_modify(LKL_RTM_NEWADDR, LKL_NLM_F_CREATE | LKL_NLM_F_EXCL,
ifindex, af, addr, netprefix_len);
}

int lkl_if_del_ip(int ifindex, int af, void *addr, unsigned int netprefix_len)
{
return ipaddr_modify(LKL_RTM_DELADDR, 0, ifindex, af,
addr, netprefix_len);
}

0 comments on commit 44c9b9b

Please sign in to comment.