#include <stdint.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include <inttypes.h>
#include <getopt.h>
#include <termios.h>
#include <unistd.h>
#include <pthread.h>
#include <cmdline_rdline.h>
#include <cmdline_parse.h>
#include <cmdline_parse_num.h>
#include <cmdline_parse_string.h>
#include <cmdline_parse_ipaddr.h>
#include <cmdline_parse_etheraddr.h>
#include <cmdline_socket.h>
#include "main.h"
#define RTE_LOGTYPE_DCB RTE_LOGTYPE_USER1
#define NB_MBUF (1024*8)
#define MAX_PKT_BURST 32
#define BURST_TX_DRAIN_US 100
#define BURST_RX_INTERVAL_NS (10)
#define RX_PTHRESH 8
#define RX_HTHRESH 8
#define RX_WTHRESH 4
#define RX_FTHRESH (MAX_PKT_BURST * 2)
#define TX_PTHRESH 36
#define TX_HTHRESH 0
#define TX_WTHRESH 0
#define RTE_RX_DESC_DEFAULT 1024
#define RTE_TX_DESC_DEFAULT 1024
#define BOND_IP_1 7
#define BOND_IP_2 0
#define BOND_IP_3 0
#define BOND_IP_4 10
#ifndef NIPQUAD
#define NIPQUAD_FMT "%u.%u.%u.%u"
#endif
#define MAX_PORTS 4
#define PRINT_MAC(addr) printf("%02"PRIx8":%02"PRIx8":%02"PRIx8 \
":%02"PRIx8":%02"PRIx8":%02"PRIx8, \
addr.addr_bytes[0], addr.addr_bytes[1], addr.addr_bytes[2], \
addr.addr_bytes[3], addr.addr_bytes[4], addr.addr_bytes[5])
uint16_t slaves[RTE_MAX_ETHPORTS];
uint16_t slaves_count;
static uint16_t BOND_PORT = 0xffff;
.split_hdr_size = 0,
},
.rx_adv_conf = {
.rss_conf = {
.rss_key = NULL,
.rss_hf = ETH_RSS_IP,
},
},
.txmode = {
},
};
static void
slave_port_init(uint16_t portid,
struct rte_mempool *mbuf_pool)
{
int retval;
uint16_t nb_rxd = RTE_RX_DESC_DEFAULT;
uint16_t nb_txd = RTE_TX_DESC_DEFAULT;
rte_exit(EXIT_FAILURE,
"Invalid port\n");
dev_info.flow_type_rss_offloads;
printf("Port %u modified RSS hash function based on hardware support,"
"requested:%#"PRIx64" configured:%#"PRIx64"\n",
portid,
}
if (retval != 0)
rte_exit(EXIT_FAILURE,
"port %u: configuration failed (res=%d)\n",
portid, retval);
if (retval != 0)
rte_exit(EXIT_FAILURE,
"port %u: rte_eth_dev_adjust_nb_rx_tx_desc " "failed (res=%d)\n", portid, retval);
rxq_conf = dev_info.default_rxconf;
&rxq_conf,
mbuf_pool);
if (retval < 0)
rte_exit(retval,
" port %u: RX queue 0 setup failed (res=%d)",
portid, retval);
txq_conf = dev_info.default_txconf;
if (retval < 0)
rte_exit(retval,
"port %u: TX queue 0 setup failed (res=%d)",
portid, retval);
if (retval < 0)
"Start port %d failed (res=%d)",
portid, retval);
printf("Port %u MAC: ", portid);
PRINT_MAC(addr);
printf("\n");
}
static void
{
int retval;
uint8_t i;
uint16_t nb_rxd = RTE_RX_DESC_DEFAULT;
uint16_t nb_txd = RTE_TX_DESC_DEFAULT;
uint16_t wait_counter = 20;
0 );
if (retval < 0)
"Faled to create bond port\n");
BOND_PORT = retval;
if (retval != 0)
rte_exit(EXIT_FAILURE,
"port %u: configuration failed (res=%d)\n",
BOND_PORT, retval);
if (retval != 0)
rte_exit(EXIT_FAILURE,
"port %u: rte_eth_dev_adjust_nb_rx_tx_desc " "failed (res=%d)\n", BOND_PORT, retval);
for (i = 0; i < slaves_count; i++) {
rte_exit(-1,
"Oooops! adding slave (%u) to bond (%u) failed!\n",
slaves[i], BOND_PORT);
}
rxq_conf = dev_info.default_rxconf;
&rxq_conf, mbuf_pool);
if (retval < 0)
rte_exit(retval,
" port %u: RX queue 0 setup failed (res=%d)",
BOND_PORT, retval);
txq_conf = dev_info.default_txconf;
if (retval < 0)
rte_exit(retval,
"port %u: TX queue 0 setup failed (res=%d)",
BOND_PORT, retval);
if (retval < 0)
rte_exit(retval,
"Start port %d failed (res=%d)", BOND_PORT, retval);
printf("Waiting for slaves to become active...");
while (wait_counter) {
uint16_t act_slaves[16] = {0};
slaves_count) {
printf("\n");
break;
}
sleep(1);
printf("...");
if (--wait_counter == 0)
rte_exit(-1,
"\nFailed to activate slaves\n");
}
printf("Port %u MAC: ", (unsigned)BOND_PORT);
PRINT_MAC(addr);
printf("\n");
}
static inline size_t
{
size_t vlan_offset = 0;
vlan_hdr = vlan_hdr + 1;
}
}
return vlan_offset;
}
struct global_flag_stru_t {
int LcoreMainIsRunning;
int LcoreMainCore;
uint32_t port_packets[4];
};
struct global_flag_stru_t global_flag_stru;
struct global_flag_stru_t *global_flag_stru_p = &global_flag_stru;
static int lcore_main(__attribute__((unused)) void *arg1)
{
uint16_t ether_type, offset;
uint16_t rx_cnt;
uint32_t bond_ip;
int i = 0;
uint8_t is_free;
bond_ip = BOND_IP_1 | (BOND_IP_2 << 8) |
(BOND_IP_3 << 16) | (BOND_IP_4 << 24);
while (global_flag_stru_p->LcoreMainIsRunning) {
is_free = 0;
if (rx_cnt == 0) {
continue;
}
for (i = 0; i < rx_cnt; i++) {
global_flag_stru_p->port_packets[0]++;
}
printf("VLAN taged frame, offset:");
offset = get_vlan_offset(eth_hdr, ðer_type);
if (offset > 0)
printf("%d\n", offset);
global_flag_stru_p->port_packets[1]++;
}
(char *)(eth_hdr + 1) + offset);
if (arp_hdr->
arp_data.
arp_tip == bond_ip) {
arp_hdr->arp_data.
arp_sip = bond_ip;
is_free = 1;
} else {
}
}
global_flag_stru_p->port_packets[2]++;
}
ipv4_hdr = (
struct rte_ipv4_hdr *)((
char *)(eth_hdr + 1) + offset);
}
}
if (is_free == 0)
}
}
printf("BYE lcore_main\n");
return 0;
}
struct cmd_obj_send_result {
cmdline_fixed_string_t action;
cmdline_ipaddr_t ip;
};
static inline void get_string(struct cmd_obj_send_result *res, char *buf, uint8_t size)
{
snprintf(buf, size, NIPQUAD_FMT,
((unsigned)((unsigned char *)&(res->ip.addr.ipv4))[0]),
((unsigned)((unsigned char *)&(res->ip.addr.ipv4))[1]),
((unsigned)((unsigned char *)&(res->ip.addr.ipv4))[2]),
((unsigned)((unsigned char *)&(res->ip.addr.ipv4))[3])
);
}
static void cmd_obj_send_parsed(void *parsed_result,
__attribute__((unused)) struct cmdline *cl,
__attribute__((unused)) void *data)
{
struct cmd_obj_send_result *res = parsed_result;
char ip_str[INET6_ADDRSTRLEN];
uint32_t bond_ip;
size_t pkt_size;
if (res->ip.family == AF_INET)
get_string(res, ip_str, INET_ADDRSTRLEN);
else
cmdline_printf(cl, "Wrong IP format. Only IPv4 is supported\n");
bond_ip = BOND_IP_1 | (BOND_IP_2 << 8) |
(BOND_IP_3 << 16) | (BOND_IP_4 << 24);
if (created_pkt == NULL) {
cmdline_printf(cl, "Failed to allocate mbuf\n");
return;
}
arp_hdr->
arp_plen =
sizeof(uint32_t);
arp_hdr->arp_data.
arp_sip = bond_ip;
((unsigned char *)&res->ip.addr.ipv4)[0] |
(((unsigned char *)&res->ip.addr.ipv4)[1] << 8) |
(((unsigned char *)&res->ip.addr.ipv4)[2] << 16) |
(((unsigned char *)&res->ip.addr.ipv4)[3] << 24);
cmdline_printf(cl, "\n");
}
cmdline_parse_token_string_t cmd_obj_action_send =
TOKEN_STRING_INITIALIZER(struct cmd_obj_send_result, action, "send");
cmdline_parse_token_ipaddr_t cmd_obj_ip =
TOKEN_IPV4_INITIALIZER(struct cmd_obj_send_result, ip);
cmdline_parse_inst_t cmd_obj_send = {
.f = cmd_obj_send_parsed,
.data = NULL,
.help_str = "send client_ip",
.tokens = {
(void *)&cmd_obj_action_send,
(void *)&cmd_obj_ip,
NULL,
},
};
struct cmd_start_result {
cmdline_fixed_string_t start;
};
static void cmd_start_parsed(__attribute__((unused)) void *parsed_result,
struct cmdline *cl,
__attribute__((unused)) void *data)
{
if (global_flag_stru_p->LcoreMainIsRunning == 0) {
return;
}
} else {
cmdline_printf(cl, "lcore_main already running on core:%d\n",
global_flag_stru_p->LcoreMainCore);
return;
}
if ((slave_core_id >= RTE_MAX_LCORE) || (slave_core_id == 0))
return;
global_flag_stru_p->LcoreMainIsRunning = 1;
cmdline_printf(cl,
"Starting lcore_main on core %d:%d "
"Our IP:%d.%d.%d.%d\n",
slave_core_id,
BOND_IP_1,
BOND_IP_2,
BOND_IP_3,
BOND_IP_4
);
}
cmdline_parse_token_string_t cmd_start_start =
TOKEN_STRING_INITIALIZER(struct cmd_start_result, start, "start");
cmdline_parse_inst_t cmd_start = {
.f = cmd_start_parsed,
.data = NULL,
.help_str = "starts listening if not started at startup",
.tokens = {
(void *)&cmd_start_start,
NULL,
},
};
struct cmd_help_result {
cmdline_fixed_string_t help;
};
static void cmd_help_parsed(__attribute__((unused)) void *parsed_result,
struct cmdline *cl,
__attribute__((unused)) void *data)
{
cmdline_printf(cl,
"ALB - link bonding mode 6 example\n"
"send IP - sends one ARPrequest through bonding for IP.\n"
"start - starts listening ARPs.\n"
"stop - stops lcore_main.\n"
"show - shows some bond info: ex. active slaves etc.\n"
"help - prints help.\n"
"quit - terminate all threads and quit.\n"
);
}
cmdline_parse_token_string_t cmd_help_help =
TOKEN_STRING_INITIALIZER(struct cmd_help_result, help, "help");
cmdline_parse_inst_t cmd_help = {
.f = cmd_help_parsed,
.data = NULL,
.help_str = "show help",
.tokens = {
(void *)&cmd_help_help,
NULL,
},
};
struct cmd_stop_result {
cmdline_fixed_string_t stop;
};
static void cmd_stop_parsed(__attribute__((unused)) void *parsed_result,
struct cmdline *cl,
__attribute__((unused)) void *data)
{
if (global_flag_stru_p->LcoreMainIsRunning == 0) {
cmdline_printf(cl,
"lcore_main not running on core:%d\n",
global_flag_stru_p->LcoreMainCore);
return;
}
global_flag_stru_p->LcoreMainIsRunning = 0;
cmdline_printf(cl,
"error: lcore_main can not stop on core:%d\n",
global_flag_stru_p->LcoreMainCore);
else
cmdline_printf(cl,
"lcore_main stopped on core:%d\n",
global_flag_stru_p->LcoreMainCore);
}
cmdline_parse_token_string_t cmd_stop_stop =
TOKEN_STRING_INITIALIZER(struct cmd_stop_result, stop, "stop");
cmdline_parse_inst_t cmd_stop = {
.f = cmd_stop_parsed,
.data = NULL,
.help_str = "this command do not handle any arguments",
.tokens = {
(void *)&cmd_stop_stop,
NULL,
},
};
struct cmd_quit_result {
cmdline_fixed_string_t quit;
};
static void cmd_quit_parsed(__attribute__((unused)) void *parsed_result,
struct cmdline *cl,
__attribute__((unused)) void *data)
{
if (global_flag_stru_p->LcoreMainIsRunning == 0) {
cmdline_printf(cl,
"lcore_main not running on core:%d\n",
global_flag_stru_p->LcoreMainCore);
cmdline_quit(cl);
return;
}
global_flag_stru_p->LcoreMainIsRunning = 0;
cmdline_printf(cl,
"error: lcore_main can not stop on core:%d\n",
global_flag_stru_p->LcoreMainCore);
else
cmdline_printf(cl,
"lcore_main stopped on core:%d\n",
global_flag_stru_p->LcoreMainCore);
cmdline_quit(cl);
}
cmdline_parse_token_string_t cmd_quit_quit =
TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, "quit");
cmdline_parse_inst_t cmd_quit = {
.f = cmd_quit_parsed,
.data = NULL,
.help_str = "this command do not handle any arguments",
.tokens = {
(void *)&cmd_quit_quit,
NULL,
},
};
struct cmd_show_result {
cmdline_fixed_string_t show;
};
static void cmd_show_parsed(__attribute__((unused)) void *parsed_result,
struct cmdline *cl,
__attribute__((unused)) void *data)
{
uint16_t slaves[16] = {0};
uint8_t len = 16;
uint16_t i = 0;
while (i < slaves_count) {
PRINT_MAC(addr);
printf("\n");
i++;
}
cmdline_printf(cl,
"Active_slaves:%d "
"packets received:Tot:%d Arp:%d IPv4:%d\n",
global_flag_stru_p->port_packets[0],
global_flag_stru_p->port_packets[1],
global_flag_stru_p->port_packets[2]);
}
cmdline_parse_token_string_t cmd_show_show =
TOKEN_STRING_INITIALIZER(struct cmd_show_result, show, "show");
cmdline_parse_inst_t cmd_show = {
.f = cmd_show_parsed,
.data = NULL,
.help_str = "this command do not handle any arguments",
.tokens = {
(void *)&cmd_show_show,
NULL,
},
};
cmdline_parse_ctx_t main_ctx[] = {
(cmdline_parse_inst_t *)&cmd_start,
(cmdline_parse_inst_t *)&cmd_obj_send,
(cmdline_parse_inst_t *)&cmd_stop,
(cmdline_parse_inst_t *)&cmd_show,
(cmdline_parse_inst_t *)&cmd_quit,
(cmdline_parse_inst_t *)&cmd_help,
NULL,
};
static void prompt(__attribute__((unused)) void *arg1)
{
struct cmdline *cl;
cl = cmdline_stdin_new(main_ctx, "bond6>");
if (cl != NULL) {
cmdline_interact(cl);
cmdline_stdin_exit(cl);
}
}
int
main(int argc, char *argv[])
{
int ret, slave_core_id;
uint16_t nb_ports, i;
if (ret < 0)
rte_exit(EXIT_FAILURE,
"Error with EAL initialization\n");
argc -= ret;
argv += ret;
if (nb_ports == 0)
rte_exit(EXIT_FAILURE,
"Give at least one port\n");
else if (nb_ports > MAX_PORTS)
rte_exit(EXIT_FAILURE,
"You can have max 4 ports\n");
if (mbuf_pool == NULL)
rte_exit(EXIT_FAILURE,
"Cannot create mbuf pool\n");
slaves_count = nb_ports;
slave_port_init(i, mbuf_pool);
slaves[i] = i;
}
bond_port_init(mbuf_pool);
return -EBUSY;
}
if ((slave_core_id >= RTE_MAX_LCORE) || (slave_core_id == 0))
return -EPERM;
global_flag_stru_p->LcoreMainIsRunning = 1;
global_flag_stru_p->LcoreMainCore = slave_core_id;
printf("Starting lcore_main on core %d:%d Our IP:%d.%d.%d.%d\n",
slave_core_id,
NULL,
slave_core_id),
BOND_IP_1,
BOND_IP_2,
BOND_IP_3,
BOND_IP_4
);
prompt(NULL);
return 0;
}