pmlag

Poor man's link aggregation
git clone git://git.finwo.net/app/pmlag
Log | Files | Refs | README | LICENSE

commit 31b387ee9181a0e68ba721b9fde30167f918b66c
parent 561808954072dde134799b285f34137edec093c3
Author: Robin Bron <robin@finwo.nl>
Date:   Sat, 11 Feb 2023 21:44:12 +0100

Verified packet tx and rx over physical adapters

Diffstat:
Msrc/config.h | 4+++-
Msrc/main.c | 323+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mtest.ini | 28++++++++++++++--------------
3 files changed, 191 insertions(+), 164 deletions(-)

diff --git a/src/config.h b/src/config.h @@ -15,7 +15,8 @@ extern "C" { struct pmlag_iface { void *next; char *name; - int weight; + int weight; + int sockfd; pthread_t tid; struct pmlag_bond *bond; }; @@ -24,6 +25,7 @@ struct pmlag_bond { void *next; char *name; int mode; + int sockfd; pthread_t tid; struct pmlag_iface *interfaces; }; diff --git a/src/main.c b/src/main.c @@ -17,7 +17,7 @@ #include "config.h" #include "socket.h" -#define INTERFACE "docker0" +#define INTERFACE "enp0s13f0u2c2" static const char *const usage[] = { __NAME " [options]", @@ -26,7 +26,9 @@ static const char *const usage[] = { void * thread_iface(void *arg) { struct pmlag_iface *iface = (struct pmlag_iface *)arg; - printf("Thread started for iface: %s->%s\n", iface->bond->name, iface->name); + + int sockfd = sockraw_open(iface->name); + printf("Thread started for iface: %s->%s(%d)\n", iface->bond->name, iface->name, sockfd); // TODO: open raw socket on iface // TODO: blocking listen on iface, send to bond @@ -72,10 +74,15 @@ void * thread_bond(void *arg) { int main(int argc, const char **argv) { char *config_file="/etc/pmlag/pmlag.ini"; + int rx = 0; + int tx = 0; + // Define which options we support struct argparse_option options[] = { OPT_HELP(), OPT_STRING('c', "config", &config_file, "Config file to use", NULL, 0, 0), + OPT_BOOLEAN('t', "tx", &tx, "Send a message", NULL, 0, 0), + OPT_BOOLEAN('r', "rx", &rx, "eth dump", NULL, 0, 0), OPT_END(), }; @@ -90,164 +97,182 @@ int main(int argc, const char **argv) { ); argc = argparse_parse(&argparse, argc, argv); - // Load configuration file - struct pmlag_configuration *config = config_load(config_file); - if (!config) { - return 1; - } + /* // Load configuration file */ + /* struct pmlag_configuration *config = config_load(config_file); */ + /* if (!config) { */ + /* return 1; */ + /* } */ - // For each bond of config->bonds - struct pmlag_bond *bond = config->bonds; - while(bond) { - if(pthread_create(&(bond->tid), NULL, thread_bond, bond)) { - perror("Starting bond thread"); - return 1; - } - bond = bond->next; - } + /* // For each bond of config->bonds */ + /* struct pmlag_bond *bond = config->bonds; */ + /* while(bond) { */ + /* if(pthread_create(&(bond->tid), NULL, thread_bond, bond)) { */ + /* perror("Starting bond thread"); */ + /* return 1; */ + /* } */ + /* bond = bond->next; */ + /* } */ - // Wait for all bonds to finish - bond = config->bonds; - while(bond) { - pthread_join(bond->tid, NULL); - bond = bond->next; - } + /* // Wait for all bonds to finish */ + /* bond = config->bonds; */ + /* while(bond) { */ + /* pthread_join(bond->tid, NULL); */ + /* bond = bond->next; */ + /* } */ + int sockfd; /* int sockfd = sockraw_open(INTERFACE); */ /* if (sockfd < 0) { */ /* return 1; */ /* } */ - /* if (rx) { */ - -/* // Prepare ingress buffer */ -/* int buflen; */ -/* unsigned char *buffer = (unsigned char *) malloc(65536); */ -/* memset(buffer, 0, 65536); */ -/* struct sockaddr saddr; */ -/* int saddr_len = sizeof(saddr); */ - -/* struct ethhdr *eth = (struct ethhdr *)(buffer); */ -/* struct sockaddr_in source; */ -/* struct sockaddr_in dest; */ - -/* while(1) { */ - -/* // Fetch a packet */ -/* buflen = recvfrom(sockfd, buffer, 65536, 0, &saddr, (socklen_t *)&saddr_len); */ -/* if (buflen < 0) { */ -/* perror("recvfrom"); */ -/* exit(EXIT_FAILURE); */ -/* } */ - -/* printf("\n"); */ -/* printf("Got packet: %d bytes\n", buflen); */ -/* printf("\n"); */ - -/* printf("Ethernet header\n"); */ -/* printf("\t|- DST %.2X-%.2X-%.2X-%.2X-%.2X-%.2X\n",eth->h_dest[0],eth->h_dest[1],eth->h_dest[2],eth->h_dest[3],eth->h_dest[4],eth->h_dest[5]); */ -/* printf("\t|- SRC %.2X-%.2X-%.2X-%.2X-%.2X-%.2X\n",eth->h_source[0],eth->h_source[1],eth->h_source[2],eth->h_source[3],eth->h_source[4],eth->h_source[5]); */ -/* printf("\t|- PROTO %.4X\n",be16toh(eth->h_proto)); */ - -/* printf("\n"); */ - -/* if (be16toh(eth->h_proto) == 0x0800) { */ -/* unsigned short iphdrlen; */ -/* struct iphdr *ip = (struct iphdr*)(buffer + sizeof(struct ethhdr)); */ -/* memset(&source, 0, sizeof(source)); */ -/* source.sin_addr.s_addr = ip->saddr; */ -/* memset(&dest, 0, sizeof(dest)); */ -/* dest.sin_addr.s_addr = ip->daddr; */ - -/* printf("IP header\n"); */ -/* printf("\t|- Version %d\n",(unsigned int)ip->version); */ -/* printf("\t|- Internet hlen %d DWORDS or %d Bytes\n",(unsigned int)ip->ihl,((unsigned int)(ip->ihl))*4); */ -/* printf("\t|- Type Of Service %d\n",(unsigned int)ip->tos); */ -/* printf("\t|- Total Length %d Bytes\n",ntohs(ip->tot_len)); */ -/* printf("\t|- Identification %d\n",ntohs(ip->id)); */ -/* printf("\t|- Time To Live %d\n",(unsigned int)ip->ttl); */ -/* printf("\t|- Protocol %d\n",(unsigned int)ip->protocol); */ -/* printf("\t|- Header Checksum %d\n",ntohs(ip->check)); */ -/* printf("\t|- Source IP %s\n", inet_ntoa(source.sin_addr)); */ -/* printf("\t|- Destination IP %s\n",inet_ntoa(dest.sin_addr)); */ - -/* printf("\n"); */ -/* } */ - -/* } */ + if (rx) { + sockfd = sockraw_open("enp0s13f0u1c2"); + if (sockfd < 0) { + return 1; + } - /* } */ + // Prepare ingress buffer + int buflen; + unsigned char *buffer = (unsigned char *) malloc(65536); + memset(buffer, 0, 65536); + struct sockaddr saddr; + int saddr_len = sizeof(saddr); + + struct ethhdr *eth = (struct ethhdr *)(buffer); + struct sockaddr_in source; + struct sockaddr_in dest; + + while(1) { + + // Fetch a packet + buflen = recvfrom(sockfd, buffer, 65536, 0, &saddr, (socklen_t *)&saddr_len); + if (buflen < 0) { + perror("recvfrom"); + exit(EXIT_FAILURE); + } + + printf("\n"); + printf("Got packet: %d bytes\n", buflen); + printf("\n"); + + printf("Ethernet header\n"); + printf("\t|- DST %.2X-%.2X-%.2X-%.2X-%.2X-%.2X\n",eth->h_dest[0],eth->h_dest[1],eth->h_dest[2],eth->h_dest[3],eth->h_dest[4],eth->h_dest[5]); + printf("\t|- SRC %.2X-%.2X-%.2X-%.2X-%.2X-%.2X\n",eth->h_source[0],eth->h_source[1],eth->h_source[2],eth->h_source[3],eth->h_source[4],eth->h_source[5]); + printf("\t|- PROTO %.4X\n",be16toh(eth->h_proto)); + + printf("\n"); + + if (be16toh(eth->h_proto) == 0x0800) { + unsigned short iphdrlen; + struct iphdr *ip = (struct iphdr*)(buffer + sizeof(struct ethhdr)); + memset(&source, 0, sizeof(source)); + source.sin_addr.s_addr = ip->saddr; + memset(&dest, 0, sizeof(dest)); + dest.sin_addr.s_addr = ip->daddr; + + printf("IP header\n"); + printf("\t|- Version %d\n",(unsigned int)ip->version); + printf("\t|- Internet hlen %d DWORDS or %d Bytes\n",(unsigned int)ip->ihl,((unsigned int)(ip->ihl))*4); + printf("\t|- Type Of Service %d\n",(unsigned int)ip->tos); + printf("\t|- Total Length %d Bytes\n",ntohs(ip->tot_len)); + printf("\t|- Identification %d\n",ntohs(ip->id)); + printf("\t|- Time To Live %d\n",(unsigned int)ip->ttl); + printf("\t|- Protocol %d\n",(unsigned int)ip->protocol); + printf("\t|- Header Checksum %d\n",ntohs(ip->check)); + printf("\t|- Source IP %s\n", inet_ntoa(source.sin_addr)); + printf("\t|- Destination IP %s\n",inet_ntoa(dest.sin_addr)); + + printf("\n"); + } - /* if (tx) { */ - -/* // Prepare egress buffer */ -/* int buflen; */ -/* unsigned char *buffer = (unsigned char *) malloc(65536); */ -/* memset(buffer, 0, 65536); */ -/* struct sockaddr_ll saddr; */ -/* int saddr_len = sizeof(saddr); */ - -/* // Get MAC address of the interface */ -/* struct ifreq ifreq_c; */ -/* memset(&ifreq_c,0,sizeof(ifreq_c)); */ -/* strncpy(ifreq_c.ifr_name,INTERFACE,IFNAMSIZ-1);//giving name of Interface */ -/* if((ioctl(sockfd,SIOCGIFHWADDR,&ifreq_c))<0) { */ -/* perror("error in SIOCGIFHWADDR ioctl reading"); */ -/* return 1; */ -/* } */ - -/* // Get ethhdr reference to the buffer */ -/* struct ethhdr *eth = (struct ethhdr *)(buffer); */ - -/* // Fill ethernet source address */ -/* memcpy(eth->h_source, ifreq_c.ifr_hwaddr.sa_data, 6); */ -/* /1* eth->h_source[0] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[0]); *1/ */ -/* /1* eth->h_source[1] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[1]); *1/ */ -/* /1* eth->h_source[2] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[2]); *1/ */ -/* /1* eth->h_source[3] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[3]); *1/ */ -/* /1* eth->h_source[4] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[4]); *1/ */ -/* /1* eth->h_source[5] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[5]); *1/ */ - -/* // Broadcast packet */ -/* eth->h_dest[0] = 0xFF; */ -/* eth->h_dest[1] = 0xFF; */ -/* eth->h_dest[2] = 0xFF; */ -/* eth->h_dest[3] = 0xFF; */ -/* eth->h_dest[4] = 0xFF; */ -/* eth->h_dest[5] = 0xFF; */ - -/* // Custom protocol (not shown as registered on https://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml) */ -/* eth->h_proto = htons(0x0666); */ - -/* struct sockaddr_ll sadr_ll; */ -/* sadr_ll.sll_ifindex = iface_idx(sockfd, INTERFACE); */ -/* sadr_ll.sll_halen = ETH_ALEN; // length of destination mac address */ -/* memcpy(sadr_ll.sll_addr, eth->h_dest, ETH_ALEN); */ - -/* /1* sadr_ll.sll_addr[0] = 0xFF; *1/ */ -/* /1* sadr_ll.sll_addr[1] = 0xFF; *1/ */ -/* /1* sadr_ll.sll_addr[2] = 0xFF; *1/ */ -/* /1* sadr_ll.sll_addr[3] = 0xFF; *1/ */ -/* /1* sadr_ll.sll_addr[4] = 0xFF; *1/ */ -/* /1* sadr_ll.sll_addr[5] = 0xFF; *1/ */ - -/* /1* saddr.sll_ifindex = ifreq_i.ifr_ifindex; // index of interface *1/ */ -/* /1* saddr.sll_halen = ETH_ALEN; // length of destination mac address *1/ */ -/* /1* saddr.sll_addr[0] = DESTMAC0; *1/ */ -/* /1* saddr.sll_addr[1] = DESTMAC1; *1/ */ -/* /1* saddr.sll_addr[2] = DESTMAC2; *1/ */ -/* /1* saddr.sll_addr[3] = DESTMAC3; *1/ */ -/* /1* saddr.sll_addr[4] = DESTMAC4; *1/ */ -/* /1* saddr.sll_addr[5] = DESTMAC5; *1/ */ - - -/* int send_len = sendto(sockfd,buffer,60,0,(const struct sockaddr*)&sadr_ll,sizeof(struct sockaddr_ll)); */ -/* if(send_len<0) { */ -/* printf("error in sending....sendlen=%d....errno=%d\n",send_len,errno); */ -/* return -1; */ -/* } */ + } - /* } */ + } + + if (tx) { + sockfd = sockraw_open(INTERFACE); + if (sockfd < 0) { + return 1; + } + + // Prepare egress buffer + int buflen; + unsigned char *buffer = (unsigned char *) malloc(65536); + memset(buffer, 0, 65536); + struct sockaddr_ll saddr; + int saddr_len = sizeof(saddr); + + // Get MAC address of the interface + struct ifreq ifreq_c; + memset(&ifreq_c,0,sizeof(ifreq_c)); + strncpy(ifreq_c.ifr_name,INTERFACE,IFNAMSIZ-1);//giving name of Interface + if((ioctl(sockfd,SIOCGIFHWADDR,&ifreq_c))<0) { + perror("error in SIOCGIFHWADDR ioctl reading"); + return 1; + } + + // Get ethhdr reference to the buffer + struct ethhdr *eth = (struct ethhdr *)(buffer); + + // Fill ethernet source address + memcpy(eth->h_source, ifreq_c.ifr_hwaddr.sa_data, 6); + /* eth->h_source[0] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[0]); */ + /* eth->h_source[1] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[1]); */ + /* eth->h_source[2] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[2]); */ + /* eth->h_source[3] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[3]); */ + /* eth->h_source[4] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[4]); */ + /* eth->h_source[5] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[5]); */ + + // Broadcast packet + eth->h_dest[0] = 0xFF; + eth->h_dest[1] = 0xFF; + eth->h_dest[2] = 0xFF; + eth->h_dest[3] = 0xFF; + eth->h_dest[4] = 0xFF; + eth->h_dest[5] = 0xFF; + + // Custom protocol (not shown as registered on https://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml) + eth->h_proto = htons(0x0666); + + struct sockaddr_ll sadr_ll; + sadr_ll.sll_ifindex = iface_idx(sockfd, INTERFACE); + sadr_ll.sll_halen = ETH_ALEN; // length of destination mac address + memcpy(sadr_ll.sll_addr, eth->h_dest, ETH_ALEN); + + /* sadr_ll.sll_addr[0] = 0xFF; */ + /* sadr_ll.sll_addr[1] = 0xFF; */ + /* sadr_ll.sll_addr[2] = 0xFF; */ + /* sadr_ll.sll_addr[3] = 0xFF; */ + /* sadr_ll.sll_addr[4] = 0xFF; */ + /* sadr_ll.sll_addr[5] = 0xFF; */ + + /* saddr.sll_ifindex = ifreq_i.ifr_ifindex; // index of interface */ + /* saddr.sll_halen = ETH_ALEN; // length of destination mac address */ + /* saddr.sll_addr[0] = DESTMAC0; */ + /* saddr.sll_addr[1] = DESTMAC1; */ + /* saddr.sll_addr[2] = DESTMAC2; */ + /* saddr.sll_addr[3] = DESTMAC3; */ + /* saddr.sll_addr[4] = DESTMAC4; */ + /* saddr.sll_addr[5] = DESTMAC5; */ + + + int send_len = sendto(sockfd,buffer, 12 + 2 + 46,0,(const struct sockaddr*)&sadr_ll,sizeof(struct sockaddr_ll)); + if(send_len<0) { + printf("error in sending....sendlen=%d....errno=%d\n",send_len,errno); + return -1; + } + + printf("\n"); + printf("Sent packet: %d bytes\n", send_len); + printf("\n"); + + printf("Ethernet header\n"); + printf("\t|- DST %.2X-%.2X-%.2X-%.2X-%.2X-%.2X\n",eth->h_dest[0],eth->h_dest[1],eth->h_dest[2],eth->h_dest[3],eth->h_dest[4],eth->h_dest[5]); + printf("\t|- SRC %.2X-%.2X-%.2X-%.2X-%.2X-%.2X\n",eth->h_source[0],eth->h_source[1],eth->h_source[2],eth->h_source[3],eth->h_source[4],eth->h_source[5]); + printf("\t|- PROTO %.4X\n",be16toh(eth->h_proto)); + + } /* printf("name: %s\n", __NAME); */ /* printf("conf: %s\n", config_file); */ diff --git a/test.ini b/test.ini @@ -3,21 +3,21 @@ ; eth0 = backup, eth1 = primary [bond0] mode=active-backup -interface=eth0 +interface=enp0s13f0u1c2 weight=10 -interface=eth1 +interface=enp0s13f0u2c2 weight=25 -; broadcast everything on all interfaces -[bond1] -mode=broadcast -interface=eth2 -interface=eth3 +; ; broadcast everything on all interfaces +; [bond1] +; mode=broadcast +; interface=eth2 +; interface=eth3 -; use both at the same time -[bond2] -mode=balanced-rr -interface=eth4 -weight=10 -interface=eth5 -weight=25 +; ; use both at the same time +; [bond2] +; mode=balanced-rr +; interface=eth4 +; weight=10 +; interface=eth5 +; weight=25