commit 0f4d21da3457854788aec6937e6cfdf0aaf9a00a
parent 2cb07fe9501dea415aad7bfd6facbdc27585672a
Author: Robin Bron <robin@finwo.nl>
Date: Fri, 17 Feb 2023 00:22:55 +0100
Data to-and-fro single interface
Diffstat:
4 files changed, 123 insertions(+), 259 deletions(-)
diff --git a/src/config.h b/src/config.h
@@ -17,6 +17,7 @@ struct pmlag_iface {
char *name; // name of the interface this object represents
int weight; // weight of this interface within the bond
int sockfd; // file descriptor for the iface raw socket
+ int ifidx; // index of the interface within the socket
pthread_t tid; // thread id where the iface listener recides in
struct pmlag_bond *bond; // reference to the bond this iface belongs to
};
diff --git a/src/main.c b/src/main.c
@@ -29,12 +29,12 @@ static const char *const usage[] = {
void * thread_iface(void *arg) {
struct pmlag_iface *iface = (struct pmlag_iface *)arg;
- /* // Open socket for the interface in the bond */
- /* iface->sockfd = sockraw_open(iface->name); */
- /* if (iface->sockfd < 0) { */
- /* pthread_exit(NULL); */
- /* return NULL; */
- /* } */
+ // Open socket for the interface in the bond
+ iface->sockfd = sockraw_open(iface->name);
+ if (iface->sockfd < 0) {
+ pthread_exit(NULL);
+ return NULL;
+ }
// Reserve receive buffer, support 64k packets just in case
int buflen;
@@ -42,19 +42,23 @@ void * thread_iface(void *arg) {
struct sockaddr saddr;
int saddr_len = sizeof(saddr);
+ // Get the interface's idx on the socket
+ iface->ifidx = iface_idx(iface->sockfd, iface->name);
+
printf("Thread started for iface: %s->%s(%d)\n", iface->bond->name, iface->name, iface->sockfd);
- /* // Wait for the bond thread to finish initializing */
- /* pthread_mutex_lock(&(iface->bond->mtx_rt)); */
- /* pthread_mutex_unlock(&(iface->bond->mtx_rt)); */
+ // Wait for the bond thread to finish initializing
+ pthread_mutex_lock(&(iface->bond->mtx_rt));
+ pthread_mutex_unlock(&(iface->bond->mtx_rt));
// Find bond socket iface_idx
int send_len;
+ uint16_t proto;
while(1) {
// Zero out buffer, to prevent pollution, & receive packet
- memset(buffer, 0, RCVBUFSIZ);
+ /* memset(buffer, 0, RCVBUFSIZ); */
buflen = recvfrom(iface->sockfd, buffer, RCVBUFSIZ, 0, &saddr, (socklen_t *)&saddr_len);
if (buflen < 0) {
perror("recvfrom");
@@ -62,32 +66,32 @@ void * thread_iface(void *arg) {
return NULL;
}
- // TODO: track received proto=0x0666 packet to update routing table
-
- 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",buffer[0],buffer[1],buffer[2],buffer[3],buffer[ 4],buffer[ 5]);
- printf("\t|- SRC %.2X-%.2X-%.2X-%.2X-%.2X-%.2X\n",buffer[6],buffer[7],buffer[8],buffer[9],buffer[10],buffer[11]);
- printf("\t|- PROTO %.4X\n", ((int)((char)buffer[12]) << 8) + buffer[13]);
- printf("\n");
+ // Update routing table if our custom protocol is seen
+ proto = ((uint16_t)((unsigned char)buffer[12]) << 8) + buffer[13];
+ if (proto == 0x0666) {
+ pthread_mutex_lock(&(iface->bond->mtx_rt));
+ // TODO: update routing table
+ pthread_mutex_unlock(&(iface->bond->mtx_rt));
+ continue; // Don't forward the packet
+ }
- /* memset(buffer + 16, 0, buflen - 16); */
+ printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x < %.2x:%.2x:%.2x:%.2x:%.2x:%.2x, %.4x (%d)\n",
+ buffer[0],buffer[1],buffer[2],buffer[3],buffer[ 4],buffer[ 5], // DST
+ buffer[6],buffer[7],buffer[8],buffer[9],buffer[10],buffer[11], // SRC
+ ((unsigned int)((unsigned char)buffer[12]) << 8) + buffer[13], // PROTO
+ buflen
+ );
// Redirect packet to bond socket as-is
- printf("Bond iface: %d\n\n", iface->bond->sockfd);
send_len = write(iface->bond->sockfd, buffer, buflen);
- printf("Got %d, sent %d\n\n", buflen, send_len);
if (buflen != send_len) {
perror("write(bond)");
/* pthread_exit(NULL); */
/* return NULL; */
}
+
}
- /* sleep(3); */
pthread_exit(NULL);
return NULL;
}
@@ -96,37 +100,91 @@ void * thread_bond(void *arg) {
struct pmlag_bond *bond = (struct pmlag_bond *)arg;
printf("Thread started for bond: %s\n", bond->name);
- /* // Lock this bond's routing table */
- /* pthread_mutex_lock(&(bond->mtx_rt)); */
-
- /* // Initialize the bond interface */
- /* bond->sockfd = tap_alloc(bond->name); */
-
- /* // Start thread for each interface of this bond */
- /* struct pmlag_iface *iface = bond->interfaces; */
- /* while(iface) { */
- /* if(pthread_create(&(iface->tid), NULL, thread_iface, iface)) { */
- /* perror("Starting iface thread"); */
- /* pthread_exit((void*)1); */
- /* return (void*)1; */
- /* } */
- /* iface = iface->next; */
- /* } */
-
- /* // Free this bond's routing table */
- /* pthread_mutex_unlock(&(bond->mtx_rt)); */
-
- /* // TODO: blocked listen on bond, send through routing table to other ifaces */
- /* // TODO: send broadcasts to all interfaces */
- /* // TODO: timer to broadcast announce our presence to ifaces (vrrp-ish) */
- /* // hint: include sequence id, so tracking can react quickly (seq dist > 1) */
-
- /* // Wait for iface threads to finish */
- /* iface = bond->interfaces; */
- /* while(iface) { */
- /* pthread_join(iface->tid, NULL); */
- /* iface = iface->next; */
- /* } */
+ // Assign bond interface
+ unsigned char *mac = iface_mac(bond->interfaces->name);
+ bond->sockfd = tap_alloc(bond->name, mac);
+ free(mac);
+ if (bond->sockfd < 0) {
+ perror("Allocating bond interface");
+ pthread_exit(NULL);
+ return NULL;
+ };
+
+ // Lock this bond's routing table
+ pthread_mutex_lock(&(bond->mtx_rt));
+
+ // Start thread for each interface of this bond
+ struct pmlag_iface *iface = bond->interfaces;
+ while(iface) {
+ if(pthread_create(&(iface->tid), NULL, thread_iface, iface)) {
+ perror("Starting iface thread");
+ pthread_exit((void*)1);
+ return (void*)1;
+ }
+ iface = iface->next;
+ }
+
+ // Give iface threads time to run into the lock
+ /* sleep(1); */
+
+ // Free this bond's routing table
+ pthread_mutex_unlock(&(bond->mtx_rt));
+
+ int buflen, send_len;
+ unsigned char *buffer = (unsigned char *) malloc(RCVBUFSIZ);
+ struct sockaddr_ll saddr_ll;
+ saddr_ll.sll_halen = ETH_ALEN;
+
+ while(1) {
+ /* sleep(1); */
+
+ buflen = read(bond->sockfd, buffer, RCVBUFSIZ);
+ if (buflen < 0) {
+ perror("read(bond)");
+ pthread_exit(NULL);
+ return NULL;
+ }
+
+ /* printf("\n"); */
+ /* printf("Got packet: %d bytes\n", buflen); */
+
+ /* printf("Ethernet header\n"); */
+ printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x > %.2x:%.2x:%.2x:%.2x:%.2x:%.2x, %.4x (%d)\n",
+ buffer[6],buffer[7],buffer[8],buffer[9],buffer[10],buffer[11], // SRC
+ buffer[0],buffer[1],buffer[2],buffer[3],buffer[ 4],buffer[ 5], // DST
+ ((unsigned int)((unsigned char)buffer[12]) << 8) + buffer[13], // PROTO
+ buflen
+ );
+
+ // Select interface from routing table
+ // DEBUG: only the first iface
+ iface = bond->interfaces;
+
+ // Prepare saddr_ll for sendto
+ saddr_ll.sll_ifindex = iface->ifidx;
+ memcpy(saddr_ll.sll_addr, buffer, ETH_ALEN);
+
+ // Forward packet to iface as-is
+ send_len = sendto(iface->sockfd, buffer, buflen, 0, (const struct sockaddr*)&saddr_ll, sizeof(struct sockaddr_ll));
+ if(send_len != buflen) {
+ perror("sendto");
+ /* pthread_exit(NULL); */
+ /* return NULL; */
+ }
+
+ }
+
+ // TODO: send through routing table to other ifaces
+ // TODO: send broadcasts to all interfaces
+ // TODO: timer to broadcast announce our presence to ifaces (vrrp-ish)
+ // hint: include sequence id, so tracking can react quickly (seq dist > 1)
+
+ // Wait for iface threads to finish
+ iface = bond->interfaces;
+ while(iface) {
+ pthread_join(iface->tid, NULL);
+ iface = iface->next;
+ }
pthread_exit(NULL);
return NULL;
@@ -161,28 +219,6 @@ int main(int argc, const char **argv) {
// Initialize interfaces for all configured bonds
struct pmlag_bond *bond = config->bonds;
- struct pmlag_iface *iface;
- unsigned char *mac;
- while(bond) {
-
- mac = iface_mac(bond->interfaces->name);
- bond->sockfd = tap_alloc(bond->name, mac);
- free(mac);
- if (bond->sockfd < 0) return 3;
-
- iface = bond->interfaces;
- while(iface) {
- iface->sockfd = sockraw_open(iface->name);
- if (iface->sockfd < 0) return 2;
- iface = iface->next;
- }
-
- bond = bond->next;
- }
-
-
- // For each bond of config->bonds
- bond = config->bonds;
while(bond) {
// Initialize routing table lock
@@ -191,22 +227,13 @@ int main(int argc, const char **argv) {
return 1;
}
+
// Start the bond's thread
if(pthread_create(&(bond->tid), NULL, thread_bond, bond)) {
perror("Starting bond thread");
return 1;
}
- // Start a thread for each interface
- iface = bond->interfaces;
- while(iface) {
- if(pthread_create(&(iface->tid), NULL, thread_iface, iface)) {
- perror("Starting iface thread");
- return 1;
- }
- iface = iface->next;
- }
-
bond = bond->next;
}
@@ -214,174 +241,8 @@ int main(int argc, const char **argv) {
bond = config->bonds;
while(bond) {
pthread_join(bond->tid, NULL);
- iface = bond->interfaces;
- while(iface) {
- pthread_join(iface->tid, NULL);
- iface = iface->next;
- }
bond = bond->next;
}
-
-
-
-
- /* int sockfd = sockraw_open(INTERFACE); */
- /* if (sockfd < 0) { */
- /* return 1; */
- /* } */
-
- /* 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) { */
- /* 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); */
- /* /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, 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); */
- /* printf("sock: %d\n", sockfd); */
-
return 0;
}
diff --git a/src/socket.c b/src/socket.c
@@ -16,13 +16,13 @@
unsigned char * iface_mac(char * ifname) {
struct ifreq ifr;
- unsigned char *mac = calloc(1, ETH_HLEN);
+ unsigned char *mac = calloc(1, ETH_ALEN);
int sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
ifr.ifr_addr.sa_family = AF_PACKET;
strncpy(ifr.ifr_name , ifname , IFNAMSIZ-1);
ioctl(sockfd, SIOCGIFHWADDR, &ifr);
close(sockfd);
- memcpy(mac, ifr.ifr_hwaddr.sa_data, ETH_HLEN);
+ memcpy(mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
return mac;
}
@@ -94,7 +94,7 @@ int tap_alloc(char * ifname, unsigned char * mac) {
// Bring up the interface
memset(&ifr, 0, sizeof(ifr));
- ifr.ifr_flags = IFF_TAP | IFF_NAPI | IFF_MULTI_QUEUE;
+ ifr.ifr_flags = IFF_TAP | IFF_MULTI_QUEUE | IFF_NO_PI;
if( *ifname ) {
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
}
@@ -104,7 +104,7 @@ int tap_alloc(char * ifname, unsigned char * mac) {
/* memset(&ifr, 0, sizeof(ifr)); */
/* strcpy(ifr.ifr_name, ifname); */
/* ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; */
- /* memcpy(ifr.ifr_hwaddr.sa_data, mac, ETH_HLEN); */
+ /* memcpy(ifr.ifr_hwaddr.sa_data, mac, ETH_ALEN); */
/* if ((err = if_ioctl(SIOCSIFHWADDR, &ifr)) < 0) { */
/* perror("Set if hwaddr"); */
/* close(fd); */
diff --git a/test.ini b/test.ini
@@ -3,7 +3,9 @@
; eth0 = backup, eth1 = primary
[bond0]
mode=active-backup
-interface=wlp170s0
+interface=virbr3
+; interface=wlp170s0
+; interface=docker0
weight=10
; ; broadcast everything on all interfaces