2014-07-14 11:49:44 +00:00
|
|
|
/** Interface related functions.
|
2014-06-05 09:35:40 +00:00
|
|
|
*
|
|
|
|
* @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>
|
2014-06-25 01:53:46 +00:00
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <net/if.h>
|
2014-12-05 12:39:52 +01:00
|
|
|
#include <linux/if_packet.h>
|
2014-06-05 09:35:40 +00:00
|
|
|
|
2014-06-25 01:53:46 +00:00
|
|
|
#include "if.h"
|
2014-12-05 12:39:52 +01:00
|
|
|
#include "tc.h"
|
|
|
|
#include "socket.h"
|
2014-06-05 09:35:40 +00:00
|
|
|
#include "utils.h"
|
|
|
|
|
2014-12-05 12:39:52 +01:00
|
|
|
/** Linked list of interfaces */
|
|
|
|
struct interface *interfaces;
|
2014-06-05 09:35:40 +00:00
|
|
|
|
2014-12-05 12:39:52 +01:00
|
|
|
struct interface * if_create(int index) {
|
|
|
|
struct interface *i = malloc(sizeof(struct interface));
|
|
|
|
if (!i)
|
|
|
|
error("Failed to allocate memory for interface");
|
|
|
|
else
|
|
|
|
memset(i, 0, sizeof(struct interface));
|
2014-06-05 09:35:40 +00:00
|
|
|
|
2014-12-05 12:39:52 +01:00
|
|
|
i->index = index;
|
|
|
|
if_indextoname(index, i->name);
|
2014-07-04 09:47:29 +00:00
|
|
|
|
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-06-05 09:35:40 +00:00
|
|
|
|
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)))
|
2014-12-09 15:39:17 +00:00
|
|
|
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-06-05 09:35:40 +00:00
|
|
|
}
|
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-06-05 09:35:40 +00:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
2014-06-05 09:35:40 +00:00
|
|
|
}
|
|
|
|
|
2014-06-25 01:53:46 +00:00
|
|
|
int if_getirqs(struct interface *i)
|
2014-06-05 09:35:40 +00:00
|
|
|
{
|
2014-06-25 01:53:46 +00:00
|
|
|
char dirname[NAME_MAX];
|
2014-12-05 12:39:52 +01:00
|
|
|
int irq, n = 0;
|
2014-06-05 09:35:40 +00:00
|
|
|
|
2014-06-25 01:53:46 +00:00
|
|
|
snprintf(dirname, sizeof(dirname), "/sys/class/net/%s/device/msi_irqs/", i->name);
|
2014-09-04 13:30:36 +00:00
|
|
|
DIR *dir = opendir(dirname);
|
2014-12-05 12:39:52 +01:00
|
|
|
if (dir) {
|
|
|
|
memset(&i->irqs, 0, sizeof(char) * IF_IRQ_MAX);
|
2014-06-05 09:35:40 +00:00
|
|
|
|
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-06-25 01:53:46 +00:00
|
|
|
|
2014-12-05 12:39:52 +01:00
|
|
|
closedir(dir);
|
2014-06-25 01:53:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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]);
|
|
|
|
|
2014-06-05 09:35:40 +00:00
|
|
|
file = fopen(filename, "w");
|
2014-07-04 09:47:29 +00:00
|
|
|
if (file) {
|
|
|
|
if (fprintf(file, "%8x", affinity) < 0)
|
|
|
|
error("Failed to set affinity for IRQ %u", i->irqs[n]);
|
2014-06-05 09:35:40 +00:00
|
|
|
|
2014-07-04 09:47:29 +00:00
|
|
|
fclose(file);
|
|
|
|
debug(5, "Set affinity of IRQ %u for interface '%s' to %#x", i->irqs[n], i->name, affinity);
|
|
|
|
}
|
2014-09-04 13:30:36 +00:00
|
|
|
else
|
|
|
|
error("Failed to set affinity for interface '%s'", i->name);
|
2014-06-05 09:35:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2014-06-25 01:53:46 +00:00
|
|
|
|
2014-12-05 12:39:52 +01:00
|
|
|
struct interface * if_lookup_index(int index)
|
2014-06-25 01:53:46 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
|