Commit 1f9ae292 authored by Matthieu Boutier's avatar Matthieu Boutier Committed by Juliusz Chroboczek

Rewrite rule selection.

parent ae417d54
...@@ -1684,6 +1684,18 @@ flush_rule(int prio, int family) ...@@ -1684,6 +1684,18 @@ flush_rule(int prio, int family)
return netlink_talk(message_header); return netlink_talk(message_header);
} }
static int
change_rule(int new_prio, int old_prio,
const unsigned char *src, int plen, int table)
{
int rc;
kdebugf("/Swap: ");
rc = add_rule(new_prio, src, plen, table);
if(rc < 0)
return rc;
kdebugf("\\Swap: ");
return flush_rule(old_prio, v4mapped(src) ? AF_INET : AF_INET6);
}
/* Source specific functions and data structures */ /* Source specific functions and data structures */
...@@ -1702,19 +1714,53 @@ static struct rule rules[SRC_TABLE_NUM]; ...@@ -1702,19 +1714,53 @@ static struct rule rules[SRC_TABLE_NUM];
/* used tables is indexed by: <table number> - src_table_idx /* used tables is indexed by: <table number> - src_table_idx
used_tables[i] == 1 <=> the table number (i + src_table_idx) is used */ used_tables[i] == 1 <=> the table number (i + src_table_idx) is used */
static char used_tables[SRC_TABLE_NUM] = {0}; static char used_tables[SRC_TABLE_NUM] = {0};
static unsigned char src_table_used = 0; /* number of tables used */
static inline int static int
change_table_priority(const unsigned char *src, int plen, int table, get_free_table(void)
int old_prio, int new_prio)
{ {
int rc; int i;
kdebugf("/Swap: "); for(i = 0; i < SRC_TABLE_NUM; i++)
rc = add_rule(new_prio, src, plen, table); if(!used_tables[i]) {
if(rc < 0) used_tables[i] = 1;
return rc; return i + src_table_idx;
kdebugf("\\Swap: "); }
return flush_rule(old_prio, v4mapped(src) ? AF_INET : AF_INET6); return -1;
}
static void
release_table(int i)
{
used_tables[i - src_table_idx] = 0;
}
static int
find_hole_around(int i)
{
int j;
for(j = i; j < SRC_TABLE_NUM; j++)
if(rules[j].plen == 0)
return j;
for(j = i - 1; j >= 0; j--)
if(rules[j].plen == 0)
return j;
return -1;
}
static int
shift_rule(int from, int to)
{
int dec = (from < to) ? 1 /* right */ : -1 /* left */;
while(to != from) {
to =- dec;
rc = change_rule(to + dec + src_table_prio, to + src_table_prio,
rules[to].src, rules[to].plen, rules[to].table);
if(rc < 0) {
perror("change_table_priority");
return NULL;
}
rules[to+dec] = rules[to];
rules[to].plen = 0;
}
} }
/* Return a new table at index [idx] of rules. If cell at that index is not /* Return a new table at index [idx] of rules. If cell at that index is not
...@@ -1724,95 +1770,77 @@ insert_table(const unsigned char *src, unsigned short src_plen, int idx) ...@@ -1724,95 +1770,77 @@ insert_table(const unsigned char *src, unsigned short src_plen, int idx)
{ {
int table; int table;
int rc; int rc;
int i; int hole;
if(idx < 0 || idx >= SRC_TABLE_NUM) { if(idx < 0 || idx >= SRC_TABLE_NUM) {
fprintf(stderr, "Incorrect table number %d\n", idx); fprintf(stderr, "Incorrect table number %d\n", idx);
return NULL; return NULL;
} }
if(src_table_used >= SRC_TABLE_NUM) { table = get_free_table();
if(table < 0) {
kdebugf("All allowed routing tables are used!\n"); kdebugf("All allowed routing tables are used!\n");
return NULL; return NULL;
} }
/* find a free table number */ hole = find_hole_around(idx);
for(table = 0; table < SRC_TABLE_NUM; table++) if(hole < 0) {
if(!used_tables[table]) fprintf(stderr, "Have free table but not free rule.\n");
break; goto fail;
table += src_table_idx;
/* Create the table's rule at the right place. Shift rules if necessary. */
if(rules[idx].plen != 0) {
/* shift right */
i = src_table_used;
while(i > idx) {
i--;
rc = change_table_priority(rules[i].src,
rules[i].plen,
rules[i].table,
i + src_table_prio,
i + 1 + src_table_prio);
if(rc < 0) {
perror("change_table_priority");
return NULL;
}
rules[i+1] = rules[i];
rules[i].plen = 0;
}
} }
rc = shift_rule(idx, hole);
if(rc < 0) {
goto fail;
rc = add_rule(idx + src_table_prio, src, src_plen, table); rc = add_rule(idx + src_table_prio, src, src_plen, table);
if(rc < 0) { if(rc < 0) {
perror("add rule"); perror("add rule");
return NULL; goto fail;
} }
used_tables[table - src_table_idx] = 1;
memcpy(rules[idx].src, src, 16); memcpy(rules[idx].src, src, 16);
rules[idx].plen = src_plen; rules[idx].plen = src_plen;
rules[idx].table = table; rules[idx].table = table;
src_table_used++;
return &rules[idx]; return &rules[idx];
fail:
release_table(table);
return NULL;
} }
/* Sorting rules in a well ordered fashion will increase code complexity and /* Sorting rules in a well ordered fashion will increase code complexity and
decrease performances, because more rule shifs will be required, so more decrease performances, because more rule shifs will be required, so more
system calls invoked. */ system calls invoked. */
static int static int
find_table_slot(const unsigned char *src, unsigned short src_plen, find_table_slot(const unsigned char *src, unsigned short src_plen, int *found)
int *new_return) {
{ struct rule *kr = NULL;
struct rule *kt = NULL;
int i; int i;
*new_return = -1; *found = false;
for(i = 0; i < SRC_TABLE_NUM; i++) { for(i = 0; i < SRC_TABLE_NUM; i++) {
kt = &rules[i]; kr = &rules[i];
if(kt->plen == 0) if(kr->plen == 0)
goto new_table_here; /* empty table here */ return i;
switch(prefix_cmp(src, src_plen, kt->src, kt->plen)) { switch(prefix_cmp(src, src_plen, kr->src, kr->plen)) {
case PST_LESS_SPECIFIC: case PST_LESS_SPECIFIC:
case PST_DISJOINT: case PST_DISJOINT:
continue; /* try to find a comparable route entry. */ continue;
case PST_MORE_SPECIFIC: case PST_MORE_SPECIFIC:
goto new_table_here; return i;
case PST_EQUALS: case PST_EQUALS:
*found = true;
return i; return i;
} }
} }
return -1; return -1;
new_table_here: }
*new_return = i;
return -1;
}
static int static int
find_table(const unsigned char *src, unsigned short src_plen) find_table(const unsigned char *src, unsigned short src_plen)
{ {
struct rule *kt = NULL; struct rule *kr = NULL;
int i, new_i; int i, found;
if(src_plen == 0 || if(src_plen == 0 ||
(kernel_disambiguate(src_plen >= 96 && v4mapped(src)))) { (kernel_disambiguate(src_plen >= 96 && v4mapped(src)))) {
...@@ -1821,15 +1849,13 @@ find_table(const unsigned char *src, unsigned short src_plen) ...@@ -1821,15 +1849,13 @@ find_table(const unsigned char *src, unsigned short src_plen)
return -1; return -1;
} }
i = find_table_slot(src, src_plen, &new_i); i = find_table_slot(src, src_plen, &found);
if(i < 0) { if(found)
if(new_i < 0) return rules[i].table;
return -1; if(i < 0)
kt = insert_table(src, src_plen, new_i); return -1;
} else { kr = insert_table(src, src_plen, i);
kt = &rules[i]; return kr == NULL ? -1 : kr->table;
}
return kt == NULL ? -1 : kt->table;
} }
static void static void
...@@ -1844,7 +1870,6 @@ release_tables(void) ...@@ -1844,7 +1870,6 @@ release_tables(void)
} }
used_tables[i] = 0; used_tables[i] = 0;
} }
src_table_used = 0;
} }
static int static int
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment