From 4e3599d820398e23ff12559bec3630a1655989a8 Mon Sep 17 00:00:00 2001 From: fengbojiang Date: Wed, 16 Jun 2021 19:24:35 +0800 Subject: [PATCH] Support set multi virtual IPv4/IPv6 net addrs in `config.ini`, instead of use `ff_ifconfig`. Close #421. --- config.ini | 15 +++++- lib/ff_config.c | 100 +++++++++++++++++++++++++++++++--- lib/ff_config.h | 12 +++++ lib/ff_veth.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 254 insertions(+), 12 deletions(-) diff --git a/config.ini b/config.ini index 3a0b2cfc9..598120417 100644 --- a/config.ini +++ b/config.ini @@ -84,12 +84,23 @@ addr=192.168.1.2 netmask=255.255.225.0 broadcast=192.168.1.255 gateway=192.168.1.1 -# IPv6 net addr -# Optional parameters + +# IPv6 net addr, Optional parameters. #addr6=ff::02 #prefix_len=64 #gateway6=ff::01 +# Multi virtual IPv4/IPv6 net addr, Optional parameters. +# `vip_ifname`: default `f-stack-x` +# `vip_addr`: Separated by semicolons, MAX number 64; + Only support netmask 255.255.255.255, broadcast x.x.x.255 now, hard code in `ff_veth_setvaddr`. +# `vip_addr6`: Separated by semicolons, MAX number 64. +# `vip_prefix_len`: All addr6 use the same prefix now, default 64. +#vip_ifname=lo0 +#vip_addr=192.168.1.3;192.168.1.4;192.168.1.5;192.168.1.6 +#vip_addr6=ff::03;ff::04;ff::05;ff::06;ff::07 +#vip_prefix_len=64 + # lcore list used to handle this port # the format is same as port_list #lcore_list=0 diff --git a/lib/ff_config.c b/lib/ff_config.c index 4d7b7c4ed..049a6b33b 100644 --- a/lib/ff_config.c +++ b/lib/ff_config.c @@ -366,6 +366,81 @@ parse_port_slave_list(struct ff_port_cfg *cfg, const char *v_str) return res; } +static int +vip_cfg_hander(struct ff_port_cfg *cur) +{ + //vip cfg + int ret; + char *vip_addr_array[VIP_MAX_NUM]; + + ret = rte_strsplit(cur->vip_addr_str, strlen(cur->vip_addr_str), &vip_addr_array[0], VIP_MAX_NUM, ';'); + if (ret <= 0) { + fprintf(stdout, "vip_cfg_hander nb_vip is 0, not set vip_addr or set invalid vip_addr %s\n", + cur->vip_addr_str); + return 1; + } + + cur->nb_vip = ret; + + cur->vip_addr_array = (char **)calloc(cur->nb_vip, sizeof(char *)); + if (cur->vip_addr_array == NULL) { + fprintf(stderr, "vip_cfg_hander malloc failed\n"); + goto err; + } + + memcpy(cur->vip_addr_array, vip_addr_array, cur->nb_vip * sizeof(char *)); + + return 1; + +err: + cur->nb_vip = 0; + if (cur->vip_addr_array) { + free(cur->vip_addr_array); + cur->vip_addr_array = NULL; + } + + return 0; +} + +#ifdef INET6 +static int +vip6_cfg_hander(struct ff_port_cfg *cur) +{ + //vip6 cfg + int ret; + char *vip_addr6_array[VIP_MAX_NUM]; + + ret = rte_strsplit(cur->vip_addr6_str, strlen(cur->vip_addr6_str), + &vip_addr6_array[0], VIP_MAX_NUM, ';'); + if (ret == 0) { + fprintf(stdout, "vip6_cfg_hander nb_vip6 is 0, not set vip_addr6 or set invalid vip_addr6 %s\n", + cur->vip_addr6_str); + return 1; + } + + cur->nb_vip6 = ret; + + cur->vip_addr6_array = (char **) calloc(cur->nb_vip6, sizeof(char *)); + if (cur->vip_addr6_array == NULL) { + fprintf(stderr, "port_cfg_handler malloc failed\n"); + goto fail; + } + + memcpy(cur->vip_addr6_array, vip_addr6_array, cur->nb_vip6 * sizeof(char *)); + + return 1; + +fail: + cur->nb_vip6 = 0; + if (cur->vip_addr6_array) { + free(cur->vip_addr6_array); + cur->vip_addr6_array = NULL; + } + + return 0; +} +#endif + static int port_cfg_handler(struct ff_config *cfg, const char *section, const char *name, const char *value) { @@ -426,20 +501,29 @@ port_cfg_handler(struct ff_config *cfg, const char *section, return parse_port_lcore_list(cur, value); } else if (strcmp(name, "slave_port_list") == 0) { return parse_port_slave_list(cur, value); + } else if (strcmp(name, "vip_addr") == 0) { + cur->vip_addr_str = strdup(value); + if (cur->vip_addr_str) { + return vip_cfg_hander(cur); + } + } else if (strcmp(name, "vip_ifname") == 0) { + cur->vip_ifname = strdup(value); } #ifdef INET6 - else if (0 == strcmp(name, "addr6")) - { + else if (0 == strcmp(name, "addr6")) { cur->addr6_str = strdup(value); - } - else if (0 == strcmp(name, "prefix_len")) - { + } else if (0 == strcmp(name, "prefix_len")) { cur->prefix_len = atoi(value); - } - else if (0 == strcmp(name, "gateway6")) - { + } else if (0 == strcmp(name, "gateway6")) { cur->gateway6_str = strdup(value); + } else if (strcmp(name, "vip_addr6") == 0) { + cur->vip_addr6_str = strdup(value); + if (cur->vip_addr_str) { + return vip6_cfg_hander(cur); + } + } else if (0 == strcmp(name, "vip_prefix_len")) { + cur->vip_prefix_len = atoi(value); } #endif diff --git a/lib/ff_config.h b/lib/ff_config.h index 8bb14a6df..16990a9a1 100644 --- a/lib/ff_config.h +++ b/lib/ff_config.h @@ -44,6 +44,8 @@ extern char *dpdk_argv[DPDK_CONFIG_NUM + 1]; #define MAX_PKT_BURST 32 #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */ +#define VIP_MAX_NUM 64 + struct ff_hw_features { uint8_t rx_csum; uint8_t rx_lro; @@ -62,10 +64,20 @@ struct ff_port_cfg { char *broadcast; char *gateway; + char *vip_ifname; + char *vip_addr_str; + char **vip_addr_array; + uint32_t nb_vip; + #ifdef INET6 char *addr6_str; char *gateway6_str; uint8_t prefix_len; + + char *vip_addr6_str; + char **vip_addr6_array; + uint32_t nb_vip6; + uint8_t vip_prefix_len; #endif int nb_lcores; diff --git a/lib/ff_veth.c b/lib/ff_veth.c index 58455db0b..7d50b9ed1 100644 --- a/lib/ff_veth.c +++ b/lib/ff_veth.c @@ -69,10 +69,17 @@ struct ff_veth_softc { in_addr_t broadcast; in_addr_t gateway; + uint8_t nb_vip; + in_addr_t vip[VIP_MAX_NUM]; + #ifdef INET6 struct in6_addr ip6; struct in6_addr gateway6; uint8_t prefix_length; + + uint8_t nb_vip6; + uint8_t vip_prefix_length; + struct in6_addr vip6[VIP_MAX_NUM]; #endif /* INET6 */ struct ff_dpdk_if_context *host_ctx; @@ -81,12 +88,26 @@ struct ff_veth_softc { static int ff_veth_config(struct ff_veth_softc *sc, struct ff_port_cfg *cfg) { + int i, j; + memcpy(sc->mac, cfg->mac, ETHER_ADDR_LEN); inet_pton(AF_INET, cfg->addr, &sc->ip); inet_pton(AF_INET, cfg->netmask, &sc->netmask); inet_pton(AF_INET, cfg->broadcast, &sc->broadcast); inet_pton(AF_INET, cfg->gateway, &sc->gateway); + if (cfg->nb_vip) { + for (i = 0, j = 0; i < cfg->nb_vip; ++i) { + if (inet_pton(AF_INET, cfg->vip_addr_array[i], &sc->vip[j])) { + j++; + } else { + printf("ff_veth_config inet_pton vip %s failed.\n", cfg->vip_addr_array[i]); + } + } + + sc->nb_vip = j; + } + #ifdef INET6 if (cfg->addr6_str) { inet_pton(AF_INET6_LINUX, cfg->addr6_str, &sc->ip6); @@ -103,6 +124,19 @@ ff_veth_config(struct ff_veth_softc *sc, struct ff_port_cfg *cfg) } else { printf("%s: No addr6 config found.\n", sc->host_ifname); } + + if (cfg->nb_vip6) { + for (i = 0, j = 0; i < cfg->nb_vip6; ++i) { + if (inet_pton(AF_INET6_LINUX, cfg->vip_addr6_array[i], &sc->vip6[j])) { + j++; + } else { + printf("ff_veth_config inet_pton vip6 %s failed.\n", cfg->vip_addr6_array[i]); + } + } + + sc->nb_vip6 = j; + sc->vip_prefix_length = cfg->vip_prefix_len == 0 ? 64 : cfg->vip_prefix_len; + } #endif /* INET6 */ return 0; @@ -334,6 +368,52 @@ ff_veth_set_gateway(struct ff_veth_softc *sc) (struct sockaddr *)&nm, RTF_GATEWAY, NULL, RT_DEFAULT_FIB); } +static int +ff_veth_setvaddr(struct ff_veth_softc *sc, struct ff_port_cfg *cfg) +{ + struct in_aliasreq req; + bzero(&req, sizeof req); + + if (cfg->vip_ifname) { + strlcpy(req.ifra_name, cfg->vip_ifname, IFNAMSIZ); + } else { + strlcpy(req.ifra_name, sc->ifp->if_dname, IFNAMSIZ); + } + + struct sockaddr_in sa; + bzero(&sa, sizeof(sa)); + sa.sin_len = sizeof(sa); + sa.sin_family = AF_INET; + + int i, ret; + struct socket *so = NULL; + socreate(AF_INET, &so, SOCK_DGRAM, 0, curthread->td_ucred, curthread); + + for (i = 0; i < sc->nb_vip; ++i) { + sa.sin_addr.s_addr = sc->vip[i]; + bcopy(&sa, &req.ifra_addr, sizeof(sa)); + + // Only support '255.255.255.255' netmask now + sa.sin_addr.s_addr = 0xFFFFFFFF; + bcopy(&sa, &req.ifra_mask, sizeof(sa)); + + // Only support 'x.x.x.255' broadaddr now + sa.sin_addr.s_addr = sc->vip[i] | 0xFF000000; + bcopy(&sa, &req.ifra_broadaddr, sizeof(sa)); + + ret = ifioctl(so, SIOCAIFADDR, (caddr_t)&req, curthread); + if (ret < 0) { + printf("ff_veth_setvaddr ifioctl SIOCAIFADDR error\n"); + goto done; + } + } + +done: + sofree(so); + + return ret; +} + #ifdef INET6 static int ff_veth_setaddr6(struct ff_veth_softc *sc) @@ -351,7 +431,8 @@ ff_veth_setaddr6(struct ff_veth_softc *sc) uint8_t mask_size_mod = sc->prefix_length % 8; if (mask_size_mod) { - ifr6.ifra_prefixmask.sin6_addr.__u6_addr.__u6_addr8[sc->prefix_length / 8] = ((1 << mask_size_mod) - 1) << (8 - mask_size_mod); + ifr6.ifra_prefixmask.sin6_addr.__u6_addr.__u6_addr8[sc->prefix_length / 8] = \ + ((1 << mask_size_mod) - 1) << (8 - mask_size_mod); } ifr6.ifra_lifetime.ia6t_pltime = ifr6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; @@ -383,6 +464,52 @@ ff_veth_set_gateway6(struct ff_veth_softc *sc) return rtrequest_fib(RTM_ADD, (struct sockaddr *)&dst, (struct sockaddr *)&gw, (struct sockaddr *)&nm, RTF_GATEWAY, NULL, RT_DEFAULT_FIB); } + +static int +ff_veth_setvaddr6(struct ff_veth_softc *sc, struct ff_port_cfg *cfg) +{ + struct in6_aliasreq ifr6; + bzero(&ifr6, sizeof(ifr6)); + + if (cfg->vip_ifname) { + strlcpy(ifr6.ifra_name, cfg->vip_ifname, IFNAMSIZ); + } else { + strlcpy(ifr6.ifra_name, sc->ifp->if_dname, IFNAMSIZ); + } + + ifr6.ifra_addr.sin6_len = sizeof ifr6.ifra_addr; + ifr6.ifra_addr.sin6_family = AF_INET6; + + ifr6.ifra_prefixmask.sin6_len = sizeof ifr6.ifra_prefixmask; + memset(&ifr6.ifra_prefixmask.sin6_addr, 0xff, sc->prefix_length / 8); + uint8_t mask_size_mod = sc->prefix_length % 8; + if (mask_size_mod) + { + ifr6.ifra_prefixmask.sin6_addr.__u6_addr.__u6_addr8[sc->prefix_length / 8] = \ + ((1 << mask_size_mod) - 1) << (8 - mask_size_mod); + } + + ifr6.ifra_lifetime.ia6t_pltime = ifr6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; + + struct socket *so = NULL; + socreate(AF_INET6, &so, SOCK_DGRAM, 0, curthread->td_ucred, curthread); + + int i, ret; + for (i = 0; i < sc->nb_vip6; ++i) { + ifr6.ifra_addr.sin6_addr = sc->vip6[i]; + + ret = ifioctl(so, SIOCAIFADDR_IN6, (caddr_t)&ifr6, curthread); + if (ret < 0) { + printf("ff_veth_setvaddr6 ifioctl SIOCAIFADDR error\n"); + goto done; + } + } + +done: + sofree(so); + + return ret; +} #endif /* INET6 */ static int @@ -426,7 +553,7 @@ ff_veth_setup_interface(struct ff_veth_softc *sc, struct ff_port_cfg *cfg) return -1; } - //set ip + // Set ip int ret = ff_veth_setaddr(sc); if (ret != 0) { printf("ff_veth_setaddr failed\n"); @@ -436,6 +563,10 @@ ff_veth_setup_interface(struct ff_veth_softc *sc, struct ff_port_cfg *cfg) printf("ff_veth_set_gateway failed\n"); } + if (sc->nb_vip) { + ret = ff_veth_setvaddr(sc, cfg); + } + #ifdef INET6 // Set IPv6 if (cfg->addr6_str) { @@ -451,6 +582,10 @@ ff_veth_setup_interface(struct ff_veth_softc *sc, struct ff_port_cfg *cfg) } } } + + if (sc->nb_vip6) { + ret = ff_veth_setvaddr6(sc, cfg); + } #endif /* INET6 */ return (0);