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

205 lines
5 KiB
C
Raw Normal View History

/** Interface related functions.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
2015-06-02 21:53:04 +02:00
* @copyright 2014-2015, Institute for Automation of Complex Power Systems, EONERC
* This file is part of S2SS. All Rights Reserved. Proprietary and confidential.
2015-08-07 01:11:43 +02:00
* Unauthorized copying of this file, via any medium is strictly prohibited.
2015-06-02 21:53:04 +02:00
*********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <arpa/inet.h>
2014-12-05 12:39:52 +01:00
#include <linux/if_packet.h>
#include <netlink/route/link.h>
#include <netlink/route/route.h>
#include "if.h"
2014-12-05 12:39:52 +01:00
#include "tc.h"
#include "nl.h"
2014-12-05 12:39:52 +01:00
#include "socket.h"
#include "utils.h"
/** Linked list of interfaces. */
struct list interfaces;
struct interface * if_create(struct rtnl_link *link)
{
struct interface *i = alloc(sizeof(struct interface));
i->nl_link = link;
debug(3, "Created interface '%s'", rtnl_link_get_name(i->nl_link));
if_get_irqs(i);
2014-12-05 12:39:52 +01:00
list_init(&i->sockets, NULL);
list_push(&interfaces, i);
2014-12-05 12:39:52 +01:00
return i;
}
void if_destroy(struct interface *i)
{
/* List members are freed by the nodes they belong to. */
list_destroy(&i->sockets);
rtnl_qdisc_put(i->tc_qdisc);
free(i);
}
2014-12-05 12:39:52 +01:00
int if_start(struct interface *i, int affinity)
{
info("Starting interface '%s' which is used by %u sockets", rtnl_link_get_name(i->nl_link), list_length(&i->sockets));
2015-08-07 01:11:43 +02:00
2014-12-05 12:39:52 +01:00
{ INDENT
/* Set affinity for network interfaces (skip _loopback_ dev) */
if_set_affinity(i, affinity);
/* Assign fwmark's to socket nodes which have netem options */
int ret, mark = 0;
FOREACH(&i->sockets, it) {
struct socket *s = it->socket;
if (s->tc_qdisc)
2014-12-05 12:39:52 +01:00
s->mark = 1 + mark++;
}
2015-08-07 01:11:43 +02:00
/* Abort if no node is using netem */
if (mark == 0)
return 0;
/* Replace root qdisc */
if ((ret = tc_prio(i, &i->tc_qdisc, TC_HANDLE(1, 0), TC_H_ROOT, mark)))
;//error("Failed to setup priority queuing discipline: %s", nl_geterror(ret));
2015-08-07 01:11:43 +02:00
/* Create netem qdisks and appropriate filter per netem node */
FOREACH(&i->sockets, it) {
struct socket *s = it->socket;
if (s->tc_qdisc) {
if ((ret = tc_mark(i, &s->tc_classifier, TC_HANDLE(1, s->mark), s->mark)))
error("Failed to setup FW mark classifier: %s", nl_geterror(ret));
char buf[256];
tc_print(buf, sizeof(buf), s->tc_qdisc);
debug(5, "Starting network emulation on interface '%s' for FW mark %u: %s",
rtnl_link_get_name(i->nl_link), s->mark, buf);
if ((ret = tc_netem(i, &s->tc_qdisc, TC_HANDLE(0x1000+s->mark, 0), TC_HANDLE(1, s->mark))))
error("Failed to setup netem qdisc: %s", nl_geterror(ret));
2014-12-05 12:39:52 +01:00
}
}
}
2014-12-05 12:39:52 +01:00
return 0;
}
int if_stop(struct interface *i)
{
info("Stopping interface '%s'", rtnl_link_get_name(i->nl_link));
2014-12-05 12:39:52 +01:00
{ INDENT
if_set_affinity(i, -1L);
2015-08-07 01:11:43 +02:00
if (i->tc_qdisc)
tc_reset(i);
2014-12-05 12:39:52 +01:00
}
return 0;
}
int if_get_egress(struct sockaddr *sa, struct rtnl_link **link)
2014-12-05 12:39:52 +01:00
{
int ifindex = -1;
2014-12-05 12:39:52 +01:00
switch (sa->sa_family) {
case AF_INET:
case AF_INET6: {
2014-12-05 12:39:52 +01:00
struct sockaddr_in *sin = (struct sockaddr_in *) sa;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
struct nl_addr *addr = (sa->sa_family == AF_INET)
? nl_addr_build(sin->sin_family, &sin->sin_addr.s_addr, sizeof(sin->sin_addr.s_addr))
: nl_addr_build(sin6->sin6_family, sin6->sin6_addr.s6_addr, sizeof(sin6->sin6_addr));
ifindex = nl_get_egress(addr);
if (ifindex < 0)
error("Netlink error: %s", nl_geterror(ifindex));
break;
2014-12-05 12:39:52 +01:00
}
2014-12-05 12:39:52 +01:00
case AF_PACKET: {
struct sockaddr_ll *sll = (struct sockaddr_ll *) sa;
ifindex = sll->sll_ifindex;
break;
2014-12-05 12:39:52 +01:00
}
}
struct nl_cache *cache = nl_cache_mngt_require("route/link");
if (!(*link = rtnl_link_get(cache, ifindex)))
return -1;
return 0;
}
int if_get_irqs(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/", rtnl_link_get_name(i->nl_link));
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);
}
debug(6, "Found %u IRQs for interface '%s'", n, rtnl_link_get_name(i->nl_link));
return 0;
}
int if_set_affinity(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], rtnl_link_get_name(i->nl_link), affinity);
}
else
error("Failed to set affinity for interface '%s'", rtnl_link_get_name(i->nl_link));
}
return 0;
}
2014-12-05 12:39:52 +01:00
struct interface * if_lookup_index(int index)
{
FOREACH(&interfaces, it) {
if (rtnl_link_get_ifindex(it->interface->nl_link) == index)
return it->interface;
}
return NULL;
}
2014-12-05 12:39:52 +01:00