Browse Source

Mass update for non-daemon code (see `6d3865b`)

Change-Id: I7c1f3816c20b1e7e44d11838d841c26e15de380b
pull/197/head
Richard Fuchs 10 years ago
parent
commit
6b5c4e8b0c
3 changed files with 323 additions and 94 deletions
  1. +19
    -0
      README.md
  2. +303
    -93
      kernel-module/xt_RTPENGINE.c
  3. +1
    -1
      kernel-module/xt_RTPENGINE.h

+ 19
- 0
README.md View File

@ -731,6 +731,25 @@ Optionally included keys are:
However, this mechanism for selecting the address family is now obsolete
and the `address family` dictionary key should be used instead.
A direction keyword is *round-robin-calls*. If this is received, a round robin algorithm runs for
choosing the logical interface for the current stream(e.g. audio, video).
The algorithm checks that all local interfaces of the tried logical interface have free ports for
call streams. If a logical interface fails the check, the next one is tried. If there is no logical
interface found with this property, it fallbacks to the default behaviour (e.g. return first logical
interface in --interface list even if no free ports are available). The attribute is ignored for
answers() because the logical interface was already selected at offers().
Naming an interface "round-robin-calls" and trying to select it using direction will
__run the above algorithm__!
Round robin for both legs of the stream:
{ ..., "direction": [ "round-robin-calls", "round-robin-calls" ], ... }
Round robin for first leg and and select "pub" for the second leg of the stream:
{ ..., "direction": [ "round-robin-calls", "pub" ], ... }
Round robin for first leg and and default behaviour for the second leg of the stream:
{ ..., "direction": [ "round-robin-calls" ], ... }
* `received from`
Contains a list of exactly two elements. The first element denotes the address family and the second


+ 303
- 93
kernel-module/xt_RTPENGINE.c View File

