From e2a4010b3a2f309e9f757f600fe6c1293e7a85d6 Mon Sep 17 00:00:00 2001 From: Yuan Liu Date: Thu, 9 Jun 2016 11:32:16 -0700 Subject: [PATCH] lkl: lkl_add_arp_entry Provides API support to add permanent arp entries to lkl so outsiders don't need to reply arp request. Signed-off-by: Yuan Liu --- Documentation/lkl.txt | 9 ++++++- tools/lkl/include/lkl.h | 8 +++++++ tools/lkl/lib/hijack/init.c | 33 ++++++++++++++++++++++++++ tools/lkl/lib/net.c | 43 +++++++++++++++++++++++++++++++++- tools/lkl/tests/hijack-test.sh | 7 ++++++ 5 files changed, 98 insertions(+), 2 deletions(-) diff --git a/Documentation/lkl.txt b/Documentation/lkl.txt index 95ed6b3a814574..01ed70a7de786c 100644 --- a/Documentation/lkl.txt +++ b/Documentation/lkl.txt @@ -189,9 +189,16 @@ are the list of those variable for your environment. ``` $ LKL_HIJACK_NET_MTU=1280 lkl-hijack.sh ip address show ``` +* LKL_HIJACK_NET_ARP + + Add a list of arp permanent entries in the form of "ip|mac;ip|mac;..." +``` + $ LKL_HIJACK_NET_ARP="192.168.13.100|12:34:56:78:9a:bc;192.168.13.101|12:34:56:78:9a:be" + lkl-hijack.sh ip neighbor show +``` * LKL_HIJACK_DEBUG - increate the verbose level of debug information. + increase the verbose level of debug information. ``` $ LKL_HIJACK_DEBUG=1 lkl-hijack.sh ip address show ``` diff --git a/tools/lkl/include/lkl.h b/tools/lkl/include/lkl.h index 23e3d11fcef717..56a3b2d3d3ed1f 100644 --- a/tools/lkl/include/lkl.h +++ b/tools/lkl/include/lkl.h @@ -301,6 +301,14 @@ struct lkl_netdev *lkl_netdev_dpdk_create(const char *ifname); */ struct lkl_netdev *lkl_netdev_vde_create(const char *switch_path); +/** + * lkl_add_arp_entry - add a permanent arp entry + * @ifindex - the ifindex of the interface + * @ip - ip address of the entry in network byte order + * @mac - mac address of the entry + */ +int lkl_add_arp_entry(int ifindex, unsigned int ip, void* mac); + #ifdef __cplusplus } #endif diff --git a/tools/lkl/lib/hijack/init.c b/tools/lkl/lib/hijack/init.c index 40b907be7dc1cf..5d8d376e8be920 100644 --- a/tools/lkl/lib/hijack/init.c +++ b/tools/lkl/lib/hijack/init.c @@ -62,6 +62,35 @@ int parse_mac_str(char *mac_str, __lkl__u8 mac[LKL_ETH_ALEN]) return 1; } +/* Add permanent arp entries in the form of "ip|mac;ip|mac;..." */ +static void add_arp(int ifindex, char* entries) { + char *saveptr = NULL, *token = NULL; + char *ip = NULL, *mac_str = NULL; + int ret = 0; + __lkl__u8 mac[LKL_ETH_ALEN]; + unsigned int ip_addr; + + for (token = strtok_r(entries, ";", &saveptr); token; + token = strtok_r(NULL, ";", &saveptr)) { + ip = strtok(token, "|"); + mac_str = strtok(NULL, "|"); + if (ip == NULL || mac_str == NULL || strtok(NULL, "|") != NULL) { + return; + } + ip_addr = inet_addr(ip); + ret = parse_mac_str(mac_str, mac); + if (ret != 1) { + fprintf(stderr, "Failed to parse mac: %s\n", mac_str); + return; + } + ret = lkl_add_arp_entry(ifindex, ip_addr, mac); + if (ret) { + fprintf(stderr, "Failed to add arp entry: %s\n", lkl_strerror(ret)); + return; + } + } + return; +} /* We don't have an easy way to make FILE*s out of our fds, so we * can't use e.g. fgets */ @@ -165,6 +194,7 @@ hijack_init(void) char *debug = getenv("LKL_HIJACK_DEBUG"); char *mount = getenv("LKL_HIJACK_MOUNT"); struct lkl_netdev *nd = NULL; + char *arp_entries = getenv("LKL_HIJACK_NET_ARP"); /* Must be run before lkl_netdev_tap_create */ fixup_netdev_tap_ops(); @@ -272,6 +302,9 @@ hijack_init(void) if (mount) mount_cmds_exec(mount, mount_fs); + + if (nd_ifindex >=0 && arp_entries) + add_arp(nd_ifindex, arp_entries); } void __attribute__((destructor)) diff --git a/tools/lkl/lib/net.c b/tools/lkl/lib/net.c index 6b3ac0d9ebbf39..64121a3739ac59 100644 --- a/tools/lkl/lib/net.c +++ b/tools/lkl/lib/net.c @@ -3,7 +3,6 @@ #include "endian.h" #include - static inline void set_sockaddr(struct lkl_sockaddr_in *sin, unsigned int addr, unsigned short port) { @@ -159,3 +158,45 @@ int lkl_netdev_get_ifindex(int id) return ret < 0 ? ret : ifr.lkl_ifr_ifindex; } + +struct lkl_arpreq { + struct lkl_sockaddr arp_pa; /* protocol address */ + struct lkl_sockaddr arp_ha; /* hardware address */ + int arp_flags; /* flags */ + struct lkl_sockaddr arp_netmask; /* netmask of protocol address */ + char arp_dev[LKL_IFNAMSIZ]; +}; + +#define LKL_ATF_PERM 0x04 +#define LKL_ATF_COM 0x02 + +int lkl_add_arp_entry(int ifindex, unsigned int ip, void* mac) { + struct lkl_arpreq req; + int ret = 0; + struct lkl_ifreq ifr; + struct lkl_sockaddr_in* sin = (struct lkl_sockaddr_in*)&req.arp_pa; + int sock; + + bzero(&req, sizeof(req)); + sin->sin_family = LKL_AF_INET; + sin->sin_addr.lkl_s_addr = ip; + memcpy(req.arp_ha.sa_data, mac, LKL_ETH_ALEN); + + sock = lkl_sys_socket(LKL_AF_INET, LKL_SOCK_DGRAM, 0); + if (sock < 0) { + return sock; + } + + req.arp_flags = LKL_ATF_PERM | LKL_ATF_COM; + + ret = ifindex_to_name(sock, &ifr, ifindex); + if (ret < 0) { + lkl_sys_close(sock); + return ret; + } + strcpy(req.arp_dev, ifr.ifr_ifrn.ifrn_name); + + ret = lkl_sys_ioctl(sock, LKL_SIOCSARP, (long)(&req)); + lkl_sys_close(sock); + return ret; +} diff --git a/tools/lkl/tests/hijack-test.sh b/tools/lkl/tests/hijack-test.sh index 63afb7b9a85bb2..9d98e8ca70673c 100755 --- a/tools/lkl/tests/hijack-test.sh +++ b/tools/lkl/tests/hijack-test.sh @@ -94,6 +94,13 @@ sudo arp -d 192.168.13.2 sudo ping -i 0.01 -c 65 192.168.13.2 & ${hijack_script} sleep 3 +# add arp entries +ans=$(LKL_HIJACK_NET_ARP="192.168.13.100|12:34:56:78:9a:bc;192.168.13.101|12:34:56:78:9a:be"\ + ${hijack_script} ip neighbor show) || true +echo "$ans" | tail -n 15 | grep "12:34:56:78:9a:bc" +echo "$ans" | tail -n 15 | grep "12:34:56:78:9a:be" + + sh ${script_dir}/run_netperf.sh 192.168.13.1 1 0 TCP_STREAM sh ${script_dir}/run_netperf.sh 192.168.13.1 1 0 TCP_RR