commit 2f6173320ae202a9f2ceb151a9c8b628dae3518d
parent 8293eaaab5b71f4acc6d13028868308c7ceab2bd
Author: Yersa Nordman <yersa@finwo.nl>
Date: Sun, 8 Oct 2023 22:11:43 +0200
raw sockets opening again; ticking implemented
Diffstat:
7 files changed, 354 insertions(+), 4 deletions(-)
diff --git a/src/main.c b/src/main.c
@@ -1,17 +1,31 @@
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
+#include <sys/epoll.h>
+#include <sys/time.h>
+#include <unistd.h>
#include "cofyc/argparse.h"
#include "util/config.h"
+#include "util/socket.h"
static const char *const usage[] = {
__NAME " [options]",
NULL
};
+int64_t millis() {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (tv.tv_sec * ((int64_t)1000)) + (tv.tv_usec / 1000);
+}
+
int main(int argc, const char **argv) {
char *config_file="/etc/pmlag/pmlag.ini";
+ struct epoll_event *epev;
+ int epfd;
+ struct pmlag_iface *iface;
// Seed random
unsigned int seed;
@@ -44,15 +58,65 @@ int main(int argc, const char **argv) {
return 1;
}
- // Display bonds
+ // Initialize epoll
+ epfd = epoll_create1(0);
int b = 0;
int i = 0;
for( b = 0 ; b < config->bond_count ; b++ ) {
+ for( i = 0 ; i < config->bond[b]->iface_count ; i++ ) {
+ iface = config->bond[b]->iface[i];
+
+ // Start a socket on the interface
+ iface->sockfd = sockraw_open(iface->name);
+ if (iface->sockfd < 0) {
+ return 2;
+ }
+ /* printf("%s: %d\n", */
+ /* iface->name, */
+ /* iface->sockfd */
+ /* ); */
+
+ epev = malloc(sizeof(struct epoll_event));
+ if (!epev) return 3;
+ epev->events = EPOLLIN;
+ epev->data.ptr = iface;
+ if (epoll_ctl(epfd, EPOLL_CTL_ADD, iface->sockfd, epev)) {
+ free(epev);
+ close(iface->sockfd);
+ iface->sockfd = 0;
+ continue;
+ }
+ iface->epev = epev;
+ }
+ }
+
+ // DEBUG: Display bonds
+ for( b = 0 ; b < config->bond_count ; b++ ) {
printf("%s\n", config->bond[b]->name);
for( i = 0 ; i < config->bond[b]->iface_count ; i++ ) {
printf(" - %s\n", config->bond[b]->iface[i]->name);
}
}
+ // Wait for things to happen & call tick methods periodically
+ int ev_count;
+ struct epoll_event events[8];
+ int64_t ttime = millis();
+ int64_t tdiff = 0;
+ while(1) {
+ ev_count = epoll_wait(epfd, events, 8, tdiff);
+ for( i=0 ; i<ev_count; i++) {
+ // TODO: process(events[i].data.ptr);
+ }
+
+ tdiff = ttime - millis();
+ if (tdiff <= 0) {
+ ttime += 1000;
+ tdiff += 1000;
+ // TODO: time tick method (for announce handling)
+ printf("ttime: %ld\n", ttime);
+ }
+ }
+
return 69;
}
diff --git a/src/util/config.c b/src/util/config.c
@@ -1,10 +1,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/epoll.h>
#include "benhoyt/inih.h"
#include "config.h"
+#include "socket.h"
static int config_load_handler(
void *user,
@@ -60,6 +62,7 @@ static int config_load_handler(
bond->iface = realloc(bond->iface, (bond->iface_count + 1) * sizeof(void*));
bond->iface[bond->iface_count ] = NULL;
iface->name = strdup(value);
+ iface->bond = bond;
}
} else if (!strcmp(name, "hwaddr")) {
@@ -72,12 +75,21 @@ static int config_load_handler(
}
}
+ if (bond->hwaddr) {
+ printf("Already had MAC: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+ bond->hwaddr[0],
+ bond->hwaddr[1],
+ bond->hwaddr[2],
+ bond->hwaddr[3],
+ bond->hwaddr[4],
+ bond->hwaddr[5]
+ );
+ }
+
if (iface) {
// Got interface by that name = use it's hwaddr
if (bond->hwaddr) free(bond->hwaddr);
- bond->hwaddr = NULL;
- /* bond->hwaddr = iface_mac(iface_entry->data->name); */
- printf("TODO: get mac from %s\n", iface->name);
+ bond->hwaddr = iface_mac(iface->name);
} else if (!strcmp(value, "random")) {
// "random" = null, a.k.a. let the kernel generate a random mac
if (bond->hwaddr) free(bond->hwaddr);
diff --git a/src/util/config.h b/src/util/config.h
@@ -3,6 +3,9 @@
struct pmlag_iface {
char *name;
+ struct pmlag_bond *bond;
+ int sockfd;
+ struct epoll_event *epev;
/* /1* int weight; // weight of this interface within the bond *1/ */
/* int sockfd; // file descriptor for the iface raw socket */
/* int ifidx; // index of the interface within the socket */
diff --git a/src/util/routing-table.c b/src/util/routing-table.c
@@ -0,0 +1,135 @@
+/* #include <linux/if_ether.h> */
+/* #include <stdio.h> */
+/* #include <stdlib.h> */
+/* #include <string.h> */
+
+/* #include "config.h" */
+/* #include "finwo/mindex.h" */
+/* #include "routing-table.h" */
+
+/* static int rt_compare(const void *a, const void *b, void *udata) { */
+/* struct pmlag_rt_entry *ta = (struct pmlag_rt_entry *)a; */
+/* struct pmlag_rt_entry *tb = (struct pmlag_rt_entry *)b; */
+/* int result; */
+
+/* // Same pointer = match */
+/* if (a == b) return 0; */
+
+/* // Check for ETH_ALEN, unrolled memcmp */
+/* if (( result = ((int)ta->mac[0] - (int)tb->mac[0]) )) return result; */
+/* if (( result = ((int)ta->mac[1] - (int)tb->mac[1]) )) return result; */
+/* if (( result = ((int)ta->mac[2] - (int)tb->mac[2]) )) return result; */
+/* if (( result = ((int)ta->mac[3] - (int)tb->mac[3]) )) return result; */
+/* if (( result = ((int)ta->mac[4] - (int)tb->mac[4]) )) return result; */
+/* return (int)ta->mac[5] - (int)tb->mac[5]; */
+/* } */
+
+/* static void rt_purge(const void *item, void *udata) { */
+/* struct pmlag_rt_entry *rt_entry = (struct pmlag_rt_entry *)item; */
+/* free(rt_entry->interfaces); */
+/* free(rt_entry->mac); */
+/* free(rt_entry); */
+/* } */
+
+/* struct mindex_t * rt_init(void *udata) { */
+/* return mindex_init(rt_compare, rt_purge, udata); */
+/* } */
+
+/* int rt_upsert( */
+/* struct mindex_t *rt, */
+/* pthread_mutex_t *mtx, */
+/* struct pmlag_iface *iface, */
+/* unsigned char *mac, */
+/* int16_t bcidx */
+/* ) { */
+/* int isnew = 0; */
+/* struct pmlag_rt_entry *rt_entry; */
+
+/* // Lock the routing table */
+/* pthread_mutex_lock(mtx); */
+
+/* // Attempt to fetch the rt entry */
+/* rt_entry = mindex_get(rt, &((struct pmlag_rt_entry){ .mac = mac })); */
+
+/* // None given, build new one */
+/* if (!rt_entry) { */
+/* rt_entry = calloc(1, sizeof(struct pmlag_rt_entry)); */
+/* rt_entry->mac = malloc(ETH_ALEN); */
+/* rt_entry->bcidx = 0; */
+/* rt_entry->interfaces = calloc(iface->bond->iface_cnt, sizeof(struct pmlag_iface *)); */
+/* memcpy(rt_entry->mac, mac, ETH_ALEN); */
+/* isnew = 1; */
+/* } */
+
+/* // Bail if */
+/* if ( */
+/* (!bcidx && rt_entry->bcidx) || // We receive a regular packet on bcidx-tracked entry */
+/* (rt_entry->bcidx && ((bcidx - rt_entry->bcidx) < 0)) // Or the received bcidx is lower than known (old packet) */
+/* ) { */
+/* if (isnew) { */
+/* rt_purge(rt_entry, NULL); */
+/* } */
+/* pthread_mutex_unlock(mtx); */
+/* return 0; */
+/* } */
+
+/* // Clear list of known interfaces if */
+/* if ( */
+/* (bcidx && (rt_entry->bcidx != bcidx)) || // We got a NEW broadcast index */
+/* (!bcidx && (rt_entry->bcidx == 0)) // Or we're updating a non-pmlag remote */
+/* ) { */
+/* rt_entry->iface_cnt = 0; */
+/* } */
+
+/* // Update the rt_entry's broadcast index */
+/* rt_entry->bcidx = bcidx; */
+
+/* // Bail if rt_entry->iface_cnt+1 lg bond->iface_cnt */
+/* if ((rt_entry->iface_cnt + 1) > iface->bond->iface_cnt) { */
+/* if (isnew) { */
+/* rt_purge(rt_entry, NULL); */
+/* } */
+/* pthread_mutex_unlock(mtx); */
+/* return 0; */
+/* } */
+
+/* // Add our iface to the entry's interface list */
+/* rt_entry->interfaces[rt_entry->iface_cnt] = iface; */
+/* rt_entry->iface_cnt++; */
+
+/* // Ensure the entry is in the rt */
+/* if (isnew) { */
+/* mindex_set(rt, rt_entry); */
+/* } */
+
+/* if (mindex_length(rt) > RT_MAX_ENTRIES) { */
+/* rt_entry = mindex_rand(rt); */
+/* if (rt_entry) { */
+/* mindex_delete(rt, rt_entry); */
+/* } */
+/* } */
+
+/* pthread_mutex_unlock(mtx); */
+/* return 0; */
+/* } */
+
+/* struct pmlag_iface * rt_find( */
+/* struct mindex_t *rt, */
+/* pthread_mutex_t *mtx, */
+/* unsigned char *mac */
+/* ) { */
+/* struct pmlag_rt_entry *rt_entry; */
+
+/* // Attempt to fetch the rt entry */
+/* pthread_mutex_lock(mtx); */
+/* rt_entry = mindex_get(rt, &((struct pmlag_rt_entry){ .mac = mac })); */
+/* if (!rt_entry) { */
+/* pthread_mutex_unlock(mtx); */
+/* return NULL; */
+/* } */
+
+/* // Unlock the routing table again */
+/* struct pmlag_iface *iface = rt_entry->interfaces[rand() % rt_entry->iface_cnt]; */
+/* pthread_mutex_unlock(mtx); */
+/* return iface; */
+/* } */
diff --git a/src/util/routing-table.h b/src/util/routing-table.h
@@ -0,0 +1,31 @@
+/* #ifndef __PMLAG_UTIL_RT_H__ */
+/* #define __PMLAG_UTIL_RT_H__ */
+
+/* #include "config.h" */
+
+/* #include "finwo/mindex.h" */
+
+/* struct pmlag_rt_entry { */
+/* unsigned char *mac; // mac address of the remote entity */
+/* int16_t bcidx; // broadcast index last seen from the mac */
+/* int16_t iface_cnt; // amount of interfaces this mac is available on */
+/* struct pmlag_iface **interfaces; // list of pointers to interfaces */
+/* }; */
+
+/* struct mindex_t * rt_init(void *udata); */
+
+/* int rt_upsert( */
+/* struct mindex_t *rt, */
+/* pthread_mutex_t *mtx, */
+/* struct pmlag_iface *iface, */
+/* unsigned char *mac, */
+/* int16_t bcidx */
+/* ); */
+
+/* struct pmlag_iface * rt_find( */
+/* struct mindex_t *rt, */
+/* pthread_mutex_t *mtx, */
+/* unsigned char *mac */
+/* ); */
+
+/* #endif // __PMLAG_UTIL_RT_H__ */
diff --git a/src/util/socket.c b/src/util/socket.c
@@ -0,0 +1,98 @@
+#include <fcntl.h>
+#include <linux/if_arp.h>
+#include <linux/if_packet.h>
+#include <linux/if_tun.h>
+#include <linux/if.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "socket.h"
+
+unsigned char * iface_mac(char * ifname) {
+ unsigned char *mac = calloc(1, ETH_ALEN);
+ struct ifreq ifr;
+ int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ ifr.ifr_addr.sa_family = AF_INET;
+ strncpy(ifr.ifr_name , ifname , IFNAMSIZ-1);
+ ioctl(sockfd, SIOCGIFHWADDR, &ifr);
+ close(sockfd);
+ memcpy(mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+ return mac;
+}
+
+int iface_idx(int sockfd, char * ifname) {
+ struct ifreq ifr;
+ bzero(&ifr, sizeof(ifr));
+
+ // Get interface index
+ strncpy((char *)ifr.ifr_name, ifname, IFNAMSIZ);
+ if ((ioctl(sockfd, SIOCGIFINDEX, &ifr)) == -1) {
+ fprintf(stderr, "Error getting interface index for %s\n", ifname);
+ perror("Error getting interface index");
+ close(sockfd);
+ return -1;
+ }
+
+ return ifr.ifr_ifindex;
+}
+
+int if_ioctl(int cmd, struct ifreq* req) {
+ int ret, sock;
+ sock = socket(AF_INET, SOCK_PACKET, 0);
+ if (sock < 0) {
+ return -1;
+ }
+ ret = ioctl(sock, cmd, req);
+ close(sock);
+ return ret;
+}
+
+int sockraw_open(char * ifname) {
+ struct ifreq ifr;
+
+ // Open socket (P_ALL, due to custom ethertype field)
+ int sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (sockfd < 0) {
+ perror("Error opening socket");
+ close(sockfd);
+ return -1;
+ }
+
+ // Old bind to socket
+ struct sockaddr_ll sll;
+ bzero(&sll, sizeof(sll));
+ sll.sll_family = AF_PACKET;
+ sll.sll_ifindex = iface_idx(sockfd, ifname);
+ sll.sll_protocol = htons(ETH_P_ALL);
+ if (sll.sll_ifindex < 0) {
+ // Error already printed, not reprinting
+ return -1;
+ }
+ if((bind(sockfd, (struct sockaddr *)&sll, sizeof(sll))) == -1) {
+ perror("Error binding raw socket to interface");
+ close(sockfd);
+ return -1;
+ }
+
+ // Get current iface configuration
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, ifname);
+ if (if_ioctl(SIOCGIFFLAGS, &ifr) < 0) {
+ perror("Get interface flags");
+ }
+
+ // Set iface to promiscuous mode
+ ifr.ifr_flags |= IFF_PROMISC;
+ if (if_ioctl(SIOCSIFFLAGS, &ifr) < 0) {
+ perror("Configure interface promiscuous mode");
+ }
+
+ // Return the prepared socket
+ return sockfd;
+}
diff --git a/src/util/socket.h b/src/util/socket.h
@@ -0,0 +1,7 @@
+#ifndef __PMLAG_UTIL_SOCKET_H__
+#define __PMLAG_UTIL_SOCKET_H__
+
+unsigned char * iface_mac(char * ifname);
+int sockraw_open(char * ifname);
+
+#endif // __PMLAG_UTIL_SOCKET_H__