@ -132,7 +132,8 @@ static void *proc_main_list_next(struct seq_file *, void *, loff_t *);
static int proc_main_list_show(struct seq_file *, void *);
static void table_push(struct rtpengine_table *);
static struct rtpengine_target *get_target(struct rtpengine_table *, u_int16_t);
static struct rtpengine_target *get_target(struct rtpengine_table *, const struct re_address *);
static int is_valid_address(const struct re_address *rea);
static int aes_f8_session_key_init(struct re_crypto_context *, struct rtpengine_srtp *);
static int srtp_encrypt_aes_cm(struct re_crypto_context *, struct rtpengine_srtp *,
@ -188,8 +189,19 @@ struct re_bitfield {
};
struct re_bucket {
struct re_bitfield targets;
struct rtpengine_target *target[256];
struct re_bitfield ports_lo_bf;
struct rtpengine_target *ports_lo[256];
};
struct re_dest_addr {
struct re_address destination;
struct re_bitfield ports_hi_bf;
struct re_bucket *ports_hi[256];
};
struct re_dest_addr_hash {
struct re_bitfield addrs_bf;
struct re_dest_addr *addrs[256];
};
struct rtpengine_table {
@ -204,10 +216,9 @@ struct rtpengine_table {
struct proc_dir_entry *list;
struct proc_dir_entry *blist;
struct re_bitfield buckets;
struct re_bucket *bucket[256];
struct re_dest_addr_hash dest_addr_hash;
unsigned int targets;
unsigned int num_targets;
};
struct re_cipher {
@ -536,7 +547,8 @@ static void clear_proc(struct proc_dir_entry **e) {
static void table_push(struct rtpengine_table *t) {
int i, j;
int i, j, k;
struct re_dest_addr *rda;
struct re_bucket *b;
if (!t)
@ -547,23 +559,33 @@ static void table_push(struct rtpengine_table *t) {
DBG("Freeing table\n");
for (i = 0; i < 256; i++) {
b = t->bucket[i];
if (!b)
for (k = 0; k < 256; k++) {
rda = t->dest_addr_hash.addrs[k];
if (!rda)
continue;
for (j = 0; j < 256; j++) {
if (!b->target[j])
for (i = 0; i < 256; i++) {
b = rda->ports_hi[i];
if (!b)
continue;
b->target[j]->table = -1;
target_push(b->target[j]);
b->target[j] = NULL;
for (j = 0; j < 256; j++) {
if (!b->ports_lo[j])
continue;
b->ports_lo[j]->table = -1;
target_push(b->ports_lo[j]);
b->ports_lo[j] = NULL;
}
kfree(b);
rda->ports_hi[i] = NULL;
}
kfree(b);
t->bucket[i] = NULL;
kfree(rda);
t->dest_addr_hash.addrs[k] = NULL;
}
clear_proc(&t->status);
clear_proc(&t->control);
clear_proc(&t->list);
@ -656,8 +678,7 @@ static ssize_t proc_status(struct file *f, char __user *b, size_t l, loff_t *o)
read_lock_irqsave(&t->target_lock, flags);
len += sprintf(buf + len, "Refcount: %u\n", atomic_read(&t->refcnt) - 1);
len += sprintf(buf + len, "Control PID: %u\n", t->pid);
len += sprintf(buf + len, "Targets: %u\n", t->targets);
len += sprintf(buf + len, "Buckets: %u\n", t->buckets.used);
len += sprintf(buf + len, "Targets: %u\n", t->num_targets);
read_unlock_irqrestore(&t->target_lock, flags);
table_push(t);
@ -758,43 +779,69 @@ static inline void bitfield_clear(struct re_bitfield *bf, unsigned char i) {
bf->b[b] &= ~k;
bf->used--;
}
static inline struct rtpengine_target *find_next_target(struct rtpengine_table *t, int *port) {
static inline struct rtpengine_target *find_next_target(struct rtpengine_table *t, int *addr_bucket,
int *port)
{
unsigned long flags;
struct re_dest_addr *rda;
struct re_bucket *b;
unsigned char hi, lo;
unsigned int hi_b, lo_b;
unsigned char hi, lo, ab;
unsigned int rda_b, hi_b, lo_b;
struct rtpengine_target *g;
if (*port < 0 || *port > 0xffff)
if (*port < 0)
return NULL;
if (*port > 0xffff) {
*port = 0;
(*addr_bucket)++;
}
if (*addr_bucket < 0 || *addr_bucket > 255)
return NULL;
hi = (*port & 0xff00) >> 8;
lo = *port & 0xff;
ab = *addr_bucket;
read_lock_irqsave(&t->target_lock, flags);
for (;;) {
rda_b = bitfield_slot(ab);
if (!t->dest_addr_hash.addrs_bf.b[rda_b]) {
ab = bitfield_next_slot(rda_b);
hi = 0;
lo = 0;
goto next_rda;
}
rda = t->dest_addr_hash.addrs[ab];
if (!rda) {
ab++;
hi = 0;
lo = 0;
goto next_rda;
}
hi_b = bitfield_slot(hi);
if (!t->buckets.b[hi_b]) {
if (!rda->ports_hi_bf.b[hi_b]) {
hi = bitfield_next_slot(hi_b);
lo = 0;
goto next;
goto next_hi;
}
b = t->bucket[hi];
b = rda->ports_hi[hi];
if (!b) {
hi++;
lo = 0;
goto next;
goto next_hi;
}
lo_b = bitfield_slot(lo);
if (!b->targets.b[lo_b]) {
if (!b->ports_lo_bf.b[lo_b]) {
lo = bitfield_next_slot(lo_b);
goto next_lo;
}
g = b->target[lo];
g = b->ports_lo[lo];
if (!g) {
lo++;
goto next_lo;
@ -806,13 +853,17 @@ static inline struct rtpengine_target *find_next_target(struct rtpengine_table *
next_lo:
if (!lo)
hi++;
next:
next_hi:
if (!hi && !lo)
ab++;
next_rda:
if (!ab && !hi && !lo)
break;
}
read_unlock_irqrestore(&t->target_lock, flags);
*addr_bucket = ab;
*port = (hi << 8) | lo;
(*port)++;
@ -854,7 +905,7 @@ static ssize_t proc_blist_read(struct file *f, char __user *b, size_t l, loff_t
u_int32_t id;
struct rtpengine_table *t;
struct rtpengine_list_entry op;
int err, port, i;
int err, port, addr_bucket, i;
struct rtpengine_target *g;
unsigned long flags;
@ -869,9 +920,10 @@ static ssize_t proc_blist_read(struct file *f, char __user *b, size_t l, loff_t
if (!t)
return -ENOENT;
port = (int) *o;
g = find_next_target(t, &port);
*o = port;
addr_bucket = ((int) *o) >> 17;
port = ((int) *o) & 0x1ffff;
g = find_next_target(t, &addr_bucket, &port);
*o = (addr_bucket << 17) | port;
err = 0;
if (!g)
goto err;
@ -950,34 +1002,34 @@ static void *proc_list_next(struct seq_file *f, void *v, loff_t *o) { /* v is in
u_int32_t id = (u_int32_t) (unsigned long) f->private;
struct rtpengine_table *t;
struct rtpengine_target *g;
int port;
int port, addr_bucket;
port = (int) *o;
addr_bucket = ((int) *o) >> 17;
port = ((int) *o) & 0x1ffff;
t = get_table(id);
if (!t)
return NULL;
g = find_next_target(t, &port);
g = find_next_target(t, &addr_bucket, &port);
*o = port;
*o = (addr_bucket << 17) | port;
table_push(t);
return g;
}
static void proc_list_addr_print(struct seq_file *f, const char *s, const struct re_address *a) {
static void seq_addr_print(struct seq_file *f, const struct re_address *a) {
if (!a->family)
return;
seq_printf(f, " %6s ", s);
switch (a->family) {
case AF_INET:
seq_printf(f, "inet4 %u.%u.%u.%u:%u\n", a->u.u8[0], a->u.u8[1], a->u.u8[2],
seq_printf(f, "inet4 %u.%u.%u.%u:%u", a->u.u8[0], a->u.u8[1], a->u.u8[2],
a->u.u8[3], a->port);
break;
case AF_INET6:
seq_printf(f, "inet6 [%x:%x:%x:%x:%x:%x:%x:%x]:%u\n",
seq_printf(f, "inet6 [%x:%x:%x:%x:%x:%x:%x:%x]:%u",
htons(a->u.u16[0]), htons(a->u.u16[1]),
htons(a->u.u16[2]), htons(a->u.u16[3]), htons(a->u.u16[4]), htons(a->u.u16[5]),
htons(a->u.u16[6]), htons(a->u.u16[7]), a->port);
@ -988,6 +1040,15 @@ static void proc_list_addr_print(struct seq_file *f, const char *s, const struct
}
}
static void proc_list_addr_print(struct seq_file *f, const char *s, const struct re_address *a) {
if (!a->family)
return;
seq_printf(f, " %6s ", s);
seq_addr_print(f, a);
seq_printf(f, "\n");
}
static void proc_list_crypto_print(struct seq_file *f, struct re_crypto_context *c,
struct rtpengine_srtp *s, const char *label)
{
@ -1015,7 +1076,9 @@ static int proc_list_show(struct seq_file *f, void *v) {
struct rtpengine_target *g = v;
int i;
seq_printf(f, "port %5u:\n", g->target.target_port);
seq_printf(f, "local ");
seq_addr_print(f, &g->target.local);
seq_printf(f, "\n");
proc_list_addr_print(f, "src", &g->target.src_addr);
proc_list_addr_print(f, "dst", &g->target.dst_addr);
proc_list_addr_print(f, "mirror", &g->target.mirror_addr);
@ -1046,37 +1109,119 @@ static int proc_list_show(struct seq_file *f, void *v) {
static unsigned int re_address_hash(const struct re_address *a) {
u_int32_t ret = 0;
if (!a)
goto out;
ret += a->family;
switch (a->family) {
case AF_INET:
ret += a->u.ipv4;
break;
case AF_INET6:
ret += a->u.u32[0];
ret += a->u.u32[1];
ret += a->u.u32[2];
ret += a->u.u32[3];
break;
default:
goto out;
}
ret = (ret & 0xffff) ^ ((ret & 0xffff0000) >> 16);
ret = (ret & 0xff) ^ ((ret & 0xff00) >> 8);
out:
return ret;
}
static int re_address_match(const struct re_address *a, const struct re_address *b) {
if (!a || !b)
return 0;
if (a->family != b->family)
return 0;
switch (a->family) {
case AF_INET:
if (a->u.ipv4 == b->u.ipv4)
return 1;
break;
case AF_INET6:
if (!memcmp(a->u.ipv6, b->u.ipv6, sizeof(a->u.ipv6)))
return 1;
break;
default:
return 0;
}
return 0;
}
static struct re_dest_addr *find_dest_addr(const struct re_dest_addr_hash *h, const struct re_address *local) {
unsigned int rda_hash, i;
struct re_dest_addr *rda;
i = rda_hash = re_address_hash(local);
while (1) {
rda = h->addrs[i];
if (!rda)
return NULL;
if (re_address_match(local, &rda->destination))
return rda;
i++;
if (i >= 256)
i = 0;
if (i == rda_hash)
return NULL;
}
}
static int table_del_target(struct rtpengine_table *t, u_int16_t port) {
static int table_del_target(struct rtpengine_table *t, const struct re_address *local) {
unsigned char hi, lo;
struct re_dest_addr *rda;
struct re_bucket *b;
struct rtpengine_target *g = NULL;
unsigned long flags;
if (!port)
if (!local || !is_valid_address(local))
return -EINVAL;
hi = (port & 0xff00) >> 8;
lo = port & 0xff;
hi = (local->port & 0xff00) >> 8;
lo = local->port & 0xff;
write_lock_irqsave(&t->target_lock, flags);
b = t->bucket[hi];
rda = find_dest_addr(&t->dest_addr_hash, local);
if (!rda)
goto out;
b = rda->ports_hi[hi];
if (!b)
goto out;
g = b->target[lo];
g = b->ports_lo[lo];
if (!g)
goto out;
b->target[lo] = NULL;
bitfield_clear(&b->targets, lo);
t->targets--;
if (!b->targets.used) {
t->bucket[hi] = NULL;
bitfield_clear(&t->buckets, hi);
b->ports_lo[lo] = NULL;
bitfield_clear(&b->ports_lo_bf, lo);
t->num_targets--;
if (!b->ports_lo_bf.used) {
rda->ports_hi[hi] = NULL;
bitfield_clear(&rda->ports_hi_bf, hi);
}
else
b = NULL;
/* not freeing or NULLing the re_dest_addr due to hash collision logic */
out:
write_unlock_irqrestore(&t->target_lock, flags);
@ -1093,7 +1238,7 @@ out:
static int is_valid_address(struct re_address *rea) {
static int is_valid_address(const struct re_address *rea) {
switch (rea->family) {
case AF_INET:
if (!rea->u.ipv4)
@ -1418,13 +1563,17 @@ static void crypto_context_init(struct re_crypto_context *c, struct rtpengine_sr
static int table_new_target(struct rtpengine_table *t, struct rtpengine_target_info *i, int update) {
unsigned char hi, lo;
unsigned int rda_hash, rh_it;
struct rtpengine_target *g;
struct re_dest_addr *rda;
struct re_bucket *b, *ba = NULL;
struct rtpengine_target *og = NULL;
int err, j;
unsigned long flags;
if (!i->target_port)
/* validation */
if (!is_valid_address(&i->local))
return -EINVAL;
if (!is_valid_address(&i->src_addr))
return -EINVAL;
@ -1445,6 +1594,8 @@ static int table_new_target(struct rtpengine_table *t, struct rtpengine_target_i
DBG("Creating new target\n");
/* initializing */
err = -ENOMEM;
g = kmalloc(sizeof(*g), GFP_KERNEL);
if (!g)
@ -1465,37 +1616,86 @@ static int table_new_target(struct rtpengine_table *t, struct rtpengine_target_i
if (err)
goto fail2;
hi = (i->target_port & 0xff00) >> 8;
lo = i->target_port & 0xff;
/* find or allocate re_dest_addr */
rda_hash = re_address_hash(&i->local);
hi = (i->local.port & 0xff00) >> 8;
lo = i->local.port & 0xff;
retry:
rh_it = rda_hash;
write_lock_irqsave(&t->target_lock, flags);
if (!(b = t->bucket[hi])) {
err = -ENOENT;
if (update)
rda = t->dest_addr_hash.addrs[rh_it];
while (rda) {
if (re_address_match(&rda->destination, &i->local))
goto got_rda;
rh_it++;
if (rh_it >= 256)
rh_it = 0;
err = -ENXIO;
if (rh_it == rda_hash)
goto fail4;
rda = t->dest_addr_hash.addrs[rh_it];
}
err = -ENOENT;
if (update)
goto fail4;
write_unlock_irqrestore(&t->target_lock, flags);
rda = kmalloc(sizeof(*rda), GFP_KERNEL);
err = -ENOMEM;
if (!rda)
goto fail2;
memset(rda, 0, sizeof(*rda));
memcpy(&rda->destination, &i->local, sizeof(rda->destination));
write_lock_irqsave(&t->target_lock, flags);
if (t->dest_addr_hash.addrs[rh_it]) {
write_unlock_irqrestore(&t->target_lock, flags);
kfree(rda);
goto retry;
}
t->dest_addr_hash.addrs[rh_it] = rda;
bitfield_set(&t->dest_addr_hash.addrs_bf, rh_it);
b = kmalloc(sizeof(*b), GFP_KERNEL);
err = -ENOMEM;
if (!b)
goto fail2;
memset(b, 0, sizeof(*b));
got_rda:
/* find or allocate re_bucket */
write_lock_irqsave(&t->target_lock, flags);
if ((b = rda->ports_hi[hi]))
goto got_bucket;
if (!t->bucket[hi]) {
t->bucket[hi] = b;
bitfield_set(&t->buckets, hi);
}
else {
ba = b;
b = t->bucket[hi];
}
err = -ENOENT;
if (update)
goto fail4;
write_unlock_irqrestore(&t->target_lock, flags);
b = kmalloc(sizeof(*b), GFP_KERNEL);
err = -ENOMEM;
if (!b)
goto fail2;
memset(b, 0, sizeof(*b));
write_lock_irqsave(&t->target_lock, flags);
if (!rda->ports_hi[hi]) {
rda->ports_hi[hi] = b;
bitfield_set(&rda->ports_hi_bf, hi);
}
else {
ba = b;
b = rda->ports_hi[hi];
}
got_bucket:
if (update) {
err = -ENOENT;
og = b->target[lo];
og = b->ports_lo[lo];
if (!og)
goto fail4;
@ -1514,13 +1714,13 @@ static int table_new_target(struct rtpengine_table *t, struct rtpengine_target_i
}
else {
err = -EEXIST;
if (b->target[lo])
if (b->ports_lo[lo])
goto fail4;
bitfield_set(&b->targets, lo);
t->targets++;
bitfield_set(&b->ports_lo_bf, lo);
t->num_targets++;
}
b->target[lo] = g;
b->ports_lo[lo] = g;
g = NULL;
write_unlock_irqrestore(&t->target_lock, flags);
@ -1545,21 +1745,24 @@ fail1:
static struct rtpengine_target *get_target(struct rtpengine_table *t, u_int16_t port) {
static struct rtpengine_target *get_target(struct rtpengine_table *t, const struct re_address *local) {
unsigned char hi, lo;
struct re_dest_addr *rda;
struct rtpengine_target *r;
unsigned long flags;
if (!t)
return NULL;
if (!port)
if (!local)
return NULL;
hi = (port & 0xff00) >> 8;
lo = port & 0xff;
hi = (local->port & 0xff00) >> 8;
lo = local->port & 0xff;
read_lock_irqsave(&t->target_lock, flags);
r = t->bucket[hi] ? t->bucket[hi]->target[lo] : NULL;
rda = find_dest_addr(&t->dest_addr_hash, local);
r = rda ? (rda->ports_hi[hi] ? rda->ports_hi[hi]->ports_lo[lo] : NULL) : NULL;
if (r)
target_hold(r);
read_unlock_irqrestore(&t->target_lock, flags);
@ -1706,7 +1909,7 @@ static ssize_t proc_control_write(struct file *file, const char __user *buf, siz
break;
case MMG_DEL:
err = table_del_target(t, msg.target.target_port);
err = table_del_target(t, &msg.target.local);
if (err)
goto err;
break;
@ -2225,7 +2428,9 @@ static inline int rtp_payload_type(const struct rtp_header *hdr, const struct rt
}
#endif
static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t, struct re_address *src, u_int8_t in_tos) {
static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t, struct re_address *src,
struct re_address *dst, u_int8_t in_tos)
{
struct udphdr *uh;
struct rtpengine_target *g;
struct sk_buff *skb2;
@ -2254,8 +2459,9 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t,
skb_trim(skb, datalen);
src->port = ntohs(uh->source);
dst->port = ntohs(uh->dest);
g = get_target(t, ntohs(uh->dest));
g = get_target(t, dst);
if (!g)
goto skip2;
@ -2428,7 +2634,7 @@ static unsigned int rtpengine4(struct sk_buff *oskb, const struct xt_action_para
struct sk_buff *skb;
struct iphdr *ih;
struct rtpengine_table *t;
struct re_address src;
struct re_address src, dst;
t = get_table(pinfo->id);
if (!t)
@ -2447,8 +2653,10 @@ static unsigned int rtpengine4(struct sk_buff *oskb, const struct xt_action_para
memset(&src, 0, sizeof(src));
src.family = AF_INET;
src.u.ipv4 = ih->saddr;
dst.family = AF_INET;
dst.u.ipv4 = ih->daddr;
return rtpengine46(skb, t, &src, (u_int8_t)ih->tos);
return rtpengine46(skb, t, &src, &dst, (u_int8_t)ih->tos);
skip2:
kfree_skb(skb);
@ -2470,7 +2678,7 @@ static unsigned int rtpengine6(struct sk_buff *oskb, const struct xt_action_para
struct sk_buff *skb;
struct ipv6hdr *ih;
struct rtpengine_table *t;
struct re_address src;
struct re_address src, dst;
t = get_table(pinfo->id);
if (!t)
@ -2490,8 +2698,10 @@ static unsigned int rtpengine6(struct sk_buff *oskb, const struct xt_action_para
memset(&src, 0, sizeof(src));
src.family = AF_INET6;
memcpy(&src.u.ipv6, &ih->saddr, sizeof(src.u.ipv6));
dst.family = AF_INET6;
memcpy(&dst.u.ipv6, &ih->daddr, sizeof(dst.u.ipv6));
return rtpengine46(skb, t, &src, ipv6_get_dsfield(ih));
return rtpengine46(skb, t, &src, &dst, ipv6_get_dsfield(ih));
skip2:
kfree_skb(skb);


+ 1
- 1
kernel-module/xt_RTPENGINE.h View File

@ -75,7 +75,7 @@ enum rtpengine_src_mismatch {
};
struct rtpengine_target_info {
u_int16_t target_port;
struct re_address local;
struct re_address expected_src; /* for incoming packets */
enum rtpengine_src_mismatch src_mismatch;


Loading…
Cancel
Save