1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-16 00:00:02 +01:00
VILLASnode/server/src/if.c

183 lines
3.7 KiB
C
Raw Normal View History

/** Interface related functions.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014, Institute for Automation of Complex Power Systems, EONERC
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <net/if.h>
2014-12-05 12:39:52 +01:00
#include <linux/if_packet.h>
#include "if.h"
2014-12-05 12:39:52 +01:00
#include "tc.h"
#include "socket.h"
#include "utils.h"
2014-12-05 12:39:52 +01:00
/** Linked list of interfaces */
struct interface *interfaces;
2014-12-05 12:39:52 +01:00
struct interface * if_create(int index) {
struct interface *i = alloc(sizeof(struct interface));
2014-12-05 12:39:52 +01:00
i->index = index;
if_indextoname(index, i->name);
2014-12-05 12:39:52 +01:00
debug(3, "Created interface '%s'", i->name, i->index, i->refcnt);
list_add(interfaces, i);
return i;
}
2014-12-05 12:39:52 +01:00
int if_start(struct interface *i, int affinity)
{ INDENT
if (!i->refcnt) {
warn("Interface '%s' is not used by an active node", i->name);
return -1;
}
else
info("Starting interface '%s'", i->name);
{ INDENT
int mark = 0;
for (struct socket *s = i->sockets; s; s = s->next) {
if (s->netem) {
s->mark = 1 + mark++;
/* Set fwmark for outgoing packets */
if (setsockopt(s->sd, SOL_SOCKET, SO_MARK, &s->mark, sizeof(s->mark)))
serror("Failed to set fwmark for outgoing packets");
2014-12-05 12:39:52 +01:00
else
debug(4, "Set fwmark for socket->sd = %u to %u", s->sd, s->mark);
tc_mark(i, TC_HDL(4000, s->mark), s->mark);
tc_netem(i, TC_HDL(4000, s->mark), s->netem);
}
}
2014-12-05 12:39:52 +01:00
/* Create priority qdisc */
if (mark)
tc_prio(i, TC_HDL(4000, 0), mark);
/* Set affinity for network interfaces (skip _loopback_ dev) */
if_getirqs(i);
if_setaffinity(i, affinity);
}
2014-12-05 12:39:52 +01:00
return 0;
}
int if_stop(struct interface *i)
{ INDENT
info("Stopping interface '%s'", i->name);
{ INDENT
if_setaffinity(i, -1L);
tc_reset(i);
}
return 0;
}
int if_getegress(struct sockaddr *sa)
{
switch (sa->sa_family) {
case AF_INET: {
struct sockaddr_in *sin = (struct sockaddr_in *) sa;
char cmd[128];
char token[32];
snprintf(cmd, sizeof(cmd), "ip route get %s", inet_ntoa(sin->sin_addr));
debug(8, "System: %s", cmd);
FILE *p = popen(cmd, "r");
if (!p)
return -1;
while (!feof(p) && fscanf(p, "%31s", token)) {
if (!strcmp(token, "dev")) {
fscanf(p, "%31s", token);
break;
}
}
return (WEXITSTATUS(fclose(p))) ? -1 : if_nametoindex(token);
}
case AF_PACKET: {
struct sockaddr_ll *sll = (struct sockaddr_ll *) sa;
return sll->sll_ifindex;
}
default:
return -1;
}
}
int if_getirqs(struct interface *i)
{
char dirname[NAME_MAX];
2014-12-05 12:39:52 +01:00
int irq, n = 0;
snprintf(dirname, sizeof(dirname), "/sys/class/net/%s/device/msi_irqs/", i->name);
DIR *dir = opendir(dirname);
2014-12-05 12:39:52 +01:00
if (dir) {
memset(&i->irqs, 0, sizeof(char) * IF_IRQ_MAX);
2014-12-05 12:39:52 +01:00
struct dirent *entry;
while ((entry = readdir(dir)) && n < IF_IRQ_MAX) {
if ((irq = atoi(entry->d_name)))
i->irqs[n++] = irq;
}
2014-12-05 12:39:52 +01:00
closedir(dir);
}
return 0;
}
int if_setaffinity(struct interface *i, int affinity)
{
char filename[NAME_MAX];
FILE *file;
for (int n = 0; n < IF_IRQ_MAX && i->irqs[n]; n++) {
snprintf(filename, sizeof(filename), "/proc/irq/%u/smp_affinity", i->irqs[n]);
file = fopen(filename, "w");
if (file) {
if (fprintf(file, "%8x", affinity) < 0)
error("Failed to set affinity for IRQ %u", i->irqs[n]);
fclose(file);
debug(5, "Set affinity of IRQ %u for interface '%s' to %#x", i->irqs[n], i->name, affinity);
}
else
error("Failed to set affinity for interface '%s'", i->name);
}
return 0;
}
2014-12-05 12:39:52 +01:00
struct interface * if_lookup_index(int index)
{
for (struct interface *i = interfaces; i; i = i->next) {
if (i->index == index) {
return i;
}
}
return NULL;
}
2014-12-05 12:39:52 +01:00