Browse Source

TT#99621 track basic RTP stats in kernel

Change-Id: I199c37ca02f44afa45d0fe2b6d9c1b67dff0fba1
pull/1163/head
Richard Fuchs 5 years ago
parent
commit
09026c1910
2 changed files with 152 additions and 1 deletions
  1. +129
    -0
      kernel-module/xt_RTPENGINE.c
  2. +23
    -1
      kernel-module/xt_RTPENGINE.h

+ 129
- 0
kernel-module/xt_RTPENGINE.c View File

@ -277,6 +277,8 @@ struct rtpengine_target {
struct rtpengine_stats_a stats;
struct rtpengine_rtp_stats_a rtp_stats[NUM_PAYLOAD_TYPES];
spinlock_t ssrc_stats_lock;
struct rtpengine_ssrc_stats ssrc_stats;
struct re_crypto_context decrypt;
struct re_crypto_context encrypt;
@ -1658,6 +1660,32 @@ static struct re_dest_addr *find_dest_addr(const struct re_dest_addr_hash *h, co
static int table_get_target_stats(struct rtpengine_table *t, struct rtpengine_stats_info *i, int reset) {
struct rtpengine_target *g;
g = get_target(t, &i->local);
if (!g)
return -ENOENT;
i->ssrc = g->target.ssrc;
spin_lock(&g->ssrc_stats_lock);
i->ssrc_stats = g->ssrc_stats;
if (reset) {
g->ssrc_stats.basic_stats.packets = 0;
g->ssrc_stats.basic_stats.bytes = 0;
g->ssrc_stats.total_lost = 0;
}
spin_unlock(&g->ssrc_stats_lock);
target_put(g);
return 0;
}
static int table_del_target(struct rtpengine_table *t, const struct re_address *local) {
unsigned char hi, lo;
struct re_dest_addr *rda;
@ -2131,6 +2159,8 @@ static int table_new_target(struct rtpengine_table *t, struct rtpengine_target_i
memcpy(&g->target, i, sizeof(*i));
crypto_context_init(&g->decrypt, &g->target.decrypt);
crypto_context_init(&g->encrypt, &g->target.encrypt);
spin_lock_init(&g->ssrc_stats_lock);
g->ssrc_stats.lost_bits = -1;
err = gen_session_keys(&g->decrypt, &g->target.decrypt);
if (err)
@ -3244,6 +3274,20 @@ static inline ssize_t proc_control_read_write(struct file *file, char __user *ub
err = table_new_target(t, &msg->u.target, 1);
break;
case REMG_GET_STATS:
err = -EINVAL;
if (!writeable)
goto err;
err = table_get_target_stats(t, &msg->u.stats, 0);
break;
case REMG_GET_RESET_STATS:
err = -EINVAL;
if (!writeable)
goto err;
err = table_get_target_stats(t, &msg->u.stats, 1);
break;
case REMG_ADD_CALL:
err = -EINVAL;
if (!writeable)
@ -3925,6 +3969,88 @@ static struct sk_buff *intercept_skb_copy(struct sk_buff *oskb, const struct re_
static void rtp_stats(struct rtpengine_target *g, struct rtp_parsed *rtp, s64 arrival_time, int pt_idx) {
unsigned long flags;
struct rtpengine_ssrc_stats *s = &g->ssrc_stats;
u_int16_t old_seq_trunc;
u_int32_t last_seq;
u_int16_t seq_diff;
u_int32_t clockrate;
u_int32_t transit;
int32_t d;
u_int16_t seq = ntohs(rtp->header->seq_num);
u_int32_t ts = ntohl(rtp->header->timestamp);
spin_lock_irqsave(&g->ssrc_stats_lock, flags);
s->basic_stats.packets++;
s->basic_stats.bytes += rtp->payload_len;
s->timestamp = ts;
// track sequence numbers and lost frames
last_seq = s->ext_seq;
// old seq or seq reset?
old_seq_trunc = last_seq & 0xffff;
seq_diff = seq - old_seq_trunc;
if (seq_diff == 0 || seq_diff >= 0xfeff) // old/dup seq - ignore
;
else if (seq_diff > 0x100) {
// reset seq and loss tracker
s->ext_seq = seq;
s->lost_bits = -1;
}
else {
// seq wrap?
u_int32_t new_seq = (last_seq & 0xffff0000) | seq;
while (new_seq < last_seq) {
new_seq += 0x10000;
if ((new_seq & 0xffff0000) == 0) // ext seq wrapped
break;
}
seq_diff = new_seq - s->ext_seq;
s->ext_seq = new_seq;
// shift loss tracker bit field and count losses
if (seq_diff >= (sizeof(s->lost_bits) * 8)) {
// complete loss
s->total_lost += sizeof(s->lost_bits) * 8;
s->lost_bits = -1;
}
else {
while (seq_diff) {
// shift out one bit and see if we lost it
if ((s->lost_bits & 0x80000000) == 0)
s->total_lost++;
s->lost_bits <<= 1;
seq_diff--;
}
}
}
// track this frame as being seen
seq_diff = (s->ext_seq & 0xffff) - seq;
if (seq_diff < (sizeof(s->lost_bits) * 8))
s->lost_bits |= (1 << seq_diff);
// jitter
// RFC 3550 A.8
clockrate = g->target.clock_rates[pt_idx];
transit = (((arrival_time / 1000) * clockrate) / 1000) - ts;
d = 0;
if (s->transit)
d = transit - s->transit;
s->transit = transit;
if (d < 0)
d = -d;
s->jitter += d - ((s->jitter + 8) >> 4);
spin_unlock_irqrestore(&g->ssrc_stats_lock, flags);
}
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, const struct xt_action_param *par)
{
@ -4040,6 +4166,9 @@ src_check_ok:
skb_trim(skb, rtp.header_len + rtp.payload_len);
if (g->target.rtp_stats)
rtp_stats(g, &rtp, ktime_to_us(skb->tstamp), rtp_pt_idx);
DBG("packet payload decrypted as %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x...\n",
rtp.payload[0], rtp.payload[1], rtp.payload[2], rtp.payload[3],
rtp.payload[4], rtp.payload[5], rtp.payload[6], rtp.payload[7],


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

@ -24,6 +24,15 @@ struct rtpengine_rtp_stats {
u_int64_t packets;
u_int64_t bytes;
};
struct rtpengine_ssrc_stats {
struct rtpengine_rtp_stats basic_stats;
u_int32_t timestamp;
u_int32_t ext_seq;
u_int32_t lost_bits; // sliding bitfield, [0] = ext_seq
u_int32_t total_lost;
u_int32_t transit;
u_int32_t jitter;
};
struct re_address {
int family;
@ -95,6 +104,7 @@ struct rtpengine_target_info {
u_int32_t ssrc_out; // Rewrite SSRC
unsigned char payload_types[NUM_PAYLOAD_TYPES]; /* must be sorted */
u_int32_t clock_rates[NUM_PAYLOAD_TYPES];
unsigned int num_payload_types;
unsigned char tos;
@ -105,7 +115,8 @@ struct rtpengine_target_info {
rtp_only:1,
do_intercept:1,
transcoding:1, // SSRC subst and RTP PT filtering
non_forwarding:1; // empty src/dst addr
non_forwarding:1, // empty src/dst addr
rtp_stats:1; // requires SSRC and clock_rates to be set
};
struct rtpengine_call_info {
@ -125,6 +136,12 @@ struct rtpengine_packet_info {
unsigned int stream_idx;
};
struct rtpengine_stats_info {
struct re_address local; // input
u_int32_t ssrc; // output
struct rtpengine_ssrc_stats ssrc_stats; // output
};
struct rtpengine_message {
enum {
REMG_NOOP = 1,
@ -145,6 +162,10 @@ struct rtpengine_message {
/* packet_info: */
REMG_PACKET,
/* stats_info: */
REMG_GET_STATS,
REMG_GET_RESET_STATS,
__REMG_LAST
} cmd;
@ -153,6 +174,7 @@ struct rtpengine_message {
struct rtpengine_call_info call;
struct rtpengine_stream_info stream;
struct rtpengine_packet_info packet;
struct rtpengine_stats_info stats;
} u;
unsigned char data[];


Loading…
Cancel
Save